Index: coins.lua ================================================================== --- coins.lua +++ coins.lua @@ -51,11 +51,10 @@ do return end ::foundmetal:: if not inv:is_empty('gem') then local id = slot_gem:get_name() for name,gem in pairs(sorcery.data.gems) do - print('scanning gem',name,dump(gem)) if gem.foreign then if id == gem.foreign then gemname = name else goto skip end else if id == 'sorcery:gem_' .. name then gemname = name @@ -65,11 +64,10 @@ do break end ::skip::end end coincount = coincount * coins_per_ingot - print('names',coinname,gemname) local coinname = 'sorcery:coin_' .. metalname .. ((gemname and '_' .. gemname) or '') inv:set_stack('output',1,ItemStack { Index: data/enchants.lua ================================================================== --- data/enchants.lua +++ data/enchants.lua @@ -60,17 +60,14 @@ }; desc = 'some damage is repaired when used to mine ore or kill an attacker'; on_dig = function(ctx) local orepfx = "stone_with_" -- }:< -- local oredrop = ' lump' - local dug = minetest.get_node(ctx.target.under) - local barename = string.sub(dug.name, string.find(dug.name, ':') + 1) - print('is ore? ',dug.name,barename) - if minetest.get_item_group(dug.name, ore) ~= 0 or + local barename = string.sub(ctx.node.name, string.find(ctx.node.name, ':') + 1) + if minetest.get_item_group(ctx.node.name, 'ore') ~= 0 or string.sub(barename,1,string.len(orepfx)) == orepfx then - print('is ore!') ctx.tool:add_wear(-(sorcery.enchant.strength(ctx.tool,'harvest') * 2000)) ctx.cost = 3 end end; }; Index: data/gems.lua ================================================================== --- data/gems.lua +++ data/gems.lua @@ -21,10 +21,12 @@ foreign = 'default:diamond'; tone = {137,240,255}; items = default_items('diamond'); tools = true, armor = true; maxenergy = 2000; + hardness = 8; + randomfind = false; slots = { {affinity = {'praxic','counterpraxic'}, confluence = 1}; {affinity = {'praxic','syncretic'}, confluence = 0.6}; {affinity = {'counterpraxic', 'entropic'}, confluence = 0.7}; }; @@ -35,10 +37,11 @@ tone = {255,253,94}; energysource = 5; maxenergy = 600; items = default_items('mese'); tools = true, armor = true; + randomfind = false; slots = { {affinity = {'praxic'}, confluence = 1}; {affinity = {'praxic'}, confluence = 0.5}; {affinity = {'cognic'}, confluence = 1}; {affinity = {'syncretic'}, confluence = 0.9}; Index: data/greases.lua ================================================================== --- data/greases.lua +++ data/greases.lua @@ -61,7 +61,16 @@ mix = { 'sorcery:powder_cobalt'; 'sorcery:powder_cobalt'; 'sorcery:extract_grape'; }; + }; + neutralizing = { + color = {221,148,95}; + core = { 'sorcery:oil_dawn', 'sorcery:oil_berry' }; + mix = { + 'sorcery:powder_aluminum'; + 'sorcery:powder_lithium'; + 'sorcery:extract_pine'; + }; }; } Index: data/metals.lua ================================================================== --- data/metals.lua +++ data/metals.lua @@ -29,10 +29,11 @@ ingot = 'default:copper_ingot'; block = 'default:copperblock'; tone = {255,176,61}; no_tools = true; no_armor = true; hardness = 2; + conduct = 0.1; }; brass = { tone = {255,226,87}; dye = 'bright_orange'; artificial = true; @@ -138,10 +139,11 @@ }; electrum = { tone = {212, 255, 0}, alpha = 80; artificial = true; hardness = 1; + conduct = 0.5; dye = 'bright_green'; mix = { metals = { silver = 1; gold = 1; @@ -174,10 +176,11 @@ hardness = 6; power = 3; speed = 3.5; cooktime = 30; maxenergy = 3500; + conduct = 2.0; slots = { { affinity = {'counterpraxic'}; confluence = 0.65; interference = {speed = 1}; @@ -199,10 +202,11 @@ rarity = 18; meltpoint = 3; cooktime = 340; hardness = 7; maxenergy = 1800; + conduct = 5; durability = 1900; speed = 3.2; img = { -- ingot = 'sorcery_iridium_ingot.png'; -- block = 'sorcery_iridium_block.png'; @@ -240,11 +244,11 @@ tone = {226,255,107}, alpha = 90; cooktime = 260; meltpoint = 5; artificial = true; speed = 2.1; - hardness = 20; + hardness = 15; durability = 5300; maxenergy = 2300; watercool = true; mix = { metals = { @@ -263,11 +267,11 @@ tone = {156,82,222}, alpha = 100; cooktime = 500; meltpoint = 6; artificial = true; speed = 2; - hardness = 9; + hardness = 10; maxenergy = 1200; durability = 8100; watercool = true; mix = { metals = { @@ -274,10 +278,17 @@ iridium = 2; tungsten = 2; lithium = 1; }; }; + sinter = { + 'sorcery:powder_iridium'; + 'sorcery:powder_iridium'; + 'sorcery:powder_tungsten'; + 'sorcery:powder_tungsten'; + 'sorcery:powder_lithium'; + }; slots = { {affinity={'praxic','entropic'}, confluence = 1.4}; {affinity={'praxic','syncretic'}, confluence = 1.1}; } }; @@ -287,10 +298,11 @@ cooktime = 330; artificial = true; maxenergy = 4000; hardness = 7; durability = 3300; + conduct = 15; speed = 3.4; slots = { {affinity={'praxic'}, confluence = 0.7}; {affinity={'counterpraxic'}, confluence = 1.2}; {affinity={'cognic'}, confluence = 1.1}; @@ -301,8 +313,38 @@ eternium = 4; cobalt = 1; }; }; }; - -- draconium = {artificial=true;}; - -- tyrannium = {artificial=true;}; + draconium = { + tone = {255,20,80}, alpha = 110; + artificial=true; + meltpoint = 5; + cooktime = 120; + hardness = 8; + maxconduct = 10; + speed = 1.7; + maxenergy = 2200; + durability = 1500; + slots = { + {affinity={'praxic'},confluence=3}; + {affinity={'syncretic'},confluence=2}; + }; + sinter = { + 'sorcery:powder_lithium'; + 'sorcery:powder_aluminum'; + 'sorcery:powder_iridium'; + 'sorcery:oil_flame'; + }; + }; + tyrannium = { + tone = {46,255,245}, alpha = 80; + artificial=true; + hardness = 20; + meltpoint = 6; + cooktime = 240; + maxenergy = 800; + durability = 4000; + speed = 3.0; + slots = {}; + }; }; Index: data/spells.lua ================================================================== --- data/spells.lua +++ data/spells.lua @@ -386,11 +386,10 @@ power = power * (math.random()*2) range = range * (math.random()*2) duration = duration * (math.random()*2) end local lum = math.ceil((power/maxpower) * minetest.LIGHT_MAX) - print('setting lum',lum) for i=1,power do local pos = vector.add(center, { x = math.random(-range,range); z = math.random(-range,range); y = math.random(0,range/2); Index: enchanter.lua ================================================================== --- enchanter.lua +++ enchanter.lua @@ -233,10 +233,11 @@ paramtype2 = 'facedir'; groups = { cracky = 2, oddly_breakable_by_hand = 2 }; sunlight_propagates = true; selection_box = hitbox; collision_box = hitbox; + after_dig_node = sorcery.lib.node.purge_container; tiles = { "default_obsidian.png"; "default_steel_block.png"; "default_bronze_block.png"; "default_junglewood.png"; @@ -414,10 +415,20 @@ sorcery.enchant.set(tool,ench) else sorcery.enchant.set(tool,ench,true) end puncher:set_wielded_item(tool) + + -- perform leyline checks and call notify if necessary + if minetest.get_item_group(node.name, 'sorcery_ley_device') ~= 0 then + for _,p in pairs(sorcery.ley.txofs) do + local sum = vector.add(pos,p) + if minetest.get_item_group(minetest.get_node(sum).name, 'sorcery_ley_device') ~= 0 then + sorcery.ley.notify(sum) + end + end + end end) minetest.register_chatcommand('enchants', { description = 'Log information about the currently held object\'s enchantment'; privs = { server = true }; ADDED forcefield.lua Index: forcefield.lua ================================================================== --- forcefield.lua +++ forcefield.lua @@ -0,0 +1,182 @@ +local constants = { + cost_per_barrier = 0.1; + -- 0.1 points of current will be required per second per + -- unit of charge given to a barrier-block when ley-force + -- of counterpraxic affinity is not available +} +local aimtbl = { + [0] = {x = 0, y = 1, z = 0}; + [1] = {x = 0, y = 0, z = 1}; + [2] = {x = 0, y = 0, z = -1}; + [3] = {x = 1, y = 0, z = 0}; + [4] = {x = -1, y = 0, z = 0}; + [5] = {x = 0, y = -1, z = 0}; +} +local pofstbl = { + [0] = {x=0.5, y=0, z=0.5}; + [1] = {x=0.5, y=0.5, z=0}; + [2] = {x=0.5, y=0.5, z=0}; + [3] = {x=0, y=0.5, z=0.5}; + [4] = {x=0, y=0.5, z=0.5}; + [5] = {x=0.5, y=0, z=0.5}; +} +local calc_cost = function(pos,time) + local node = minetest.get_node(pos) + local aim = aimtbl[math.floor(node.param2 / 4)] + local tgts = {} + for i=1,5 do + local tpos = vector.add(pos, vector.multiply(aim,i)) + local n = minetest.get_node(tpos) + if n.name == 'air' then tgts[#tgts + 1] = {tpos,0} else + local f = minetest.get_item_group(n.name, 'sorcery_force_barrier') + if f > 0 then + tgts[#tgts + 1] = {tpos,f} + else break end + end + end + return { + aim = aim; + maxcost = #tgts * constants.cost_per_barrier * time; + mincost = math.min(1,#tgts) * constants.cost_per_barrier * time; + targets = tgts; + } +end +for i=1,10 do + minetest.register_node('sorcery:air_barrier_' .. tostring(i), { + drawtype = 'airlike'; + walkable = true; + pointable = false; + sunlight_propagates = true; + paramtype = 'light'; + light_source = i; + groups = { + sorcery_force_barrier = i; + }; + -- _proto = { + -- strength = i; + -- }; + on_construct = function(pos) + minetest.get_node_timer(pos):start(1) + end; + on_timer = function(pos,delta) + local dec = 40*delta + local node = minetest.get_node(pos) + local newstr = math.ceil(10 * ((node.param2 - dec) / 0xFF)) + local newnode = 'sorcery:air_barrier_' .. tostring(newstr) + if newstr <= 0 then + minetest.remove_node(pos) + return false + else + for _,c in pairs {{165,255,252}, {146,205,255}, {190,93,253}} do + minetest.add_particlespawner { + time = 1; + amount = 15; + minpos = vector.add(pos, -0.6); + maxpos = vector.add(pos, 0.6); + minvel = {x = 0, y = 0, z = 0}; + maxvel = {x = 0, y = 0, z = 0}; + minacc = {x = -0.1, y = -0.1, z = -0.1}; + maxacc = {x = 0.1, y = 0.1, z = 0.1}; + minexptime = 0.5; + maxexptime = 1.0; + minsize = 0.2; + minsize = 0.7; + texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(c)):render(); + glow = 14; + animation = { + length = 1.1; + type = 'vertical_frames'; + aspect_h = 16, aspect_w = 16; + }; + } + end + minetest.swap_node(pos, { + name = newnode; + param1 = node.param1; + param2 = newstr; + }) + return true + end + end; + }) +end +minetest.register_node('sorcery:emitter_barrier', { + description = "Barrier Screen Emitter"; + paramtype2 = 'facedir'; + groups = { + cracky = 2; + sorcery_ley_device = 1; + }; + tiles = { + 'sorcery_emitter_barrier_top.png'; + 'sorcery_emitter_barrier_bottom.png'; + 'sorcery_emitter_barrier_front.png^[transformR270'; + 'sorcery_emitter_barrier_front.png^[transformFXR90'; + 'sorcery_emitter_barrier_side.png'; + 'sorcery_emitter_barrier_side.png'; + }; + on_construct = function(pos) + minetest.get_node_timer(pos):start(1) + end; + on_timer = function(pos,delta) + local orientation = math.floor(minetest.get_node(pos).param2 / 4) + local costs = calc_cost(pos,delta) + local l = sorcery.ley.netcaps(pos,delta) + if l.self.powerdraw >= costs.mincost then + local dist = l.self.powerdraw / (constants.cost_per_barrier * delta) + for i=1,math.floor(dist) do + local t = costs.targets[i] + local str = math.min(0xFF,t[2] + 50*delta); + minetest.swap_node(t[1], { + name = 'sorcery:air_barrier_' .. math.max(1, math.floor(10*(str/0xFF))); + param2 = str; + }) + minetest.get_node_timer(t[1]):start(1) + end + + local pn = vector.add(pos, vector.divide(costs.aim,2)); + local pp = vector.add(pn, pofstbl[orientation]) + pn = vector.subtract(pn, pofstbl[orientation]) + + minetest.add_particlespawner { + time = 1; + amount = 20 * dist; + minpos = pn; + maxpos = pp; + minvel = costs.aim; + maxvel = vector.multiply(costs.aim,2); + minsize = 0.3; + maxsize = 0.5; + minexptime = dist*0.5; + maxexptime = dist*0.5; + texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(240,255,160)):render(); + glow = 14; + animation = { + length = dist + 0.1; + type = 'vertical_frames'; + aspect_h = 16, aspect_w = 16; + }; + } + return true + end + return false + end; + 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; + _sorcery = { + ley = { + mode='consume', affinity={'counterpraxic'}, + power = function(pos,time) + local l = calc_cost(pos,time) + return l.mincost, l.maxcost + end; + }; + on_leychange = function(pos) + minetest.get_node_timer(pos):start(1) + end; + }; +}) Index: harvester.lua ================================================================== --- harvester.lua +++ harvester.lua @@ -17,10 +17,11 @@ description = 'Harvester'; drawtype = 'mesh'; paramtype = 'light'; paramtype2 = 'facedir'; mesh = 'sorcery-harvester.obj'; + after_dig_node = sorcery.lib.node.purge_container; groups = { cracky = 2; oddly_breakable_by_hand = 1; }; sunlight_propagates = true; selection_box = hitbox; collision_box = hitbox; tiles = { Index: infuser.lua ================================================================== --- infuser.lua +++ infuser.lua @@ -196,10 +196,11 @@ minetest.register_node("sorcery:infuser", { description = "Infuser"; drawtype = "mesh"; mesh = "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", Index: init.lua ================================================================== --- init.lua +++ init.lua @@ -27,11 +27,11 @@ -- careful about the order they're loaded in sorcery.unit('data') {'ui'} sorcery.unit('lib') { -- convenience - 'str'; + 'str', 'node'; -- serialization 'marshal', 'json'; -- data structures 'tbl', 'class'; -- wrappers @@ -49,12 +49,12 @@ 'philters', 'extracts'; 'register'; } for _,u in pairs { - 'leylines'; 'ores'; 'gems'; + 'ores'; 'gems'; 'leylines'; 'potions'; 'infuser'; 'altar'; 'wands'; 'tools'; 'enchanter'; 'harvester'; 'metallurgy-hot', 'metallurgy-cold'; 'entities'; 'recipes'; 'coins'; - 'interop'; 'tnodes'; + 'interop'; 'tnodes'; 'forcefield'; } do sorcery.load(u) end Index: leylines.lua ================================================================== --- leylines.lua +++ leylines.lua @@ -73,18 +73,206 @@ {'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'}; }; }; -minetest.register_craft { - output = 'sorcery:wire 4'; - recipe = { - {'', 'basic_materials:copper_wire',''}; - {'', 'sorcery:fragment_electrum', ''}; - {'', 'basic_materials:copper_wire',''}; + +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_conduit = 1; + }; + _sorcery = { + ley = { mode = 'signal'; power = 5; } + }; + 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 }; + }; + 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.25, -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) + sorcery.ley.notifymap(n.map) +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 @@ -104,10 +292,11 @@ }; }; minetest.register_node('sorcery:condenser', { description = 'Condenser'; drawtype = 'mesh'; + paramtype2 = 'facedir'; mesh = 'sorcery-condenser.obj'; selection_box = box; collision_box = box; tiles = { amethyst:render(); @@ -124,18 +313,18 @@ on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_string('infotext','Condenser') end; _sorcery = { - ley = { mode = 'produce' }; - on_leycalc = function(pos,time) - local l = sorcery.ley.estimate(pos) - return { - power = sorcery.ley.field_to_current(l.force, time); - affinity = l.aff; - } - end; + 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; + }; }; }) end minetest.register_craft { @@ -143,14 +332,23 @@ 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 = {} + local net,checked = {},{} power = power or 0 local devices = { consume = {}; produce = {}; @@ -157,12 +355,13 @@ signal = {}; } local numfound = 0 local maxconduct = 0 local minconduct + local startkey local foundp = function(p) - for k in pairs(net) do + 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 @@ -169,31 +368,30 @@ -- 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 { - {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}; - } do local sum = vector.add(pos,p) + 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 = minetest.get_node(sum).name + if nodename == 'ignore' then + minetest.load_area(sum) + nodename = minetest.get_node(sum).name + end 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) + 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 @@ -203,10 +401,15 @@ 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 @@ -218,10 +421,11 @@ if numfound > 0 then return { count = numfound; map = net; devices = devices; + startpos = startkey; conduct = { min = minconduct; max = maxconduct; }; } @@ -243,21 +447,23 @@ 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; - power = m.t.u32; -- power generated/consumed * 10,000 + 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]; - power = l.power * 10000; + minpower = l.minpower * 10000; + maxpower = l.maxpower * 10000; affinity = idxs; }, true) end sorcery.ley.decode = function(str) local obj = dec(meta_dearmor(str,true)) @@ -265,94 +471,321 @@ for _,k in pairs(obj.affinity) do affs[#affs+1] = afftbl[k] end return { mode = modetbl[obj.mode]; - power = obj.power / 10000.0; + 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_node(pos) meta:set_string('sorcery:ley',sorcery.ley.encode(l)) end -sorcery.ley.sample = function(pos,timespan,name) +sorcery.ley.sample = function(pos,timespan,name,flags) -- returns how much ley-force can be transmitted by a -- device over timespan + local ret = {} 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 callback = props and props.on_leycalc or nil - local p,a,m - if callback then - local gen = callback(pos,timespan) - p = gen.power - a = gen.affinity - m = gen.mode + + local evaluate = function(v) + if type(v) == 'function' then + return v(pos) + else return v end end - if not (p and a and m) then + local leymeta do local nm = minetest.get_meta(pos) if nm:contains('sorcery:ley') then - local l = sorcery.ley.decode(nm:get_string('sorcery:ley')) - p = p or sorcery.ley.field_to_current(l.power,timespan) - a = a or l.affinity - m = m or l.mode + 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) + condset('minpower',p) + condset('maxpower',p) + 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 (not (p and a and m)) and props and props.ley then - p = p or sorcery.ley.field_to_current(props.ley.power,timespan) - a = a or props.ley.affinity - m = m or props.ley.mode + 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 - - if (not (p and a and m)) then - local compat = sorcery.data.compat.ley[name] - if compat then - p = p or sorcery.ley.field_to_current(compat.power,timespan) - a = a or compat.affinity - m = m or compat.mode - end - end - - return { - power = p or 0; - mode = m or 'none'; - affinity = a or {}; - } + return ret end sorcery.ley.netcaps = function(pos,timespan,exclude) local net = sorcery.ley.mapnet(pos) 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) - freepower = freepower - ln.power + 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; }; + 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 = minetest.get_node(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; + }; + }; + }) +end ADDED lib/node.lua Index: lib/node.lua ================================================================== --- lib/node.lua +++ lib/node.lua @@ -0,0 +1,21 @@ +return { + purge_container = function(pos,node,meta,user) + local offset = function(pos,range) + local r = function(min,max) + return (math.random() * (max - min)) + min + end + return { + x = pos.x + r(0 - range, range); + y = pos.y; + z = pos.z + r(0 - range, range); + } + end + for name, inv in pairs(meta.inventory) do + for _, item in pairs(inv) do + if not item:is_empty() then + minetest.add_item(offset(pos,0.4), item) + end + end + end + end; +} Index: metallurgy-cold.lua ================================================================== --- metallurgy-cold.lua +++ metallurgy-cold.lua @@ -36,10 +36,14 @@ -- how many powders an ingot is worth default_grindvalue = 1; -- number of items produced when not otherwise -- specified + + default_grindcost = 1; + -- number of items needed to perform a grind when + -- not otherwise specified default_hardness = 1; -- difficulty to grind an item when not otherwise -- specified @@ -46,12 +50,11 @@ metal_grindcost = 1; -- number of metal items needed to perform a grind } local mill_formspec_update = function(pos,pct,stat1,stat2) -- eventually we'll want to display available - -- energy here, but for now we're just assuming - -- max energy available + -- energy here -- local meta = minetest.get_meta(pos) -- local inv = meta:get_inventory() -- local torque = 20 stat1 = stat1 or 'off' @@ -81,14 +84,14 @@ then return 1 end elseif slot == 'input' then local metal = sorcery.data.metallookup[item:get_name()] local mat = sorcery.matreg.lookup[item:get_name()] local comp = sorcery.data.compat.grindables[item:get_name()] - if metal or mat.metal or comp then + if metal or (mat and mat.metal) or comp then return item:get_count() else - local mat = item:get_definition()._matprop + mat = item:get_definition()._matprop if mat and mat.grindvalue then return item:get_count() end end end @@ -98,29 +101,30 @@ local metal = sorcery.data.metallookup[item:get_name()] if not metal then -- allow grinding of armor and tools back to their -- original components local mat = sorcery.matreg.lookup[item:get_name()] - if mat.metal then + if mat and mat.metal then metal = mat - else - return nil end end local mp = item:get_definition()._matprop or sorcery.data.compat.grindables[item:get_name()] or {} again = true if metal then mp = { - hardness = metal.data.hardness or mp.hardness or constants.default_hardness; - grindvalue = metal.value or mp.grindvalue or (metal and constants.metal_grindvalue) or constants.default_grindvalue; - powder = metal.data.parts.powder or mp.powder; - grindcost = constants.metal_grindcost or mp.grindcost; -- invariant for metal + hardness = mp.hardness or metal.data.hardness; + grindvalue = ((mp.grindvalue or metal.value) or (metal and constants.metal_grindvalue)); + powder = mp.powder or metal.data.parts.powder; + grindcost = mp.grindcost or constants.metal_grindcost; -- invariant for metal } end - mp.torque = constants.grind_torque_factor * mp.hardness + mp.torque = constants.grind_torque_factor * mp.hardness + mp.grindvalue = mp.grindvalue or constants.default_grindvalue + mp.grindcost = mp.grindcost or constants.default_grindcost + mp.hardness = mp.hardness or constants.default_hardness; if item:get_wear() ~= 0 then -- prevent cheating by recovering metal from items before they -- are destroyed local wearfac = (item:get_wear() / 65535) @@ -136,10 +140,11 @@ groups = { cracky = 2; sorcery_ley_device = 1; }; paramtype2 = 'facedir'; + 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('input',1) inv:set_size('output',4) @@ -165,26 +170,26 @@ minetest.get_meta(pos):set_float('grindtime',0) end mill_update(pos) end; _sorcery = { - ley = { mode = 'consume'; affinity = {'praxic'}}; - on_leyconnect = mill_update; - on_leycalc = function(pos,time) - local meta = minetest.get_meta(pos) - local active = meta:get_int('active') == 1 - if not active then return { power = 0; } end - local inv = meta:get_inventory() - local item = inv:get_stack('input',1) - if item:is_empty() then - meta:set_int('active', 0) - return { power = 0; } - end - return { - power = matprops(item).torque * time; - } - end; + ley = { + mode = 'consume', affinity = {'praxic'}; + power = function(pos,time) + local meta = minetest.get_meta(pos) + local active = meta:get_int('active') == 1 + if not active then return 0 end + local inv = meta:get_inventory() + local item = inv:get_stack('input',1) + if item:is_empty() then + meta:set_int('active', 0) + return 0 + end + return matprops(item).torque * time; + end; + }; + on_leychange = mill_update; }; on_timer = function(pos,delta) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local elapsed = meta:get_float('grindtime') + delta @@ -193,38 +198,31 @@ local active = false local reqtime -- sigh local statcolor = 'off' local grinders_on if inv:is_empty('input') or inv:is_empty('grinder') then - print('empty') elapsed = 0 mill_formspec_update(pos, 0) else local item = inv:get_stack('input',1) local mp = matprops(item) if mp.grindcost > item:get_count() then elapsed = 0 mill_formspec_update(pos, 0) - print('bad grindcost') goto stop end - -- print('power supply',ley.maxpower) - -- print('power available',ley.freepower) - -- print('power needed',mp.torque*delta) if ley.maxpower < (mp.torque * delta) then -- not enough potential energy in the system to grind -- so don't bother - print('not enough power') statcolor = 'red' elapsed = 0 goto stop elseif ley.freepower < (mp.torque * delta) then -- the net has enough potential energy to supply us, -- but too much of it is in use right now. give up -- on this round, but try again in a bit to see if -- more energy is available - print('currently not enough power') statcolor = 'yellow' elapsed = 0 again = true goto stop end local grinders = 0 @@ -244,11 +242,10 @@ elseif dif < 0 then wear = constants.grind_wear * ((dif * -1)/constants.grind_range) elseif dif > 0 then if dif > constants.grind_grace_range then wear = 0 - print('grinder reject') goto reject else wear = constants.grind_wear * (1 + (dif/constants.grind_range)) * constants.grind_grace_penalty end end @@ -271,11 +268,11 @@ else statcolor='green' end grindpower = grindpower / grinders -- if there is more power available than needed, -- and/or if the blades are stronger than needed, -- speed up the grind - local speedboost = math.max(0.05,((grindpower - mp.hardness)/constants.grind_range) * grinders) * ((mp.torque * delta) / ley.freepower) + local speedboost = math.max(0.05,((grindpower - mp.hardness)/constants.grind_range) * grinders) reqtime = mp.grindvalue * mp.hardness * constants.grind_factor * (1-speedboost) if elapsed >= reqtime then item:take_item(mp.grindcost) inv:set_stack('input',1,item) local pw = ItemStack{ @@ -347,10 +344,10 @@ }); minetest.register_craft { output = id; recipe = { {f,i,f}; - {i,i,i}; + {i,'',i}; {f,i,f}; }; } end Index: metallurgy-hot.lua ================================================================== --- metallurgy-hot.lua +++ metallurgy-hot.lua @@ -296,10 +296,11 @@ local id_current = (state == 'closed' and id_closed) or id local desc = (kind.temp_name and sorcery.lib.str.capitalize(kind.temp_name) .. ' kiln') or 'Kiln' minetest.register_node(id_current, { description = desc; drawtype = "mesh"; + after_dig_node = sorcery.lib.node.purge_container; mesh = 'sorcery-kiln-' .. state .. '.obj'; drop = id; groups = { cracky = (state == 'open' and 2) or nil; }; @@ -378,10 +379,11 @@ for _, active in pairs {false, true} do minetest.register_node((active and id .. '_active') or id, { _proto = kind; description = desc; drop = id; + after_dig_node = sorcery.lib.node.purge_container; groups = { cracky = (active and 2) or nil; }; paramtype2 = 'facedir'; light_source = (active and 9) or 0; Index: ores.lua ================================================================== --- ores.lua +++ ores.lua @@ -127,11 +127,12 @@ durability = metal.durability; power = metal.power; speed = metal.speed; artificial = metal.artificial; cooktime = metal.cooktime; - hardness = metal.hardness; + hardness = (metal.hardness/8) * 3; -- scaled wrt diamond + level = math.ceil(((metal.hardness/8) * 3)) + 1; ingot_image = (metal.image and metal.image.ingot) or nil; lump_image = (metal.image and metal.image.lump) or nil; armor_weight = metal.armor_weight; armor_protection = metal.armor_protection; } Index: recipes.lua ================================================================== --- recipes.lua +++ recipes.lua @@ -252,10 +252,132 @@ } ---- altar -- candles +minetest.register_craftitem('sorcery:core_counterpraxic',{ + description = 'Counterpraxis Core'; + inventory_image = 'sorcery_core_counterpraxic.png'; +}); +-- +minetest.register_craftitem('sorcery:suppression_matrix',{ + description = 'Suppression Matrix'; + inventory_image = 'sorcery_suppression_matrix.png'; +}); + +minetest.register_craftitem('sorcery:inverter_coil',{ + description = 'Inverter Coil'; + inventory_image = 'sorcery_inverter_coil.png'; +}); + +minetest.register_craftitem('sorcery:beam_generator',{ + description = 'Beam Generator'; + inventory_image = 'sorcery_beam_generator.png'; +}); + +minetest.register_craftitem('sorcery:leyline_stabilizer',{ + description = 'Leyline Stabilizer'; + inventory_image = 'sorcery_leyline_stabilizer.png'; +}); + +minetest.register_craftitem('sorcery:field_emitter',{ + description = 'Field Emitter'; + inventory_image = 'sorcery_field_emitter.png'; +}) + +minetest.register_craft { + output = 'sorcery:leyline_stabilizer'; + recipe = { + {'basic_materials:copper_wire','group:sorcery_ley_cable','basic_materials:copper_wire'}; + {'sorcery:grease_neutralizing','group:sorcery_ley_cable','sorcery:grease_neutralizing'}; + {'basic_materials:copper_wire','group:sorcery_ley_cable','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'}; + {'sorcery:grease_neutralizing', 'xdecor:bowl'}; + {'sorcery:grease_neutralizing', 'xdecor:bowl'}; + }; +} + +minetest.register_craft { + output = 'sorcery:beam_generator'; + recipe = { + {'xpanes:bar_flat','xpanes:pane_flat','xpanes:bar_flat'}; + {'sorcery:screw_aluminum','sorcery:gem_sapphire','sorcery:screw_aluminum'}; + {'xpanes:bar_flat','sorcery:gem_luxite','xpanes:bar_flat'}; + }; +} + +minetest.register_craft { + output = 'sorcery:suppression_matrix'; + recipe = { + {'sorcery:fragment_electrum','basic_materials:steel_strip','sorcery:fragment_cobalt'}; + {'basic_materials:copper_strip','xpanes:bar_flat','basic_materials:copper_strip'}; + {'sorcery:fragment_cobalt','basic_materials:steel_strip','sorcery:fragment_electrum'}; + }; +} + +minetest.register_craft { + output = 'sorcery:core_counterpraxic'; + recipe = { + {'sorcery:gem_ruby_shard','sorcery:tungsten_ingot','sorcery:gem_ruby_shard'}; + {'sorcery:tungsten_ingot','sorcery:gem_emerald','sorcery:tungsten_ingot'}; + {'sorcery:gem_ruby_shard','sorcery:tungsten_ingot','sorcery:gem_ruby_shard'}; + }; +} + +minetest.register_craft { + output = 'sorcery:inverter_coil'; + recipe = { + {'sorcery:screw_platinum','basic_materials:steel_wire','sorcery:screw_platinum'}; + {'basic_materials:copper_wire','default:tin_ingot','basic_materials:copper_wire'}; + {'sorcery:screw_platinum','basic_materials:steel_wire','sorcery:screw_platinum'}; + }; + replacements = { + {'basic_materials:steel_wire', 'basic_materials:empty_spool'}; + {'basic_materials:copper_wire', 'basic_materials:empty_spool'}; + {'basic_materials:copper_wire', 'basic_materials:empty_spool'}; + {'basic_materials:steel_wire', 'basic_materials:empty_spool'}; + }; +} + +minetest.register_craft { + output = 'sorcery:field_emitter'; + recipe = { + {'basic_materials:steel_bar','xpanes:pane_flat','basic_materials:steel_bar'}; + {'sorcery:beam_generator','sorcery:leyline_stabilizer','sorcery:beam_generator'}; + {'sorcery:beam_generator','basic_materials:copper_wire','sorcery:beam_generator'}; + }; + replacements = { + {'basic_materials:copper_wire', 'basic_materials:empty_spool'}; + }; +} + +minetest.register_craft { + output = 'sorcery:emitter_barrier'; + recipe = { + {'sorcery:suppression_matrix','sorcery:suppression_matrix','sorcery:suppression_matrix'}; + {'sorcery:field_emitter','sorcery:core_counterpraxic','sorcery:inverter_coil'}; + {'default:tin_ingot','default:tin_ingot','default:tin_ingot'}; + }; +} + +minetest.register_craft { + output = 'sorcery:generator'; + recipe = { + {'sorcery:aluminum_ingot','sorcery:aluminum_ingot','sorcery:aluminum_ingot'}; + {'default:bronze_ingot','basic_materials:copper_wire','default:bronze_ingot'}; + {'default:steel_ingot','default:furnace','default:steel_ingot'}; + }; + replacements = { + {'basic_materials:copper_wire', 'basic_materials:empty_spool'}; + }; +} + minetest.register_craftitem('sorcery:candle', { -- TODO make candle node inventory_image = 'sorcery_candle.png'; description = 'Votive Candle'; groups = { ADDED textures/sorcery_beam_generator.png Index: textures/sorcery_beam_generator.png ================================================================== --- textures/sorcery_beam_generator.png +++ textures/sorcery_beam_generator.png cannot compute difference between binary files ADDED textures/sorcery_core_counterpraxic.png Index: textures/sorcery_core_counterpraxic.png ================================================================== --- textures/sorcery_core_counterpraxic.png +++ textures/sorcery_core_counterpraxic.png cannot compute difference between binary files ADDED textures/sorcery_emitter_barrier_bottom.png Index: textures/sorcery_emitter_barrier_bottom.png ================================================================== --- textures/sorcery_emitter_barrier_bottom.png +++ textures/sorcery_emitter_barrier_bottom.png cannot compute difference between binary files ADDED textures/sorcery_emitter_barrier_front.png Index: textures/sorcery_emitter_barrier_front.png ================================================================== --- textures/sorcery_emitter_barrier_front.png +++ textures/sorcery_emitter_barrier_front.png cannot compute difference between binary files ADDED textures/sorcery_emitter_barrier_side.png Index: textures/sorcery_emitter_barrier_side.png ================================================================== --- textures/sorcery_emitter_barrier_side.png +++ textures/sorcery_emitter_barrier_side.png cannot compute difference between binary files ADDED textures/sorcery_emitter_barrier_top.png Index: textures/sorcery_emitter_barrier_top.png ================================================================== --- textures/sorcery_emitter_barrier_top.png +++ textures/sorcery_emitter_barrier_top.png cannot compute difference between binary files ADDED textures/sorcery_field_emitter.png Index: textures/sorcery_field_emitter.png ================================================================== --- textures/sorcery_field_emitter.png +++ textures/sorcery_field_emitter.png cannot compute difference between binary files ADDED textures/sorcery_inverter_coil.png Index: textures/sorcery_inverter_coil.png ================================================================== --- textures/sorcery_inverter_coil.png +++ textures/sorcery_inverter_coil.png cannot compute difference between binary files ADDED textures/sorcery_ley_generator_back.png Index: textures/sorcery_ley_generator_back.png ================================================================== --- textures/sorcery_ley_generator_back.png +++ textures/sorcery_ley_generator_back.png cannot compute difference between binary files ADDED textures/sorcery_ley_generator_bottom.png Index: textures/sorcery_ley_generator_bottom.png ================================================================== --- textures/sorcery_ley_generator_bottom.png +++ textures/sorcery_ley_generator_bottom.png cannot compute difference between binary files ADDED textures/sorcery_ley_generator_front_off.png Index: textures/sorcery_ley_generator_front_off.png ================================================================== --- textures/sorcery_ley_generator_front_off.png +++ textures/sorcery_ley_generator_front_off.png cannot compute difference between binary files ADDED textures/sorcery_ley_generator_front_on.png Index: textures/sorcery_ley_generator_front_on.png ================================================================== --- textures/sorcery_ley_generator_front_on.png +++ textures/sorcery_ley_generator_front_on.png cannot compute difference between binary files ADDED textures/sorcery_ley_generator_side.png Index: textures/sorcery_ley_generator_side.png ================================================================== --- textures/sorcery_ley_generator_side.png +++ textures/sorcery_ley_generator_side.png cannot compute difference between binary files ADDED textures/sorcery_ley_generator_top.png Index: textures/sorcery_ley_generator_top.png ================================================================== --- textures/sorcery_ley_generator_top.png +++ textures/sorcery_ley_generator_top.png cannot compute difference between binary files ADDED textures/sorcery_ley_plug.png Index: textures/sorcery_ley_plug.png ================================================================== --- textures/sorcery_ley_plug.png +++ textures/sorcery_ley_plug.png cannot compute difference between binary files ADDED textures/sorcery_ley_switch_base.png Index: textures/sorcery_ley_switch_base.png ================================================================== --- textures/sorcery_ley_switch_base.png +++ textures/sorcery_ley_switch_base.png cannot compute difference between binary files ADDED textures/sorcery_ley_switch_down.png Index: textures/sorcery_ley_switch_down.png ================================================================== --- textures/sorcery_ley_switch_down.png +++ textures/sorcery_ley_switch_down.png cannot compute difference between binary files ADDED textures/sorcery_ley_switch_panel.png Index: textures/sorcery_ley_switch_panel.png ================================================================== --- textures/sorcery_ley_switch_panel.png +++ textures/sorcery_ley_switch_panel.png cannot compute difference between binary files ADDED textures/sorcery_ley_switch_up.png Index: textures/sorcery_ley_switch_up.png ================================================================== --- textures/sorcery_ley_switch_up.png +++ textures/sorcery_ley_switch_up.png cannot compute difference between binary files ADDED textures/sorcery_leyline_stabilizer.png Index: textures/sorcery_leyline_stabilizer.png ================================================================== --- textures/sorcery_leyline_stabilizer.png +++ textures/sorcery_leyline_stabilizer.png cannot compute difference between binary files ADDED textures/sorcery_suppression_matrix.png Index: textures/sorcery_suppression_matrix.png ================================================================== --- textures/sorcery_suppression_matrix.png +++ textures/sorcery_suppression_matrix.png cannot compute difference between binary files Index: tnodes.lua ================================================================== --- tnodes.lua +++ tnodes.lua @@ -17,13 +17,10 @@ on_timer = function(pos,dtime) local meta = minetest.get_meta(pos) local elapsed = dtime + meta:get_float('duration') - meta:get_float('timeleft') local level = 1 - (elapsed / meta:get_float('duration')) local lum = math.ceil(level*meta:get_int('power')) - print('elapsed time',elapsed) - print('light level',level) - print('lum',lum) if lum ~= i then if lum <= 0 then minetest.remove_node(pos) return false else Index: wands.lua ================================================================== --- wands.lua +++ wands.lua @@ -689,10 +689,11 @@ 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