sorcery  Diff

Differences From Artifact [c4c14b0c08]:

  • File infuser.lua — part of check-in [147592b8e9] at 2020-10-26 03:58:08 on branch trunk — add over-time spellcasting abstraction to enable metamagic and in particular disjunction, add more animations and sound effects, add excavation spell, possibly some others, forget when the last commit was, edit a bunch of magitech to make it subject to the disjunction mechanism (throw up a disjunction aura and waltz right through those force fields bby, wheee), also illumination spells, tweak runeforge and rune frequence to better the balance and also limit player frustration, move some math functions into their own library category, various tweaks and bugfixes, probably other shit i don't remember (user: lexi, size: 7825) [annotate] [blame] [check-ins using]

To Artifact [6c01c64259]:


     1         -local infuser_formspec = function(percent)
            1  +local log = sorcery.logger('infuser')
            2  +
            3  +local infuser_formspec = function(percent,active)
     2      4   	return string.format([[
     3      5   		size[8,7]
     4      6   		list[context;infusion;3.5,0;1,1;]
     5      7   		list[context;potions;2.5,1.7;1,1;0]
     6      8   			list[context;potions;3.5,2;1,1;1]
     7      9   			list[context;potions;4.5,1.7;1,1;2]
     8     10   			image[2.5,1.7;1,1;vessels_shelf_slot.png]
     9     11   			image[3.5,2;1,1;vessels_shelf_slot.png]
    10     12   			image[4.5,1.7;1,1;vessels_shelf_slot.png]
    11     13   		image[3.5,1;1,1;gui_furnace_arrow_bg.png^[lowpart:%d:gui_furnace_arrow_fg.png^[transformR180]
    12     14   		list[current_player;main;0,3.3;8,4;]
           15  +		animated_image[2.5,0;1,2;tube_l;sorcery_ui_infuse_tube.png;28;%s;28]
           16  +		animated_image[4.5,0;1,2;tube_l;sorcery_ui_infuse_tube.png^[transformFX;28;%s;28]
    13     17   		listring[context;infusion]
    14     18   		listring[current_player;main]
    15     19   		listring[context;potions]
    16     20   		listring[current_player;main]
    17     21   		listring[context;infusion]
    18         -	]], percent)
           22  +	]], percent,
           23  +		active and '71' or '0',
           24  +		active and '71' or '0')
    19     25   end
    20     26   
    21     27   local infuser_stop = function(pos)
    22     28   	local meta = minetest.get_meta(pos)
    23     29   	meta:set_float('runtime', 0)
    24     30   	meta:set_string('formspec', infuser_formspec(0))
    25     31   	meta:set_string('infotext', 'Infuser')
    26     32   	minetest.get_node_timer(pos):stop()
    27     33   end
           34  +sorcery.alchemy = {}
           35  +
           36  +sorcery.alchemy.is_module = function(name)
           37  +	local def = minetest.registered_nodes[name]
           38  +	if def and def._sorcery and def._sorcery.alchemy and def._sorcery.alchemy.module then
           39  +		return def._sorcery.alchemy.module
           40  +	else return nil end
           41  +end
           42  +
           43  +local infuser_mods = function(pos)
           44  +	local getmod = function(pos)
           45  +		local st = sorcery.lib.node.force(pos)
           46  +		return sorcery.alchemy.is_module(st.name)
           47  +	end
           48  +
           49  +	local st = sorcery.lib.node.force(pos)
           50  +	if st.name ~= 'sorcery:infuser' then return false end
           51  +	local devs = {}
           52  +
           53  +	repeat
           54  +		pos = vector.offset(pos, 0, -1, 0)
           55  +		local mod = getmod(pos)
           56  +		if mod then
           57  +			if mod.attach == 'stack' then
           58  +				devs[#devs+1] = { pos = pos, mod = mod }
           59  +				if mod.stmod_connect then
           60  +					for _,ofs in pairs(mod.stmod_connect) do
           61  +						local wh = vector.add(pos,ofs)
           62  +						local stm = getmod(wh)
           63  +						if stm and stm.attach == 'stand' then
           64  +							-- TODO check facing correct direction
           65  +							devs[#devs+1] = {pos = wh, mod = stm}
           66  +						end
           67  +					end
           68  +				end
           69  +				if mod.endstack then break end
           70  +			else break end -- invalid attachment
           71  +		else break end
           72  +	until false
           73  +
           74  +	local props = {}
           75  +
           76  +	local comp = function(a,b) return function(...) return a(b(...)) end end
           77  +	local mult = function(a,b) return a * b end;
           78  +	local sum  = function(a,b) return a + b end;
           79  +	local combine = {
           80  +		brewtime = mult;
           81  +		onbrew = function(a, b)
           82  +			return function(ctx)
           83  +				ctx.stack = b(ctx)
           84  +				return a(ctx)
           85  +			end
           86  +		end;
           87  +	}
           88  +
           89  +	for _, d in pairs(devs) do
           90  +		for k,v in pairs(d.mod) do
           91  +			if combine[k] then
           92  +				if props[k]
           93  +					then props[k] = (combine[k])(v, props[k])
           94  +					else props[k] = v
           95  +				end
           96  +			end
           97  +		end
           98  +	end
           99  + 
          100  +	return props, devs
          101  +end
    28    102   
    29    103   local elixir_can_apply = function(elixir, potion)
    30    104   	-- accepts an elixir def and potion def
    31    105   	if elixir        == nil or
    32         -	   elixir._proto == nil or
    33    106   	   potion        == nil then return false end
    34    107   
    35         -	if elixir._proto.apply and potion.on_use then
          108  +	if elixir.apply and potion.on_use then
    36    109   		-- the ingredient is an elixir and at least one potion
    37    110   		-- is a fully enchanted, usable potion
    38         -		if elixir._proto.flag and potion._proto and
    39         -		   potion._proto['no_' .. elixir._proto.flag] == true then
          111  +		if elixir.flag and potion._proto and
          112  +		   potion._proto['no_' .. elixir.flag] == true then
    40    113   			-- does the elixir have a property used to denote
    41    114   			-- compatibility? if so, check the potion to see if it's
    42    115   			-- marked as incompatible
    43    116   			return false
    44    117   		else
    45    118   			return true
    46    119   		end
................................................................................
    66    139   				desc = desc;
    67    140   				affinity = aff;
    68    141   			}
    69    142   		end
    70    143   	::skip::end
    71    144   	return tbl
    72    145   end
          146  +
          147  +sorcery.alchemy.elixir_apply = function(elixir, potion)
          148  +	if not potion then return end
          149  +	local pdef = potion:get_definition()
          150  +	if elixir_can_apply(elixir, pdef) then
          151  +		elixir.apply(potion, pdef._proto)
          152  +		potion:get_meta():set_string('description', sorcery.lib.ui.tooltip {
          153  +			title = pdef._proto.name .. ' Draught';
          154  +			desc = pdef._proto.desc;
          155  +			color = sorcery.lib.color(pdef._proto.color):readable();
          156  +			props = effects_table(potion);
          157  +		});
          158  +	end
          159  +	return potion
          160  +end
          161  +
          162  +sorcery.alchemy.infuse = function(infusion, potions)
          163  +	local ingredient = infusion:get_name()
          164  +	local creations = {}
          165  +	local brewed = false
          166  +	for i = 1,#potions do
          167  +		if potions[i]:is_empty() then goto skip end
          168  +		local base = potions[i]:get_name()
          169  +		local potion = potions[i]:get_definition()
          170  +		local elixir = infusion:get_definition()
          171  +		brewed = true
          172  +		if elixir_can_apply(elixir._proto, potion) then
          173  +			local newstack = sorcery.alchemy.elixir_apply(elixir._proto, potions[i])
          174  +			if newstack ~= nil then
          175  +				creations[i] = {
          176  +					output = newstack;
          177  +					elixir = elixir;
          178  +					enhance = true;
          179  +				}
          180  +			else return true end
          181  +		else
          182  +			for _,v in pairs(sorcery.register.infusions.db) do
          183  +				if v.infuse == ingredient and v.into == base then
          184  +					-- transform the base into the infusion
          185  +					local out = ItemStack(v.output)
          186  +					if out ~= nil then
          187  +						creations[i] = {
          188  +							recipe = v;
          189  +							output = out;
          190  +							proto = minetest.registered_items[v.output]._proto;
          191  +							brew = true;
          192  +						}
          193  +					else return true end
          194  +				end
          195  +			end
          196  +		end
          197  +	::skip:: end
          198  +
          199  +	local residue = ItemStack(sorcery.register.residue.db[ingredient])
          200  +	return creations, residue
          201  +end
    73    202   
    74    203   local infuser_timer = function(pos, elapsed)
    75    204   	local meta = minetest.get_meta(pos)
    76    205   
    77    206   	local inv = meta:get_inventory()
    78    207   	local infusion = inv:get_list('infusion')
    79    208   	local potions = inv:get_list('potions')
    80    209   	local elixir = infusion[1]:get_definition()
    81    210   	local probe = sorcery.spell.probe(pos)
          211  +	local fx = infuser_mods(pos)
    82    212   	if probe.disjunction then return true end
    83    213   
    84    214   	local potionct = 0
    85    215   
    86    216   	do
    87    217   		local ingredient -- *eyeroll*
    88    218   		if infusion[1]:is_empty() then goto cancel end
    89    219   		ingredient = infusion[1]:get_name()
    90    220   		for i = 1,#potions do
    91    221   			if potions[i]:is_empty() then goto skip end
    92    222   			potionct = potionct + 1
    93    223   			local base = potions[i]:get_name()
    94    224   			local potion = potions[i]:get_definition()
    95         -			if elixir_can_apply(elixir,potion) then
          225  +			if elixir_can_apply(elixir._proto,potion) then
    96    226   				-- at least one combination makes a valid potion;
    97    227   				-- we can start the infuser
    98    228   				goto start
    99    229   			end
   100    230   			for _,v in pairs(sorcery.register.infusions.db) do
   101    231   				if v.infuse == ingredient and v.into == base then
   102    232   					-- at least one combination makes a valid
................................................................................
   112    242   		end
   113    243   
   114    244   		::start::
   115    245   	end
   116    246   
   117    247   	local time = meta:get_float("runtime") or 0
   118    248   	local newtime = time + elapsed
   119         -	local infusion_time = potionct * (15 * 60) -- 15 minutes per potion
          249  +	local infusion_time = potionct * (15 * 60) * (fx.brewtime or 1)-- 15 minutes per potion
   120    250   		-- FIXME make dependent on recipe
   121    251   	local percent = math.min(100, math.floor(100 * (newtime / infusion_time)))
   122    252   	local spawn = function(particle, scale, amt)
   123    253   		minetest.add_particlespawner {
   124         -			amount = amt;
   125         -			time = 15;
          254  +			amount = amt / 6;
          255  +			time = 2;
   126    256   			minpos = pos;
   127    257   			maxpos = pos;
   128    258   			minvel = {x = -0.1, y = 0.05, z = -0.1};
   129    259   			maxvel = {x = 0.1, y = 0.1, z = 0.1};
   130    260   			minacc = {x = 0, y = 0.1, z = 0};
   131    261   			maxacc = {x = 0, y = 0.4, z = 0};
   132    262   			minexptime = 2;
................................................................................
   151    281   	-- end
   152    282   	
   153    283   	local discharge = sorcery.lib.node.discharger(pos)
   154    284   	
   155    285   	if newtime >= infusion_time then
   156    286   		-- finished
   157    287   		local ingredient = infusion[1]:get_name()
   158         -		for i = 1,#potions do
   159         -			if potions[i]:is_empty() then goto skip end
   160         -			local base = potions[i]:get_name()
   161         -			local potion = potions[i]:get_definition()
   162         -			if elixir_can_apply(elixir, potion) then
   163         -				local newstack = inv:get_stack('potions',i)
   164         -				elixir._proto.apply(newstack, potion._proto)
   165         -				newstack:get_meta():set_string('description', sorcery.lib.ui.tooltip {
   166         -					title = potion._proto.name .. ' Draught';
   167         -					desc = potion._proto.desc;
   168         -					color = sorcery.lib.color(potion._proto.color):readable();
   169         -					props = effects_table(newstack);
   170         -				});
   171         -				inv:set_stack('potions',i,discharge(newstack))
   172         -			else
   173         -				for _,v in pairs(sorcery.register.infusions.db) do
   174         -					if v.infuse == ingredient and v.into == base then
   175         -						-- transform the base into the infusion
   176         -						inv:set_stack('potions',i,discharge(ItemStack(v.output)))
   177         -					end
   178         -				end
          288  +		local result, residue = sorcery.alchemy.infuse(infusion[1], potions)
          289  +		for i, r in pairs(result) do
          290  +			local out = r.output
          291  +			if r.brew then
          292  +				if fx.onbrew then out = fx.onbrew {
          293  +					pos = pos;
          294  +					stack = out;
          295  +					potion = r.proto;
          296  +					infusion = infusion[1];
          297  +					recipe = r.recipe;
          298  +				} end
          299  +				log.act(string.format('an infuser at %s has brewed a %s potion',
          300  +					minetest.pos_to_string(pos), out:get_name()))
          301  +			elseif r.enhance then
          302  +				if fx.onenhance then out = fx.onenhance {
          303  +					pos = pos;
          304  +					stack = out;
          305  +					potion = r.proto;
          306  +					elixir = r.elixir;
          307  +				} end
          308  +				log.act(dump(r))
          309  +				log.act(string.format('an infuser at %s has enhanced a %s potion with a %s elixir',
          310  +					minetest.pos_to_string(pos), out:get_name(), infusion[1]:get_name()))
   179    311   			end
   180         -		::skip:: end
          312  +			inv:set_stack('potions',i,discharge(out))
          313  +		end
   181    314   
   182         -		inv:set_stack('infusion',1,ItemStack(sorcery.register.residue.db[ingredient]))
          315  +		inv:set_stack('infusion',1,residue)
   183    316   
   184    317   		infuser_stop(pos)
   185    318   		return false
   186    319   	else
   187    320   		meta:set_float('runtime', newtime)
   188         -		meta:set_string('formspec', infuser_formspec(percent))
          321  +		meta:set_string('formspec', infuser_formspec(percent, true))
   189    322   		meta:set_string('infotext', 'Infuser (active)')
   190    323   		return true
   191    324   	end
   192    325   end
   193    326   
   194    327   local infuser_start = function(pos)
   195    328   	local meta = minetest.get_meta(pos)
   196    329   	infuser_stop(pos)
   197    330   	infuser_timer(pos,0)
   198         -	minetest.get_node_timer(pos):start(15)
          331  +	minetest.get_node_timer(pos):start(2)
   199    332   end
          333  +
          334  +local infrad = 0.42;
          335  +local infbox = {
          336  +	type = 'fixed';
          337  +	fixed = {
          338  +		-infrad, -0.5, -infrad;
          339  +		 infrad,  0.5,  infrad;
          340  +	};
          341  +};
   200    342   
   201    343   minetest.register_node("sorcery:infuser", {
   202    344   	description = "Infuser";
   203    345   	drawtype = "mesh";
   204    346   	mesh = "sorcery-infuser.obj";
   205         -	paramtype2 = "facedir";
          347  +	sunlight_propagates = true;
          348  +	paramtype = "light";
   206    349   	after_dig_node = sorcery.lib.node.purge_container;
   207    350   	tiles = { -- FIXME
   208    351   		"default_stone.png",
   209    352   		"default_copper_block.png",
   210    353   		"default_steel_block.png",
   211    354   		"default_bronze_block.png",
   212    355   		"default_tin_block.png",
   213    356   	};
   214    357   	paramtype2 = 'facedir';
   215    358   	groups = {
   216         -		cracky = 2, oddly_breakable_by_hand = 1, heavy = 1;
          359  +		cracky = 2, dig_immediate = 2, heavy = 1;
   217    360   		sorcery_alchemy = 1, sorcery_magitech = 1;
   218    361   	};
   219    362   	_sorcery = {
   220    363   		recipe = {
   221    364   			note = 'Infuse special ingredients into liquids to create and alter powerful potions';
   222    365   		};
   223    366   	};
   224         -	selection_box = {
   225         -		type = 'fixed';
   226         -		fixed = {
   227         -			-0.37, -0.5, -0.37,
   228         -			 0.37,  0.5,  0.37
   229         -		};
   230         -	};
   231         -	collision_box = {
   232         -		type = 'fixed';
   233         -		fixed = {
   234         -			-0.37, -0.5, -0.37,
   235         -			 0.37,  0.5,  0.37
   236         -		};
   237         -	};
          367  +	selection_box = infbox, collision_box = infbox;
   238    368   
   239    369   	on_construct = function(pos)
   240    370   		local meta = minetest.get_meta(pos)
   241    371   		local inv = meta:get_inventory()
   242    372   		inv:set_size('infusion', 1)
   243    373   		inv:set_size('potions', 3)
   244    374   		meta:set_string('infotext','Infuser')
................................................................................
   281    411   				return 1
   282    412   			end
   283    413   		else
   284    414   			return 0
   285    415   		end
   286    416   	end;
   287    417   })
          418  +
          419  +minetest.register_node("sorcery:infuser_accelerator", {
          420  +	description = "Infusion Accelerator";
          421  +	drawtype = "mesh";
          422  +	mesh = "sorcery-infuser-accelerator.obj";
          423  +	sunlight_propagates = true;
          424  +	paramtype = "light";
          425  +	paramtype2 = "facedir";
          426  +	tiles = { -- FIXME
          427  +		"basic_materials_brass_block.png",
          428  +		"default_stone.png",
          429  +		"default_copper_block.png",
          430  +	};
          431  +	paramtype2 = 'facedir';
          432  +	groups = {
          433  +		cracky = 2, heavy = 1;
          434  +		sorcery_alchemy = 1, sorcery_magitech = 1;
          435  +	};
          436  +	_sorcery = {
          437  +		recipe = {
          438  +			note = 'Connect to an infuser to speed up its operation; these can be stacked';
          439  +		};
          440  +		alchemy = {
          441  +			module = {
          442  +				attach = 'stack';
          443  +				brewtime = 0.6;
          444  +			};
          445  +		};
          446  +	};
          447  +	selection_box = infbox, collision_box = infbox;
          448  +})
          449  +
          450  +sorcery.alchemy.purge_stand = function(pos, node, meta, who)
          451  +	sorcery.lib.node.purge_container(pos,node,meta,who);
          452  +	local mod = sorcery.alchemy.is_module(node.name)
          453  +	if not mod then return end
          454  +	if mod.stmod_connect then
          455  +		for _,ofs in pairs(mod.stmod_connect) do
          456  +			local p = vector.add(pos,ofs)
          457  +			local nn = sorcery.lib.node.force(p).name
          458  +			local pm = sorcery.alchemy.is_module(nn)
          459  +			if pm then -- drop any attached modules
          460  +				minetest.dig_node(p)
          461  +			end
          462  +		end
          463  +	end
          464  +end
          465  +
          466  +minetest.register_node("sorcery:infuser_stand", {
          467  +	description = "Infuser Stand";
          468  +	drawtype = "mesh";
          469  +	mesh = "sorcery-infuser-stand.obj";
          470  +	paramtype2 = "facedir";
          471  +	after_dig_node = sorcery.alchemy.purge_stand;
          472  +	tiles = { -- FIXME
          473  +		"default_silver_sand.png",
          474  +		"default_stone.png",
          475  +		"default_copper_block.png",
          476  +		"default_wood.png",
          477  +		"default_aspen_wood.png",
          478  +		"default_steel_block.png",
          479  +	};
          480  +	paramtype2 = 'facedir';
          481  +	groups = {
          482  +		cracky = 2, choppy = 2, heavy = 1;
          483  +		sorcery_alchemy = 1, sorcery_magitech = 1;
          484  +	};
          485  +	_sorcery = {
          486  +		recipe = {
          487  +			note = 'Improve the effectiveness of an infuser by using a stand to attach modules';
          488  +		};
          489  +		alchemy = {
          490  +			module = {
          491  +				attach = 'stack';
          492  +				endstack = true;
          493  +				stmod_connect = {
          494  +					{x =  1, z =  0, y = 0};
          495  +					{x = -1, z =  0, y = 0};
          496  +					{x =  0, z =  1, y = 0};
          497  +					{x =  0, z = -1, y = 0};
          498  +				};
          499  +			};
          500  +		};
          501  +	};
          502  +	selection_box = {
          503  +		type = 'fixed', fixed = {
          504  +			-0.5, -0.5, -0.5,
          505  +			 0.5,  0.5,  0.5
          506  +		};
          507  +	};
          508  +	collision_box = {
          509  +		type = 'fixed', fixed = {
          510  +			-0.5, -0.5, -0.5,
          511  +			 0.5,  0.5,  0.5
          512  +		};
          513  +	};
          514  +
          515  +	on_construct = function(pos)
          516  +		local meta = minetest.get_meta(pos)
          517  +		local inv = meta:get_inventory()
          518  +		inv:set_size('shelves',6 * 2)
          519  +		meta:set_string('infotext','Infuser Stand')
          520  +		meta:set_string('formspec', [[
          521  +			size[8,6.25]
          522  +			list[context;shelves;0,0;3,2;]
          523  +			list[context;shelves;5,0;3,2;6]
          524  +			list[current_player;main;0,2.5;8,4;]
          525  +		]])
          526  +	end;
          527  +})
          528  +
          529  +minetest.register_craft {
          530  +	output = 'sorcery:infuser_stand';
          531  +	recipe = {
          532  +		{'sorcery:screw_copper','sorcery:conduction_plate','sorcery:screw_copper'};
          533  +		{'group:wood','basic_materials:wet_cement','group:wood'};
          534  +		{'default:bronze_ingot','sorcery:inversion_matrix','default:bronze_ingot'}
          535  +	};
          536  +}
          537  +
          538  +minetest.register_craft {
          539  +	output = 'sorcery:infuser_accelerator';
          540  +	recipe = {
          541  +		{'sorcery:brass_ingot','sorcery:conduction_plate','sorcery:brass_ingot'};
          542  +		{'basic_materials:motor','sorcery:catalytic_convector','basic_materials:motor'};
          543  +		{'default:stone','sorcery:leyline_stabilizer','default:stone'};
          544  +	};
          545  +}
          546  +
          547  +sorcery.alchemy.register_mod = function(prop, m)
          548  +	minetest.register_node(prop.name, sorcery.lib.tbl.merge({
          549  +		sunlight_propagates = true;
          550  +		paramtype = 'light', paramtype2 = 'facedir';
          551  +		drawtype = 'mesh';
          552  +
          553  +		groups = sorcery.lib.tbl.merge({
          554  +			cracky = 2;
          555  +			sorcery_magitech = 1;
          556  +			sorcery_alchemy = 1;
          557  +		}, prop.groups or {});
          558  +
          559  +		_sorcery = sorcery.lib.tbl.merge({
          560  +			alchemy = {
          561  +				module = sorcery.lib.tbl.merge({attach = 'stand'}, prop.module);
          562  +			};
          563  +			recipe = {
          564  +				note = prop.note;
          565  +			}
          566  +		}, prop.func or {});
          567  +
          568  +		node_placement_prediction = '';
          569  +
          570  +		on_place = function(stack, user, where)
          571  +			if not where or where.type ~= 'node' then return nil end
          572  +			local nd = minetest.get_node(where.under)
          573  +			if not nd then return nil end
          574  +			local def = minetest.registered_nodes[nd.name]
          575  +			if def and def._sorcery and def._sorcery.alchemy and def._sorcery.alchemy.module then
          576  +				local mod = def._sorcery.alchemy.module
          577  +				if not mod.stmod_connect then return nil end
          578  +				for _, ofs in pairs(mod.stmod_connect) do
          579  +					ofs = vector.rotate(ofs, vector.dir_to_rotation(minetest.facedir_to_dir(nd.param2)))
          580  +					if vector.equals(vector.add(where.under, ofs), where.above)
          581  +						and sorcery.lib.node.is_air(where.above) then goto valid end
          582  +				end
          583  +				do return nil end
          584  +
          585  +				::valid::
          586  +				minetest.set_node(where.above, {
          587  +					name = prop.name;
          588  +					param2 = minetest.dir_to_facedir(vector.subtract(where.under, where.above));
          589  +				})
          590  +				stack:take_item(1)
          591  +				return stack
          592  +			end
          593  +		end;
          594  +	}, m))
          595  +end
          596  +
          597  +sorcery.alchemy.register_mod({
          598  +	name = 'sorcery:infuser_mod_prolongator';
          599  +	note = 'Attached to an infuser using a stand, a Prolongator will cause it to produce longer-lasting potions';
          600  +	module = {
          601  +		onbrew = function(ctx)
          602  +			return sorcery.alchemy.elixir_apply(sorcery.data.elixirs.Longevity, ctx.stack)
          603  +		end;
          604  +	}
          605  +}, {
          606  +	description = 'Infusion Prolongator';
          607  +	mesh = 'sorcery-infuser-mod-prolongator.obj';
          608  +	inventory_image = 'sorcery_infuser_mod_prolongator.png';
          609  +	tiles = {
          610  +		sorcery.lib.image('default_diamond_block.png'):multiply(sorcery.lib.color(255,50,150)):render();
          611  +		'default_silver_sand.png';
          612  +		'default_copper_block.png';
          613  +		'default_steel_block.png';
          614  +	};
          615  +	selection_box = { type = 'fixed', fixed = { -0.23, -0.5, -0.2;  0.5, 0, 0.5; }; };
          616  +	collision_box = { type = 'fixed', fixed = { -0.23, -0.5, -0.2;  0.5, 0, 0.5; }; };
          617  +})
          618  +
          619  +sorcery.alchemy.register_mod({
          620  +	name = 'sorcery:infuser_mod_amplifier';
          621  +	note = 'Attached to an infuser using a stand, an Amplifier will cause it to produce more powerful potions';
          622  +	module = {
          623  +		onbrew = function(ctx)
          624  +			return sorcery.alchemy.elixir_apply(sorcery.data.elixirs.Force, ctx.stack)
          625  +		end;
          626  +	}
          627  +}, {
          628  +	description = 'Infusion Amplifier';
          629  +	mesh = 'sorcery-infuser-mod-amplifier.obj';
          630  +	inventory_image = 'sorcery_infuser_mod_amplifier.png';
          631  +	tiles = {
          632  +		sorcery.lib.image('default_diamond_block.png'):multiply(sorcery.lib.color(167,210,255)):render();
          633  +		'default_silver_sand.png';
          634  +		'default_copper_block.png';
          635  +		'default_steel_block.png';
          636  +		'default_wood.png';
          637  +		'default_aspen_wood.png';
          638  +	};
          639  +	selection_box = { type = 'fixed', fixed = { -0.41, -0.5, -0.1;  0.25, 0.22, 0.5; }; };
          640  +	collision_box = { type = 'fixed', fixed = { -0.41, -0.5, -0.1;  0.25, 0.22, 0.5; }; };
          641  +})
          642  +
          643  +-- sorcery.alchemy.register_mod({
          644  +-- 	name = 'sorcery:infuser_mod_auxiliator';
          645  +-- 	note = 'Attached to an infuser using a stand, provides an extra potion slot';
          646  +-- 	module = {
          647  +-- 		onbrew = function(ctx)
          648  +-- 		end;
          649  +-- 	}
          650  +-- }, {
          651  +-- 	description = 'Infusion Auxiliator';
          652  +-- 	mesh = 'sorcery-infuser-mod-auxiliator.obj';
          653  +-- 	inventory_image = 'sorcery_infuser_mod_auxiliator.png';
          654  +-- 	tiles = {
          655  +-- 		-- sorcery.lib.image('default_diamond_block.png'):multiply(sorcery.lib.color(167,210,255)):render();
          656  +-- 	};
          657  +-- 	selection_box = { type = 'fixed', fixed = { -0.41, -0.5, -0.1;  0.25, 0.22, 0.5; }; };
          658  +-- 	collision_box = { type = 'fixed', fixed = { -0.41, -0.5, -0.1;  0.25, 0.22, 0.5; }; };
          659  +-- })
          660  +
          661  +minetest.register_craft {
          662  +	output = 'sorcery:infuser_mod_prolongator';
          663  +	recipe = {
          664  +		-- this recipe is crap + way too cheap, come up with
          665  +		-- some fancy new ingredients and use them instead FIXME
          666  +		{'basic_materials:silver_wire','stairs:slab_copperblock',''};
          667  +		{'default:steel_ingot','sorcery:core_syncretic','default:steel_ingot'};
          668  +		{'sorcery:gem_ruby','default:copperblock','sorcery:gem_ruby'};
          669  +	};
          670  +}
          671  +
          672  +minetest.register_craft {
          673  +	output = 'sorcery:infuser_mod_amplifier';
          674  +	recipe = {
          675  +		-- this recipe is crap + way too cheap, come up with
          676  +		-- some fancy new ingredients and use them instead FIXME
          677  +		{'basic_materials:silver_wire','stairs:slab_copperblock',''};
          678  +		{'default:wood','sorcery:core_syncretic','default:wood'};
          679  +		{'sorcery:gem_sapphire','default:copperblock','sorcery:gem_sapphire'};
          680  +	};
          681  +}
          682  +
          683  +
          684  +-- other mods:
          685  +-- * amplifier
          686  +-- * elixir enhancer
          687  +-- * randomizer
          688  +-- * device that enables some kind of higher-tier potionmaking
          689  +-- * device that allows attaching 1 or 2 stand mods without terminating the stack
          690  +-- * radia collector - captures spare radia, occasionally can produce an extra potion, sometimes random