sorcery  Check-in [9ef6cbcf31]

Overview
Comment:add recipes, cookbooks, disassembly (to create recipes from items), attunement, farcasters, and portals; various edits for bug fixes and improvements
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 9ef6cbcf31c994b8599d0bcd9e88fa18114c438ab5ee8a3d0ba895ca5f7dc2cc
User & Date: lexi on 2020-08-28 14:08:57
Other Links: manifest | tags
Context
2020-08-30
14:45
add displacers; add item class mechanism; various tweaks, enhancements, and bugfixes esp. for books and paper check-in: 93f944b581 user: lexi tags: trunk
2020-08-28
14:08
add recipes, cookbooks, disassembly (to create recipes from items), attunement, farcasters, and portals; various edits for bug fixes and improvements check-in: 9ef6cbcf31 user: lexi tags: trunk
2020-08-21
11:52
add force field emitters, generators, rework leyline distribution algorithm, add utility function for automatically dumping out inventories when an item is dug, add draconium and tyrannium alloys (tentatively), various fixes check-in: f7f6898cbd user: lexi tags: trunk
Changes

Modified altar.lua from [1cf2c5fc2a] to [4b04c69ef3].

    58     58   		paramtype = 'light';
    59     59   		paramtype2 = 'facedir';
    60     60   		sunlight_propagates = true;
    61     61   		stack_max = 1;
    62     62   		tiles = god.idol.tex;
    63     63   		selection_box = { type = "fixed"; fixed = {hitbox}; };
    64     64   		collision_box = { type = "fixed"; fixed = {hitbox}; };
    65         -		groups = { cracky = 2, sorcery_idol = 1, heavy = 1};
           65  +		groups = { cracky = 2, sorcery_idol = 1, heavy = 1, sorcery_worship = 1};
    66     66   
    67     67   		after_place_node = function(pos, placer, stack, pointat)
    68     68   			local meta = minetest.get_meta(pos)
    69     69   			local stackmeta = stack:get_meta()
    70     70   			meta:set_int('favor', stackmeta:get_int('favor'))
    71     71   			meta:set_string('last_sacrifice', stackmeta:get_string('last_sacrifice'))
    72     72   
................................................................................
   193    193   				local itemname = stack:get_name()
   194    194   
   195    195   				-- loop through the sacrifices accepted by this god and check
   196    196   				-- whether the item on the altar is any of them
   197    197   				for s, value in pairs(god.sacrifice) do
   198    198   					if itemname == s then
   199    199   						if value < 0 then
   200         -							bestow("new_campfire:ash", sorcery.lib.color(254,117,103))
          200  +							bestow("sorcery:ash", sorcery.lib.color(254,117,103))
   201    201   						else
   202    202   							if idolmeta:get_string('last_sacrifice') == s then
   203    203   								-- the gods are getting bored
   204    204   								value = math.floor(value / 2)
   205    205   							end
   206    206   							bestow(nil)
   207    207   						end
................................................................................
   291    291   		fixed = { {-0.5, -0.5, -0.5, 0.5, -0.09, 0.5} }
   292    292   	};
   293    293   	collision_box = {
   294    294   		type = "fixed",
   295    295   		fixed = { {-0.5, -0.5, -0.5, 0.5, -0.09, 0.5} }
   296    296   	};
   297    297   
   298         -	groups = {cracky = 2, oddly_breakable_by_hand = 2};
          298  +	groups = {cracky = 2, oddly_breakable_by_hand = 2, sorcery_worship = 1};
   299    299   
   300    300   	on_construct = function(pos)
   301    301   		local meta = minetest.get_meta(pos)
   302    302   		local inv = meta:get_inventory()
   303    303   		inv:set_size('item', 1)
   304    304   	end;
   305    305   

Added attunement.lua version [3bc7b721d2].

            1  +local u = sorcery.lib
            2  +local m = u.marshal
            3  +local tunepack, tuneunpack = m.transcoder {
            4  +	code = m.t.u16; -- disambiguate just in case
            5  +	partner_x = m.t.s32;
            6  +	partner_y = m.t.s32;
            7  +	partner_z = m.t.s32;
            8  +	-- note that the meaning of 'partner' is a bit confusing. attuning
            9  +	-- is a directional relationship; that is, every item can be tuned
           10  +	-- to only one item (its partner), but more items can be tuned to
           11  +	-- it. while it will in most cases be reciprocal, this will not
           12  +	-- always be the case (e.g. with portals)
           13  +}
           14  +
           15  +sorcery.attunement = {
           16  +	nodeid = function(node)
           17  +		local meta = minetest.get_meta(node)
           18  +		local id
           19  +		if meta:contains('sorcery:identity') then
           20  +			id = meta:get_string('sorcery:identity')
           21  +		else
           22  +			id = sorcery.lib.str.rand(16)
           23  +			meta:set_string('sorcery:identity', id)
           24  +		end
           25  +		return id
           26  +	end;
           27  +	decode = function(raw)
           28  +		local obj = tuneunpack(u.str.meta_dearmor(raw,true))
           29  +		return {
           30  +			code = obj.code;
           31  +			partner = {
           32  +				x = obj.partner_x;
           33  +				y = obj.partner_y;
           34  +				z = obj.partner_z;
           35  +			};
           36  +		}
           37  +	end;
           38  +	encode = function(tune)
           39  +		return u.str.meta_armor(tunepack {
           40  +			code = tune.code;
           41  +			partner_x = tune.partner.x;
           42  +			partner_y = tune.partner.y;
           43  +			partner_z = tune.partner.z;
           44  +		}, true)
           45  +	end;
           46  +	get = function(node)
           47  +		local raw = minetest.get_meta(node):get_string('sorcery:attune')
           48  +		if not raw then return nil end
           49  +		return sorcery.attunement.decode(raw)
           50  +	end;
           51  +	verify = function(node)
           52  +		local tune = sorcery.attunement.get(node)
           53  +		if not tune then return nil end
           54  +		local ptnr = sorcery.attunement.get(tune.partner)
           55  +		if not ptnr then return nil end
           56  +
           57  +		local nodename =minetest.get_node(node).name
           58  +		local ptnrname =minetest.get_node(tune.partner).name
           59  +
           60  +		local ndef = minetest.registered_nodes[nodename]
           61  +		local pdef = minetest.registered_nodes[ptnrname]
           62  +
           63  +		if not (ndef and ndef._sorcery and pdef and pdef._sorcery and
           64  +			ndef._sorcery.attune and pdef._sorcery.attune) then return nil end
           65  +
           66  +		ndef = ndef._sorcery.attune pdef = pdef._sorcery.attune
           67  +
           68  +		if ndef.reciprocal and (not vector.equals(ptnr.partner, node)) then return nil end
           69  +
           70  +		if tune.code == ptnr.code then
           71  +			return tune, ptnr
           72  +		end
           73  +		return nil
           74  +	end;
           75  +	set = function(node,tune)
           76  +		local meta = minetest.get_meta(node)
           77  +		meta:set_string('sorcery:attune', sorcery.attunement.encode(tune))
           78  +		meta:mark_as_private('sorcery:attune')
           79  +	end;
           80  +	pair = function(reciprocal,src,dest)
           81  +		local d, code = sorcery.attunement.get(src)
           82  +		if reciprocal or not d then
           83  +			code = math.random(0,65536)
           84  +			sorcery.attunement.set(src, {
           85  +				code = code;
           86  +				partner = dest;
           87  +			})
           88  +		else code = d.code end
           89  +		sorcery.attunement.set(dest, {
           90  +			code = code;
           91  +			partner = src;
           92  +		})
           93  +	end;
           94  +}

Modified coins.lua from [f5d6bba856] to [2702148c37].

    84     84   } minetest.register_node('sorcery:coin_press', {
    85     85   	description = "Coin Press";
    86     86   	drawtype = 'mesh';
    87     87   	mesh = 'sorcery-coinpress.obj';
    88     88   	sunlight_propagates = true;
    89     89   	paramtype = 'light';
    90     90   	paramtype2 = 'facedir';
    91         -	groups = { cracky = 2; oddly_breakable_by_hand = 2; };
           91  +	groups = { cracky = 2; oddly_breakable_by_hand = 2; sorcery_metallurgy = 1};
    92     92   	tiles = {
    93     93   		'default_wood.png';
    94     94   		'default_stone.png';
    95     95   		'default_copper_block.png';
    96     96   		'default_steel_block.png';
    97     97   	};
    98     98   	selection_box = hitbox;

Modified compat.lua from [bd8d2ccd93] to [e7cd5fcdf6].

    22     22   	minetest.register_alias('sorcery:brass_ingot',brass..'_ingot')
    23     23   	minetest.register_alias('sorcery:brass_block',brass..'_block')
    24     24   end
    25     25   if silver then
    26     26   	minetest.register_alias('sorcery:silver_ingot',silver..'_ingot')
    27     27   	minetest.register_alias('sorcery:silver_block',silver..'_block')
    28     28   end
           29  +
           30  +if minetest.get_modpath("new_campfire") then
           31  +	minetest.register_alias('sorcery:ash', 'new_campfire:ash')
           32  +else
           33  +	minetest.register_craftitem('sorcery:ash', {
           34  +		description = 'Ash';
           35  +		inventory_image = 'sorcery_iron_powder.png^[colorize:#FFFFFF:100';
           36  +	})
           37  +	minetest.register_alias('new_campfire:ash', 'sorcery:ash')
           38  +end
    29     39   
    30     40   return {
    31     41   	defp = function(name)
    32     42   		return minetest.registered_items[name] or minetest.registered_aliases[name]
    33     43   	end
    34     44   }

Added cookbook.lua version [e0a46e6a8e].

            1  +-- by use of the enchanter, it is possible to reveal a random
            2  +-- recipe and enscribe it on a sheet of paper. these sheets of
            3  +-- paper can then bound together into books, combining like
            4  +-- recipes
            5  +
            6  +sorcery.cookbook = {}
            7  +local constants = {
            8  +	-- do not show recipes for items in these groups
            9  +	exclude_groups = {
           10  +	};
           11  +	exclude_names = {
           12  +		'_stairs';
           13  +		'_slab';
           14  +		'slope_';
           15  +	};
           16  +	-- do not show recipes from this namespace
           17  +	blacklist_mods = {
           18  +		'group'; -- WHY IS THIS NECESSARY
           19  +		'moreblocks'; -- too much noise
           20  +	};
           21  +
           22  +	recipes_per_cookbook_page = 3;
           23  +}
           24  +
           25  +local slot3x3 = {
           26  +	{0,0}, {1,0}, {2,0};
           27  +	{0,1}, {1,1}, {2,1};
           28  +	{0,2}, {1,2}, {2,2};
           29  +}
           30  +local props_builtin = function(item)
           31  +	local props = minetest.registered_items[item]._sorcery
           32  +	if props and props.recipe then
           33  +		return props.recipe
           34  +	end
           35  +	return {}
           36  +end
           37  +local modofname = function(id)
           38  +	local sep = string.find(id,':')
           39  +	if sep == nil then return nil end -- uh oh
           40  +	return string.sub(id, 1, sep - 1)
           41  +end
           42  +local pick_builtin = function(kind) return function(restrict)
           43  +	-- ow ow ow ow ow ow ow
           44  +	local names = {}
           45  +	for k in pairs(minetest.registered_items) do
           46  +		local rec = minetest.get_craft_recipe(k)
           47  +		if rec.items ~= nil and (rec.method == kind or (rec.method == 'shapeless' and kind == 'normal')) then -- is this last bit necessary?
           48  +			local excluded = false
           49  +			for _,n in pairs(constants.exclude_names) do
           50  +				if string.find(p,n) then
           51  +					excluded = true break end
           52  +			end
           53  +			if not excluded then for _,g in pairs(constants.exclude_groups) do
           54  +				if minetest.get_item_group(p, g) > 0 then
           55  +					excluded = true break end
           56  +			end end
           57  +			local props = minetest.registered_items[k]._sorcery
           58  +			local module = modofname(k)
           59  +			if not (excluded
           60  +				or sorcery.lib.tbl.has(constants.blacklist_mods,module)
           61  +				or (props and props.recipe and props.recipe.secret)
           62  +				or (restrict and (
           63  +				    (restrict.mod   and module ~= restrict.mod)
           64  +				 or (restrict.group and (minetest.get_item_group(k, restrict.group) == 0))
           65  +			))) then names[#names + 1] = k end
           66  +		end
           67  +	end
           68  +	return names[math.random(#names)]
           69  +end end
           70  +local find_builtin = function(out)
           71  +	local rec = {}
           72  +	local i = minetest.get_craft_recipe(out)
           73  +	if #i.items == 0 then return nil end
           74  +	local w = (i.width == 0) and 3 or i.width
           75  +	for j=1,#i.items do
           76  +		local row = math.floor((j-1) / w)
           77  +		local col = (j-1) % w
           78  +		if i.items[j] then
           79  +			rec[1 + (row * 3) + col] = i.items[j]
           80  +		end
           81  +	end
           82  +	return rec
           83  +end
           84  +local desc_builtin = function(i)
           85  +	local desc = minetest.registered_items[i].description
           86  +	if not desc then return 'Peculiar Item' end
           87  +
           88  +	local eol = string.find(desc,'\n')
           89  +	if not eol then return desc else return string.sub(desc,1,eol-1) end
           90  +end;
           91  +
           92  +local bookadjs = { -- sets are in reverse order!
           93  +	{'Celestial', 'Divine', 'Inspired', 'Heavenly';
           94  +	 'Mystic', 'Diabolic', 'Luminous', 'Forsaken'};
           95  +
           96  +	{'Dark', 'Perfected', 'Flawless', 'Unthinkable';
           97  +	 'Impossible', 'Worrisome', 'Unimpeachable'};
           98  +
           99  +	{'Splendid', 'Magnificent', 'Sublime', 'Grand';
          100  +	 'Beneficent', 'Mysterious', 'Peculiar', 'Eerie';
          101  +	 'Fulsome', 'Fearsome', 'Curious', 'Fascinating';
          102  +     'Notorious', 'Infamous'};
          103  +}
          104  +
          105  +sorcery.cookbook.classes = {
          106  +	craft = {
          107  +		name = 'Crafting Guide';
          108  +		node = 'xdecor:workbench';
          109  +		booksuf = 'Manual';
          110  +		w = 3, h = 3;
          111  +		chance = 2;
          112  +		slots = slot3x3;
          113  +		pick = pick_builtin('normal');
          114  +		find = find_builtin;
          115  +		desc = desc_builtin;
          116  +		props = props_builtin;
          117  +		apply_exclusions = true;
          118  +	};
          119  +	-- smelt = {
          120  +	-- 	w = 3, h = 3;
          121  +	-- 	slots = slot3x3;
          122  +	-- };
          123  +	cook = {
          124  +		name = 'Cooking Recipe';
          125  +		node = 'default:furnace';
          126  +		booksuf = 'Cookbook';
          127  +		w = 1, h = 1;
          128  +		chance = 5;
          129  +		slots = {{-0.2,0}};
          130  +		pick = pick_builtin('cooking');
          131  +		find = find_builtin;
          132  +		props = props_builtin;
          133  +		apply_exclusions = true;
          134  +	};
          135  +	infuse = {
          136  +		name = 'Infusion Recipe';
          137  +		node = 'sorcery:infuser';
          138  +		booksuf = 'Pharmacopeia';
          139  +		w = 1, h = 2;
          140  +		chance = 2;
          141  +		slots = {
          142  +			{0,0};
          143  +			{0,1};
          144  +		};
          145  +		pick = function(restrict)
          146  +			-- TODO make sure affinity restrictions match
          147  +			return sorcery.data.infusions[math.random(#sorcery.data.infusions)].output
          148  +		end;
          149  +		title = function(output)
          150  +			for _,i in pairs(sorcery.data.infusions) do
          151  +				print(dump(i))
          152  +				if i.output == output then
          153  +					if i._proto and i._proto.name
          154  +						then return i._proto.name
          155  +						else break end
          156  +				end
          157  +			end
          158  +			return 'Mysterious Potion'
          159  +		end;
          160  +		find = function(out)
          161  +			for _,i in pairs(sorcery.data.infusions) do
          162  +				if i.output == out then
          163  +					return { i.infuse, i.into }
          164  +				end
          165  +			end
          166  +		end;
          167  +		props = function(out)
          168  +			local i = sorcery.cookbook.classes.infuse.find(out)
          169  +			if i.recipe then return i.info else return {} end
          170  +		end;
          171  +	};
          172  +	-- wand = {
          173  +	--	booksuf = 'Grimoire';
          174  +	-- }
          175  +	enchant = {
          176  +		name = 'Enchantment Matrix';
          177  +		node = 'sorcery:enchanter';
          178  +		booksuf = 'Grimoire';
          179  +		drawslots = false;
          180  +		chance = 1;
          181  +		w = 2, h = 2;
          182  +		pick = function(restrict)
          183  +			-- TODO make sure affinity restrictions match
          184  +			local names = {}
          185  +			for k,v in pairs(sorcery.data.enchants) do
          186  +				if v.recipe then names[#names+1] = k end
          187  +			end
          188  +			return names[math.random(#names)]
          189  +		end;
          190  +		icon = function(name)
          191  +			return 'sorcery_enchant_' .. name .. '.png'
          192  +		end;
          193  +		find = function(name)
          194  +			local rec = {}
          195  +			local en = sorcery.data.enchants[name]
          196  +			if not en then return nil end
          197  +			en = en.recipe
          198  +			for i,e in pairs(en) do
          199  +				if e.lens then
          200  +					rec[i] = 'sorcery:lens_' .. e.lens .. '_' .. e.gem
          201  +				end
          202  +			end
          203  +			return rec
          204  +		end;
          205  +		props = function(name)
          206  +			return sorcery.data.enchants[name].info or {}
          207  +		end;
          208  +		slots = {
          209  +				{0.5,0};
          210  +			{0,1},   {1,1}
          211  +		};
          212  +		title = function(name) return sorcery.data.enchants[name].name end;
          213  +		outdesc = function(name,suffix)
          214  +			local e = sorcery.data.enchants[name]
          215  +			return sorcery.lib.ui.tooltip {
          216  +				title = e.name;
          217  +				desc = sorcery.lib.str.capitalize(e.desc);
          218  +				color = sorcery.lib.color(e.tone):readable();
          219  +			}
          220  +		end;
          221  +	};
          222  +	-- spells = {
          223  +	--  booksuf = 'Spellbook';
          224  +	--	slots = {
          225  +	--		{0,0}, {1,0};
          226  +	--		{0,1}, {1,1};
          227  +	--	};
          228  +	-- };
          229  +}
          230  +
          231  +local recipe_kinds = sorcery.cookbook.classes
          232  +
          233  +local namebook = function(kind,author)
          234  +	local name
          235  +	if kind then name = recipe_kinds[kind].booksuf
          236  +	        else name = 'Cyclopedia' end
          237  +	for _,set in pairs(bookadjs) do
          238  +		if math.random(3) == 1 then
          239  +			name = set[math.random(#set)] .. ' ' .. name
          240  +		end
          241  +	end
          242  +
          243  +	return sorcery.lib.str.capitalize(author) .. "'s " .. name
          244  +end
          245  +
          246  +sorcery.cookbook.pickrecipe = function(kind,restrict)
          247  +	if kind == nil then
          248  +		for k,v in pairs(recipe_kinds) do
          249  +			if math.random(v.chance) == 1 then
          250  +				kind = k break
          251  +			end
          252  +		end
          253  +		-- local rks = sorcery.lib.tbl.keys(recipe_kinds)
          254  +		-- kind = rks[math.random(#rks)]
          255  +	end
          256  +
          257  +	return recipe_kinds[kind].pick(restrict), kind
          258  +end
          259  +
          260  +local render_recipe = function(kind,ingredients,result)
          261  +	local k = recipe_kinds[kind]
          262  +	local t = ''
          263  +	for i=1,#k.slots do
          264  +		local x, y = k.slots[i][1], k.slots[i][2]
          265  +		if ingredients[i] and ingredients[i] ~= '' then
          266  +			local tt
          267  +			if k.indesc then tt = k.indesc(ingredients[i]) else tt = desc_builtin(ingredients[i]) end
          268  +			t = t .. string.format([[
          269  +				item_image[%f,%f;1,1;%s]
          270  +				tooltip[%f,%f;1,1;%s]
          271  +			]], x,y, minetest.formspec_escape(ingredients[i]),
          272  +			    x,y, minetest.formspec_escape(tt))
          273  +		else
          274  +			if k.drawslots == nil or k.drawslots then
          275  +				t = string.format('box[%f,%f;0.1,0.1;#00000060]',x+0.45,y+0.45) .. t
          276  +			end
          277  +		end
          278  +	end
          279  +	local img, ot
          280  +	local props = k.props(result)
          281  +	if props.note then
          282  +		t = t .. string.format([[
          283  +			textarea[0,3;4,1;;;%s]
          284  +		]], minetest.formspec_escape(props.note))
          285  +	end
          286  +	if k.icon then img = k.icon(result) end
          287  +	if k.outdesc then ot = k.outdesc(result) else ot = desc_builtin(result) end
          288  +		-- image[%f,%f;1,1;gui_furnace_arrow_bg.png^[transformR270]
          289  +	return t .. string.format([[
          290  +		item_image[%f,%f;1,1;%s]tooltip[%f,%f;1,1;%s]
          291  +		]] --[[box[%f,%f;1,1;#850083A0]] .. [[
          292  +		%s[%f,%f;1,1;%s]
          293  +		tooltip[%f,%f;1,1;%s]
          294  +	]], k.w, k.h/2 - 0.5, k.node,
          295  +		k.w, k.h/2 - 0.5, minetest.formspec_escape(minetest.registered_nodes[k.node].description),
          296  +			-- k.w+1, k.h/2 - 0.5,
          297  +		img and 'image' or 'item_image',
          298  +			k.w+1.1, k.h/2 - 0.5, minetest.formspec_escape(img or result),
          299  +			k.w+1.1, k.h/2 - 0.5, minetest.formspec_escape(ot))
          300  +end;
          301  +
          302  +local retrieve_recipe = function(kind,out)
          303  +	local rec = recipe_kinds[kind]
          304  +	local ing = rec.find(out)
          305  +	return render_recipe(kind,ing,out), rec.w, rec.h
          306  +end
          307  +
          308  +sorcery.cookbook.setrecipe = function(stack,k,r,restrict)
          309  +	local meta = stack:get_meta()
          310  +	if not r then r,k = sorcery.cookbook.pickrecipe(k,restrict) end
          311  +	local t = recipe_kinds[k]
          312  +	meta:set_string('recipe_kind', k)
          313  +	meta:set_string('recipe_name', r)
          314  +	meta:set_string('description',
          315  +		(t.title and t.title(r) or desc_builtin(r)) .. ' ' .. t.name)
          316  +end
          317  +
          318  +minetest.register_craftitem('sorcery:recipe', {
          319  +	description = 'Recipe';
          320  +	inventory_image = 'default_paper.png'; -- fixme
          321  +	groups = { flammable = 1; book = 1; paper = 1; };
          322  +	stack_max = 1;
          323  +	on_use = function(itemstack, user, target)
          324  +		local meta = itemstack:get_meta()
          325  +		if not meta:contains('recipe_kind') then sorcery.cookbook.setrecipe(itemstack) end
          326  +		local kind = meta:get_string('recipe_kind')
          327  +		local spec, w, h = retrieve_recipe(kind,meta:get_string('recipe_name'))
          328  +		minetest.show_formspec(user:get_player_name(), 'sorcery:recipe', string.format([[
          329  +			size[%f,%f]
          330  +			container[1,1] %s container_end[]
          331  +		]], w + 4,h + 2, 
          332  +				spec))
          333  +		return itemstack
          334  +	end;
          335  +})
          336  +
          337  +dungeon_loot.register {
          338  +	name = 'sorcery:recipe';
          339  +	chance = 0.9;
          340  +	count = {1,7};
          341  +}
          342  +
          343  +minetest.register_craft { type = 'fuel', recipe = 'sorcery:recipe', burntime = 3 }
          344  +minetest.register_craft {
          345  +	type = 'cooking';
          346  +	recipe = 'sorcery:recipe';
          347  +	output = 'sorcery:ash';
          348  +	cooktime = 3;
          349  +}
          350  +
          351  +default.register_craft_metadata_copy('default:paper','sorcery:recipe')
          352  +-- default.register_craft_metadata_copy('default:book','sorcery:cookbook')
          353  +
          354  +for i=1,8 do
          355  +	local rcp = {}
          356  +	for i=1,i do rcp[i] = 'sorcery:recipe' end
          357  +	rcp[#rcp+1]='default:book' minetest.register_craft {
          358  +		type = 'shapeless', recipe = rcp, output = 'sorcery:cookbook';
          359  +	}
          360  +	rcp[#rcp]='sorcery:cookbook' minetest.register_craft {
          361  +		type = 'shapeless', recipe = rcp, output = 'sorcery:cookbook';
          362  +	}
          363  +end
          364  +
          365  +
          366  +local m = sorcery.lib.marshal
          367  +local encbook, decbook = m.transcoder {
          368  +	pages = m.g.array(8, m.g.struct {
          369  +		kind = m.t.str;
          370  +		name = m.t.str;
          371  +	})
          372  +}
          373  +
          374  +local bookprops = function(stack)
          375  +	local meta = stack:get_meta()
          376  +	if meta:contains('cookbook') then
          377  +		return decbook(sorcery.lib.str.meta_dearmor(meta:get_string('cookbook'),true))
          378  +	else return {pages={}} end
          379  +end
          380  +
          381  +local bookform_ctx = {}
          382  +local bookform = function(stack,user)
          383  +	bookform_ctx[user:get_player_name()] = user:get_wield_index()
          384  +
          385  +	local meta = stack:get_meta()
          386  +	local book = bookprops(stack)
          387  +	local pagect = math.ceil(#book.pages / constants.recipes_per_cookbook_page)
          388  +	local curpage = meta:contains("pagenr") and meta:get_int("pagenr") or 1
          389  +
          390  +	local pgofs = (curpage - 1) * constants.recipes_per_cookbook_page
          391  +	local form = string.format([[
          392  +		formspec_version[3] 
          393  +		size[10,12]real_coordinates[true]
          394  +		box[0,0;10,1;#580C39FF]label[0.4,0.5;%s]
          395  +		button_exit[3,11;4,1;quit;Page %u/%u]
          396  +	]], minetest.formspec_escape(meta:get_string('description')),
          397  +	    curpage, pagect)
          398  +	
          399  +	if curpage > 1      then form = form .. 'button[0,11;3,1;pageback;< Back]' end
          400  +	if curpage < pagect then form = form .. 'button[7,11;3,1;pagenext;Next >]' end
          401  +
          402  +	local coords = {
          403  +		{2,1.3};
          404  +		{2,4.5};
          405  +		{2,7.7};
          406  +		-- {0,1.3}, {4, 1.3};
          407  +		-- {0,4.7}, {4, 4.7};
          408  +		-- {0,8.1}, {4, 8.1};
          409  +	}
          410  +	print('book:',dump(book))
          411  +	print('pgofs',pgofs)
          412  +	for i=pgofs,(pgofs + constants.recipes_per_cookbook_page-1) do
          413  +		local maxw, maxh = 3, 2
          414  +		if not book.pages[i+1] then break end
          415  +		local nr = 1+(i - pgofs)
          416  +		local x,y = coords[nr][1], coords[nr][2]
          417  +		local k = recipe_kinds[book.pages[i+1].kind]
          418  +		local ox,oy = maxw - k.w, maxh - k.h
          419  +		form = form .. string.format('container[%f,%f]%scontainer_end[]',(x+ox)-0.5,y,
          420  +			retrieve_recipe(book.pages[i+1].kind, book.pages[i+1].name))
          421  +	end
          422  +
          423  +	minetest.show_formspec(user:get_player_name(), 'sorcery:cookbook', form)
          424  +end
          425  +
          426  +minetest.register_craftitem('sorcery:cookbook', {
          427  +	description = 'Catalog';
          428  +	inventory_image = 'default_book_written.png';
          429  +	groups = { book = 1; flammable = 3 };
          430  +	on_use = function(stack,user)
          431  +		local book = bookprops(stack)
          432  +		if #book.pages == 0 then return nil end
          433  +		bookform(stack,user)
          434  +	end;
          435  +})
          436  +
          437  +minetest.register_on_player_receive_fields(function(user,form,fields)
          438  +	if form ~= 'sorcery:cookbook' then return false end
          439  +	if fields.quit then
          440  +		bookform_ctx[user:get_player_name()] = nil
          441  +		return true
          442  +	end
          443  +
          444  +	local idx = bookform_ctx[user:get_player_name()]
          445  +	if not idx then return true end
          446  +
          447  +	local uinv = user:get_inventory()
          448  +	local stack = uinv:get_stack('main', idx)
          449  +	local book = bookprops(stack)
          450  +	local meta = stack:get_meta()
          451  +
          452  +	local curpage = meta:contains("pagenr") and meta:get_int("pagenr") or 1
          453  +	local pagect = math.ceil(#book.pages / constants.recipes_per_cookbook_page)
          454  +
          455  +	if curpage > 1 and fields.pageback then
          456  +		meta:set_int('pagenr', curpage - 1)
          457  +	elseif curpage < pagect and fields.pagenext then
          458  +		meta:set_int('pagenr', curpage + 1)
          459  +	end
          460  +
          461  +	uinv:set_stack('main',idx,stack)
          462  +	bookform(stack,user)
          463  +end)
          464  +
          465  +minetest.register_on_craft(function(stack,player,grid,inv)
          466  +	if stack:get_name() ~= 'sorcery:cookbook' then return nil end
          467  +
          468  +	local oldbook
          469  +	local topic, onetopic = nil, true
          470  +	local recipes = {}
          471  +	for _,s in pairs(grid) do
          472  +		if s:get_name() == 'sorcery:recipe' then
          473  +			recipes[#recipes+1] = s
          474  +		elseif s:get_name() == 'sorcery:cookbook' then oldbook = s end
          475  +	end
          476  +
          477  +	oldbook = oldbook or stack
          478  +	local bookmeta = oldbook:get_meta()
          479  +	local newbook = not bookmeta:contains('cookbook')
          480  +	local book = bookprops(oldbook)
          481  +
          482  +	for _,s in pairs(recipes) do
          483  +		local meta = s:get_meta()
          484  +		local kind, item
          485  +		if meta:contains('recipe_kind') then
          486  +			kind = meta:get_string('recipe_kind')
          487  +			item = meta:get_string('recipe_name')
          488  +		else item, kind = sorcery.cookbook.pickrecipe(kind) end
          489  +		book.pages[#book.pages + 1] = { name = item, kind = kind }
          490  +		if topic then
          491  +			if topic ~= kind then onetopic = false end
          492  +		else topic = kind end
          493  +	end
          494  +
          495  +	if topic and newbook then
          496  +		if not onetopic then topic = nil end
          497  +		bookmeta:set_string('description',namebook(topic,player:get_player_name()))
          498  +		bookmeta:set_string('owner',player:get_player_name())
          499  +	end
          500  +
          501  +	print('new book',bookmeta:get_string('description'))
          502  +	print('new book',dump(book))
          503  +	bookmeta:set_string('cookbook', sorcery.lib.str.meta_armor(encbook(book),true))
          504  +	return oldbook
          505  +end)
          506  +
          507  +if minetest.get_modpath('books') then
          508  +	-- make our own placeable cookbook somehow
          509  +end

Added crafttools.lua version [569141ccf4].

            1  +minetest.register_on_craft(function(stack,crafter,recipe,grid)
            2  +	local ctoolclass = {
            3  +		[1] = 200;
            4  +		[2] = 100;
            5  +		[3] = 50;
            6  +		[4] = 10;
            7  +		[5] = 5;
            8  +	}
            9  +	for i=1,grid:get_size('craft') do
           10  +		local s = grid:get_stack('craft',i)
           11  +		local v = minetest.get_item_group(s:get_name(),'crafttool')
           12  +		if v ~= 0 then
           13  +			local dmg = 65536 / ctoolclass[v]
           14  +			local tool = recipe[i] 
           15  +			tool:add_wear(dmg)
           16  +			grid:set_stack('craft',i,tool)
           17  +		end
           18  +	end
           19  +	return nil
           20  +end)
           21  +
           22  +if minetest.get_modpath('xdecor') then
           23  +	local og = minetest.registered_tools['xdecor:hammer'].groups
           24  +	og.crafttool = 2
           25  +	minetest.override_item('xdecor:hammer', {groups = og})
           26  +end
           27  +
           28  +minetest.register_tool('sorcery:vice', {
           29  +	description = 'Vice';
           30  +	inventory_image = 'sorcery_vice.png';
           31  +	group = { crafttool = 3; }
           32  +})
           33  +minetest.register_craft {
           34  +	output = 'sorcery:vice';
           35  +	recipe = {
           36  +		{'default:steel_ingot','sorcery:screw_steel','default:steel_ingot'};
           37  +		{'default:bronze_ingot','sorcery:screw_steel','default:bronze_ingot'};
           38  +		{'default:tin_ingot','default:tin_ingot','default:tin_ingot'};
           39  +	};
           40  +}
           41  +-- chisel

Modified data/enchants.lua from [fc080855fd] to [2bce1083af].

    11     11   	'shovel'; 'axe';
    12     12   }
    13     13   return {
    14     14   	endure = { -- withstand more blows
    15     15   		name = 'Endure';
    16     16   		cost = 1;
    17     17   		tone = {232,102,255};
    18         -		desc = 'durability magnified';
           18  +		desc = 'tools last longer before wearing out';
    19     19   		affinity = 'counterpraxic';
    20     20   		groups = allgroups;
    21     21   		recipe = {
    22     22   			{lens = 'convex',    gem = 'amethyst', dmg = 2};
    23     23   			{lens = 'rectifier', gem = 'emerald',  dmg = 4};
    24     24   			{lens = 'convex',    gem = 'emerald',  dmg = 2};
    25     25   		};
................................................................................
    71     71   			end
    72     72   		end;
    73     73   	};
    74     74   	conserve = { -- use less magical energy
    75     75   		name = 'Conserve';
    76     76   		tone = {84,255,144};
    77     77   		cost = 0;
    78         -		desc = 'enchantments last longer before running out of power to sustain them.';
           78  +		desc = 'enchantments last longer before running out of power to sustain them';
    79     79   		groups = allgroups;
    80     80   		affinity = 'syncretic';
    81     81   		recipe = {
    82     82   			{lens = 'rectifier', gem = 'mese',     dmg = 7};
    83     83   			{lens = 'rectifier', gem = 'sapphire', dmg = 2};
    84     84   			{lens = 'rectifier', gem = 'amethyst', dmg = 2};
    85     85   		};
................................................................................
   124    124   					ctx.sparks[#ctx.sparks+1] = {
   125    125   						color = sorcery.lib.color(colors[minetest.get_node(n).name]);
   126    126   						count = 100 * dstfac;
   127    127   					}
   128    128   				end
   129    129   			end
   130    130   		end;
          131  +	};
          132  +	glitter = { -- increase odds of finding gem
          133  +		name = 'Glitter';
          134  +		cost = 10;
          135  +		tone = {255,50,60};
          136  +		desc = 'dramatically improve your chances of finding gems while mining veins';
          137  +		groups = {'pick','pickaxe'};
          138  +		affinity = 'entropic';
          139  +		recipe = {
          140  +			{lens = 'amplifier', gem = 'diamond',  dmg = 12};
          141  +			{lens = 'rectifier', gem = 'sapphire', dmg = 9};
          142  +			{lens = 'convex',    gem = 'ruby',     dmg = 7};
          143  +		};
   131    144   	};
   132    145   	pierce = { -- faster mining speed
   133    146   		name = 'Pierce';
   134    147   		cost = 3;
   135    148   		tone = {113,240,251};
   136    149   		groups = digtools;
   137    150   		{
................................................................................
   174    187   				local unit = 2
   175    188   				caps.groupcaps[g].maxlevel = caps[g].maxlevel + math.floor(unit*power)
   176    189   			end
   177    190   			stack:get_meta():set_tool_capabilities(caps)
   178    191   			return stack
   179    192   		end;
   180    193   	};
          194  +	-- multiply = {}; --  add a chance of receiving multiple drops of ore/coal
          195  +	-- leech = {}; -- draw power from local leylines
   181    196   }

Modified data/metals.lua from [a6eaeb7ad1] to [bb9d0957fb].

    27     27   	copper = {
    28     28   		dye = 'orange';
    29     29   		ingot = 'default:copper_ingot';
    30     30   		block = 'default:copperblock';
    31     31   		tone = {255,176,61};
    32     32   		no_tools = true; no_armor = true;
    33     33   		hardness = 2;
    34         -		conduct = 0.1;
           34  +		conduct = 0.3;
    35     35   	};
    36     36   	brass = {
    37     37   		tone = {255,226,87};
    38     38   		dye = 'bright_orange';
    39     39   		artificial = true;
    40     40   		no_tools = true; no_armor = true;
    41     41   		hardness = 3;
................................................................................
   137    137   		no_armor = true; no_tools = true;
   138    138   		power = 1; cooktime = 8; hardness = 1;
   139    139   	};
   140    140   	electrum = {
   141    141   		tone = {212, 255, 0}, alpha = 80;
   142    142   		artificial = true;
   143    143   		hardness = 1;
   144         -		conduct = 0.5;
          144  +		conduct = 2;
   145    145   		dye = 'bright_green';
   146    146   		mix = {
   147    147   			metals = {
   148    148   				silver = 1;
   149    149   				gold = 1;
   150    150   			};
   151    151   		};
................................................................................
   174    174   		rarity = 17;
   175    175   		durabilty = 900;
   176    176   		hardness = 6;
   177    177   		power = 3;
   178    178   		speed = 3.5;
   179    179   		cooktime = 30;
   180    180   		maxenergy = 3500;
   181         -		conduct = 2.0;
   182    181   		slots = {
   183    182   			{
   184    183   				affinity = {'counterpraxic'};
   185    184   				confluence = 0.65;
   186    185   				interference = {speed = 1};
   187    186   			};
   188    187   		}
................................................................................
   191    190   		tone = {255,252,93}, alpha = 80;
   192    191   		dye = 'yellow';
   193    192   		rarity = 13;
   194    193   		hardness = 2;
   195    194   		fuel = 80;
   196    195   		no_tools = true;
   197    196   		no_armor = true;
          197  +	};
          198  +	vidrium = {
          199  +		tone = {119,185,221}, alpha = 140;
          200  +		artificial = true;
          201  +		dye = 'cyan';
          202  +		hardness = 1;
          203  +		durability = 300;
          204  +		meltpoint = 2;
          205  +		cooktime = 20;
          206  +		no_tools = true, no_armor = true;
          207  +		conduct = 5;
          208  +		mix = {
          209  +			metals = {
          210  +				lithium = 2;
          211  +				tin = 4;
          212  +				gold = 1;
          213  +			}
          214  +		};
          215  +		sinter = {
          216  +			'gold'; 'lithium', 'lithium';
          217  +			'tin', 'tin', 'tin', 'tin';
          218  +		};
   198    219   	};
   199    220   	iridium = {
   200    221   		tone = {209,88,241}, alpha = 80;
   201    222   		dye = 'purple';
   202    223   		rarity = 18;
   203    224   		meltpoint = 3;
   204    225   		cooktime = 340;
   205    226   		hardness = 7;
   206    227   		maxenergy = 1800;
   207         -		conduct = 5;
          228  +		conduct = 10;
   208    229   		durability = 1900;
   209         -		speed = 3.2;
          230  +		speed = 3;
   210    231   		img = {
   211    232   			-- ingot = 'sorcery_iridium_ingot.png';
   212    233   			-- block = 'sorcery_iridium_block.png';
   213    234   		};
   214    235   		slots = {
   215    236   			{affinity={'counterpraxic','syncretic'}, confluence = 1.1};
   216    237   			{affinity={'cognic','entropic'}, confluence = 0.8};
................................................................................
   277    298   			metals = {
   278    299   				iridium = 2;
   279    300   				tungsten = 2;
   280    301   				lithium = 1;
   281    302   			};
   282    303   		};
   283    304   		sinter = {
   284         -			'sorcery:powder_iridium';
   285         -			'sorcery:powder_iridium';
   286         -			'sorcery:powder_tungsten';
   287         -			'sorcery:powder_tungsten';
   288         -			'sorcery:powder_lithium';
          305  +			'lithium';
          306  +			'iridium', 'iridium';
          307  +			'tungsten', 'tungsten';
   289    308   		};
   290    309   		slots = {
   291    310   			{affinity={'praxic','entropic'}, confluence = 1.4};
   292    311   			{affinity={'praxic','syncretic'}, confluence = 1.1};
   293    312   		}
   294    313   	};
   295    314   	unobtanium = {
................................................................................
   296    315   		tone = {114,255,214}, alpha = 120;
   297    316   		meltpoint = 3;
   298    317   		cooktime = 330;
   299    318   		artificial = true;
   300    319   		maxenergy = 4000;
   301    320   		hardness = 7;
   302    321   		durability = 3300;
   303         -		conduct = 15;
          322  +		conduct = 20;
   304    323   		speed = 3.4;
   305    324   		slots = {
   306    325   			{affinity={'praxic'}, confluence = 0.7};
   307    326   			{affinity={'counterpraxic'}, confluence = 1.2};
   308    327   			{affinity={'cognic'}, confluence = 1.1};
   309    328   		};
   310    329   		mix = {
................................................................................
   317    336   	};
   318    337   	draconium = {
   319    338   		tone = {255,20,80}, alpha = 110;
   320    339   		artificial=true;
   321    340   		meltpoint = 5;
   322    341   		cooktime = 120;
   323    342   		hardness = 8;
   324         -		maxconduct = 10;
          343  +		maxconduct = 15;
   325    344   		speed = 1.7;
   326    345   		maxenergy = 2200;
   327    346   		durability = 1500;
   328    347   		slots = {
   329    348   			{affinity={'praxic'},confluence=3};
   330    349   			{affinity={'syncretic'},confluence=2};
   331    350   		};
   332    351   		sinter = {
   333         -			'sorcery:powder_lithium';
   334         -			'sorcery:powder_aluminum';
   335         -			'sorcery:powder_iridium';
   336         -			'sorcery:oil_flame';
          352  +			'lithium'; 'aluminum'; 'iridium';
   337    353   		};
          354  +		sinter_catalyst = { 'sorcery:oil_flame' };
   338    355   	};
   339    356   	tyrannium = {
   340    357   		tone = {46,255,245}, alpha = 80;
   341    358   		artificial=true;
   342    359   		hardness = 20;
   343    360   		meltpoint = 6;
   344    361   		cooktime = 240;
   345    362   		maxenergy = 800;
   346    363   		durability = 4000;
   347    364   		speed = 3.0;
   348    365   		slots = {};
   349    366   	};
   350    367   };

Modified data/potions.lua from [c61093f3aa] to [eb3ff7cdbe].

     5      5   		basis = 'sorcery:potion_water';
     6      6   	};
     7      7   	Majestic = {
     8      8   		color = {253,133,194};
     9      9   		style = 'sparkle';
    10     10   		infusion = 'sorcery:oil_mystic';
    11     11   		basis = 'sorcery:holy_water';
           12  +		substitutes = 'Serene';
    12     13   		glow = 8;
    13     14   	};
    14     15   	Misty = {
    15     16   		color = {186,241,233};
    16     17   		infusion = 'sorcery:grease_fog';
    17     18   	};
    18     19   	Luminous = {
................................................................................
    26     27   		style = 'sparkle';
    27     28   		infusion = 'sorcery:extract_cotton';
    28     29   	};
    29     30   	Viscous = {
    30     31   		color = {119,51,111};
    31     32   		infusion = 'sorcery:oil_bleak';
    32     33   	};
           34  +	Isolating = {
           35  +		color = {188,78,225};
           36  +		infusion = 'sorcery:extract_fern';
           37  +	};
    33     38   }

Modified data/spells.lua from [a738b55bd0] to [26201c3a3e].

            1  +local cast_sparkle = function(ctx,color,strength,duration)
            2  +	minetest.add_particlespawner {
            3  +		amount = 70 * strength;
            4  +		time = duration or 1.5;
            5  +		attached = ctx.caster;
            6  +		texture = sorcery.lib.image('sorcery_spark.png'):multiply(color):render();
            7  +		minpos = { x = -0.1, z =  0.5, y =  1.2}; 
            8  +		maxpos = { x =  0.1, z =  0.3, y =  1.6}; 
            9  +		minvel = { x = -0.5, z = -0.5, y = -0.5};
           10  +		maxvel = { x =  0.5, z =  0.5, y =  0.5};
           11  +		minacc = { x =  0.0, z =  0.0, y =  0.5};
           12  +		maxacc = { x =  0.0, z =  0.0, y =  0.5};
           13  +		minsize = 0.4, maxsize = 0.8;
           14  +		minexptime = 1, maxexptime = 1;
           15  +		glow = 14;
           16  +		animation = {
           17  +			type = 'vertical_frames';
           18  +			aspect_w = 16;
           19  +			aspect_h = 16;
           20  +			length = 1.1;
           21  +		};
           22  +	}
           23  +end
     1     24   local enchantment_sparkle = function(ctx,color)
           25  +	local minvel, maxvel
           26  +	if minetest.get_node(vector.add(ctx.target.under,{y=1,z=0,x=0})).name == 'air' then
           27  +		minvel = {x=0,z=0,y= 0.3}  maxvel = {x=0,z=0,y= 1.5};
           28  +	else
           29  +		local dir = vector.subtract(ctx.target.under,ctx.target.above)
           30  +		minvel = vector.multiply(dir, 0.3)
           31  +		maxvel = vector.multiply(dir, 1.2)
           32  +	end
     2     33   	return minetest.add_particlespawner {
     3     34   		amount = 50;
     4     35   		time = 0.5;
     5     36   		minpos = vector.subtract(ctx.target.under, 0.5);
     6     37   		maxpos = vector.add(ctx.target.under, 0.5);
     7         -		minvel = {x=0,z=0,y= 0.3}, maxvel = {x=0,z=0,y= 1.5};
     8         -		minacc = {x=-0.2,z=-0.2,y=-0.1}, maxacc = {x=0.2,z=0.2,y=-0.2};
           38  +		minvel = minvel, maxvel = maxvel;
     9     39   		minexptime = 1, maxexptime = 2;
    10     40   		minsize = 0.5, maxsize = 2;
    11     41   		texture = sorcery.lib.image('sorcery_spark.png'):multiply(color):render();
    12     42   		animation = {
    13     43   			type = 'vertical_frames';
    14     44   			aspect_w = 16, aspect_h = 16;
    15     45   			length = 2;
................................................................................
   232    262   		affinity = {'apple','silent'};
   233    263   		uses = 128;
   234    264   		desc = 'Reveal the strength and affinities of the local leyline';
   235    265   		cast = function(ctx)
   236    266   			local color = ctx.base.gem == 'sapphire';
   237    267   			local duration = (ctx.base.gem == 'amethyst' and 4) or 2;
   238    268   			local ley = sorcery.ley.estimate(ctx.caster:get_pos())
   239         -			local emit = function(color,strength)
   240         -				minetest.add_particlespawner {
   241         -					amount = 70 * strength;
   242         -					time = duration * strength;
   243         -					attached = ctx.caster;
   244         -					texture = sorcery.lib.image('sorcery_spark.png'):
   245         -						multiply(color:brighten(1.3)):render();
   246         -					minpos = { x = -0.1, z =  0.5, y =  1.2}; 
   247         -					maxpos = { x =  0.1, z =  0.3, y =  1.6}; 
   248         -					minvel = { x = -0.5, z = -0.5, y = -0.5};
   249         -					maxvel = { x =  0.5, z =  0.5, y =  0.5};
   250         -					minacc = { x =  0.0, z =  0.0, y =  0.5};
   251         -					maxacc = { x =  0.0, z =  0.0, y =  0.5};
   252         -					minsize = 0.4, maxsize = 0.8;
   253         -					minexptime = 1, maxexptime = 1;
   254         -					glow = 14;
   255         -					animation = {
   256         -						type = 'vertical_frames';
   257         -						aspect_w = 16;
   258         -						aspect_h = 16;
   259         -						length = 1.1;
   260         -					};
   261         -				}
   262         -			end
   263    269   
   264    270   			local strength = ley.force
   265    271   			if color then
   266    272   				strength = strength / #ley.aff
   267    273   				for _,a in pairs(ley.aff) do
   268         -					emit(sorcery.lib.color(sorcery.data.affinities[a].color), strength)
          274  +					cast_sparkle(ctx,sorcery.lib.color(sorcery.data.affinities[a].color):brighten(1.3), strength, duration * strength)
   269    275   				end
   270    276   			else
   271         -				emit(sorcery.lib.color(250,255,185), strength)
          277  +				cast_sparkle(ctx,sorcery.lib.color(250,255,185), strength, duration*strength)
   272    278   			end
   273    279   
   274    280   		end;
   275    281   	};
   276    282   	dowse = {
   277    283   		name = 'dowsing';
   278    284   		leytype = 'cognic';
................................................................................
   308    314   	attune = {
   309    315   		name = 'attunement';
   310    316   		uses = 38;
   311    317   		color = {255,65,207};
   312    318   		leytype = 'syncretic';
   313    319   		affinity = {'pine','verdant','dark'};
   314    320   		desc = 'Establish a connection between mystic mechanisms, like connecting two sides of a portal or impressing targets onto a dowsing wand in an enchanter';
          321  +		cast = function(ctx)
          322  +			if not (ctx.target and ctx.target.type == 'node') then
          323  +				ctx.meta:set_string('source','')
          324  +				cast_sparkle(ctx, sorcery.lib.color(234,45,100), 0.3)
          325  +				return true
          326  +			end
          327  +			local n = minetest.registered_nodes[minetest.get_node(ctx.target.under).name]
          328  +			if not (n and n._sorcery and n._sorcery.attune) then
          329  +				return false end -- just in case anyone casts on an undefined node
          330  +			local m = sorcery.lib.marshal
          331  +			local encpos, decpos = m.transcoder {
          332  +				x = m.t.s32, y = m.t.s32, z = m.t.s32;
          333  +				id = m.t.str;
          334  +			}
          335  +			local props = n._sorcery.attune
          336  +
          337  +			local rec = ctx.meta:get_string('source')
          338  +			local src
          339  +			if rec then
          340  +				local data = decpos(sorcery.lib.str.meta_dearmor(rec,true))
          341  +				local srcpos = {x=data.x,y=data.y,z=data.z}
          342  +				local srcnode = minetest.get_node(srcpos)
          343  +				local srcdef = minetest.registered_nodes[srcnode.name]
          344  +				if srcdef and srcdef._sorcery and srcdef._sorcery.attune then
          345  +					if sorcery.attunement.nodeid(srcpos) == data.id then
          346  +						-- check for ink
          347  +						src = { 
          348  +							pos = srcpos;
          349  +							props = srcdef._sorcery.attune;
          350  +						}
          351  +					end
          352  +				end
          353  +			end
          354  +
          355  +			local color
          356  +			if src and src.props.source and
          357  +			   src.props.class == props.accepts and props.target and
          358  +			   (not vector.equals(src.pos, ctx.target.under)) then
          359  +				sorcery.attunement.pair(src.props.reciprocal or true, src.pos, ctx.target.under)
          360  +				ctx.meta:set_string('source','')
          361  +				color = sorcery.lib.color(255,130,75)
          362  +			elseif props.source then
          363  +				ctx.meta:set_string('source', sorcery.lib.str.meta_armor(encpos {
          364  +					x = ctx.target.under.x;
          365  +					y = ctx.target.under.y;
          366  +					z = ctx.target.under.z;
          367  +					id = sorcery.attunement.nodeid(ctx.target.under);
          368  +				},true))
          369  +				color = sorcery.lib.color(128,75,255)
          370  +			end
          371  +
          372  +			if color then enchantment_sparkle(ctx,color)
          373  +				else return false end
          374  +		end;
   315    375   	};
   316    376   	meld = {
   317    377   		name = 'melding';
   318    378   		uses = 48;
   319    379   		leytype = 'syncretic';
   320    380   		color = {172,65,255};
   321    381   		affinity = {'apple','verdant'};
................................................................................
   364    424   	disjoin = {
   365    425   		name = 'disjunction';
   366    426   		uses = 32;
   367    427   		color = {17,6,212};
   368    428   		leytype = 'occlutic';
   369    429   		affinity = {'jungle','silent'};
   370    430   		desc = 'With an enchanter, disjoin the anchor holding a spell into an object so a new spell can instead be bound in';
          431  +	};
          432  +	divine = {
          433  +		name = 'divining';
          434  +		desc = 'Steal away the secrets of the cosmos';
          435  +		uses = 16;
          436  +		color= {97,97,255};
          437  +		sound = 'xdecor:enchanting';
          438  +		leytype = 'cognic';
          439  +		affinity = {'pine','shimmering','dark','verdant'};
          440  +		cast = function(ctx)
          441  +			local inks = {'black','red','white','violet','blue','green'}
          442  +			local getcolor = function(stack)
          443  +				 if stack:is_empty() then return nil end
          444  +				 if minetest.get_item_group(stack:get_name(), 'dye') == 0 then return nil end
          445  +				 for _,ink in pairs(inks) do
          446  +					 if minetest.get_item_group(stack:get_name(), 'color_' ..ink) ~= 0
          447  +						 then print('found',ink,'ink') return ink end
          448  +				 end
          449  +			end
          450  +			if not ctx.target or ctx.target.type ~= 'node' then return false end
          451  +			local tgt = minetest.get_node(ctx.target.under)
          452  +			if tgt.name == 'sorcery:enchanter' then
          453  +				local meta = minetest.get_meta(ctx.target.under)
          454  +				local inv = meta:get_inventory()
          455  +				if inv:get_stack('item',1):get_name() == 'default:paper'
          456  +					and inv:get_stack('item',1):get_count() == 1
          457  +					and not inv:is_empty('foci') then
          458  +				   local ink1 = getcolor(inv:get_stack('foci',2))
          459  +				   local ink2 = getcolor(inv:get_stack('foci',3))
          460  +				   local restrict, kind, mod = {} do
          461  +					   local ms = inv:get_stack('foci',1)
          462  +					   if not ms:is_empty() then mod = ms:get_name() end
          463  +				   end
          464  +				   print(ink1,ink2,mod)
          465  +				   if ink1 == 'black' and ink2 == 'black' then kind = 'craft'
          466  +					   if mod then
          467  +						   if mod == sorcery.data.metals.cobalt.parts.powder then
          468  +							   restrict.group = 'sorcery_magitech'
          469  +						   elseif mod == sorcery.data.metals.vidrium.parts.powder then
          470  +							   restrict.group = 'sorcery_ley_device'
          471  +						   elseif mod == sorcery.data.metals.aluminum.parts.powder then
          472  +							   restrict.group = 'sorcery_metallurgy'
          473  +						   elseif mod == sorcery.data.metals.lithium.parts.powder then
          474  +							   restrict.group = 'sorcery_enchanting_lens'
          475  +						   elseif mod == sorcery.data.metals.iridium.parts.powder then
          476  +							   restrict.group = 'sorcery_worship'
          477  +						   elseif mod == sorcery.data.metals.gold.parts.powder then
          478  +							   restrict.group = 'sorcery_grease'
          479  +						   elseif mod == sorcery.data.metals.silver.parts.powder then
          480  +							   restrict.group = 'sorcery_oil'
          481  +						   elseif mod == sorcery.data.metals.electrum.parts.powder then
          482  +							   restrict.group = 'sorcery_extract'
          483  +						   elseif mod == 'farming:sugar' then
          484  +							   restrict.mod = 'farming'
          485  +						   else return false end
          486  +					   end
          487  +				   elseif ink1 == 'black' and ink2 == 'white' then kind = 'infuse'
          488  +					   if mod then
          489  +						   if mod == sorcery.data.metals.gold.parts.powder then
          490  +							   restrict.mod = 'sorcery_draught'
          491  +						   elseif mod == sorcery.data.metals.cobalt.parts.powder then
          492  +							   restrict.mod = 'sorcery_philter'
          493  +						   elseif mod == sorcery.data.metals.lithium.parts.powder then
          494  +							   restrict.mod = 'sorcery_elixirs'
          495  +						   else return false end
          496  +					   end
          497  +				   elseif ink1 == 'blue' and ink2 == 'violet' then kind = 'enchant'
          498  +					   if mod then
          499  +						   if mod == sorcery.data.metals.cobalt.parts.powder then
          500  +							   restrict.aff = 'praxic'
          501  +						   elseif mod == sorcery.data.metals.tungsten.parts.powder then
          502  +							   restrict.aff = 'counterpraxic'
          503  +						   elseif mod == sorcery.data.metals.aluminum.parts.powder then
          504  +							   restrict.aff = 'syncretic'
          505  +						   elseif mod == sorcery.data.metals.lithium.parts.powder then
          506  +							   -- restrict.aff = 'mandatic' -- no enchants yet, will cause infinite loop
          507  +						   elseif mod == sorcery.data.metals.iridium.parts.powder then
          508  +							   restrict.aff = 'entropic'
          509  +						   elseif mod == sorcery.data.metals.gold.parts.powder then
          510  +							   restrict.aff = 'cognic'
          511  +						   elseif mod == sorcery.data.metals.silver.parts.powder then
          512  +							   -- restrict.aff = 'occlutic'
          513  +						   elseif mod == sorcery.data.metals.electrum.parts.powder then
          514  +							   -- restrict.aff = 'imperic'
          515  +						   else return false end
          516  +					   end
          517  +				   elseif ink1 == 'red' and ink2 == 'yellow' then kind = 'cook';
          518  +				   -- elseif ink1 == 'red' and ink2 == 'orange' then kind = 'smelt';
          519  +				   end
          520  +				   print('result',kind,dump(restrict))
          521  +				   if kind then
          522  +					   print('found kind')
          523  +					   local rec = ItemStack('sorcery:recipe')
          524  +					   local m = rec:get_meta()
          525  +					   if ctx.base.gem == 'diamond' then
          526  +						   -- make recipe for thing in slot 1
          527  +					   else
          528  +						   sorcery.cookbook.setrecipe(rec,kind,nil,restrict)
          529  +					   end
          530  +					   inv:set_stack('item',1,rec)
          531  +					   for i=1,inv:get_size('foci') do
          532  +						   local f = inv:get_stack('foci',i)
          533  +						   f:take_item(1)
          534  +						   inv:set_stack('foci',i,f)
          535  +					   end
          536  +					   enchantment_sparkle(ctx,sorcery.lib.color(97,97,255))
          537  +					   return
          538  +				   end
          539  +				end
          540  +			end
          541  +			return false
          542  +		end;
   371    543   	};
   372    544   	luminate = {
   373    545   		name = 'lumination';
   374    546   		desc = 'Banish darkness all about you for a few moments';
   375    547   		uses = 40;
   376    548   		color = {244,255,157};
   377    549   		affinity = {'acacia','shimmering','blazing'};

Added disassembly.lua version [5ba85bac04].

            1  +local update_disassembler = function(pos)
            2  +	local m = minetest.get_meta(pos)
            3  +	local i = m:get_inventory()
            4  +	local paper = i:get_stack('paper',1)
            5  +	local item = i:get_stack('item',1)
            6  +
            7  +	local ink_count
            8  +	for j=1,i:get_size('ink') do
            9  +		local ink = i:get_stack('ink',j)
           10  +		local c = ink:get_count()
           11  +		if ink_count then
           12  +			if c < ink_count then ink_count = c end
           13  +		else ink_count = c end
           14  +	end
           15  +	
           16  +	ink_count = ink_count or 0
           17  +	local maxrecs = math.min(ink_count, paper:get_count(), item:get_count())
           18  +
           19  +	if maxrecs > 0 and sorcery.cookbook.classes.craft.find(item:get_name()) then
           20  +		local rec = ItemStack{name = 'sorcery:recipe', count = maxrecs}
           21  +		sorcery.cookbook.setrecipe(rec, 'craft', item:get_name())
           22  +		i:set_stack('output',1,rec)
           23  +	else
           24  +		i:set_stack('output',1,ItemStack())
           25  +	end
           26  +end
           27  +minetest.register_node('sorcery:disassembler', {
           28  +	description = 'Disassembly Kit';
           29  +	drawtype = 'mesh';
           30  +	mesh = 'sorcery-disassembler.obj';
           31  +	paramtype = 'light', sunlight_propagates = true;
           32  +	paramtype2 = 'facedir';
           33  +	groups = { cracky = 2, sorcery_tech = 1 };
           34  +	tiles = {
           35  +		'default_copper_block.png';
           36  +		'default_wood.png';
           37  +		'default_steel_block.png';
           38  +		'default_stone.png';
           39  +		'default_gold_block.png';
           40  +		'default_coal_block.png';
           41  +	};
           42  +	after_dig_node = sorcery.lib.node.purge_container;
           43  +	on_construct = function(pos)
           44  +		local m = minetest.get_meta(pos)
           45  +		local i = m:get_inventory()
           46  +		i:set_size('item',1)
           47  +		i:set_size('paper',1)
           48  +		i:set_size('ink',3)
           49  +		i:set_size('output',1)
           50  +		m:set_string('infotext','Disassembly Kit')
           51  +		m:set_string('formspec', [[
           52  +			formspec_version[3]
           53  +			size[10.25,7] real_coordinates[true]
           54  +			list[current_player;main;0.25,2;8,4]
           55  +
           56  +			list[context;item;0.25,0.5;1,1;]
           57  +			list[context;paper;2.25,0.5;1,1;]
           58  +			list[context;ink;4.25,0.5;3,1;]
           59  +			list[context;output;9,0.5;1,1;]
           60  +
           61  +			listring[current_player;main] listring[context;item]
           62  +			listring[current_player;main] listring[context;paper]
           63  +			listring[current_player;main] listring[context;ink]
           64  +		]])
           65  +	end;
           66  +	on_metadata_inventory_put = update_disassembler;
           67  +	on_metadata_inventory_take = function(pos,list,idx,stack,user)
           68  +		local m = minetest.get_meta(pos)
           69  +		local i = m:get_inventory()
           70  +		local paper = i:get_stack('paper',1)
           71  +		local item = i:get_stack('item',1)
           72  +
           73  +		if list == 'output' then
           74  +			local count = stack:get_count()
           75  +			item:take_item(count)
           76  +			i:set_stack('item',1,item)
           77  +			for j=1,i:get_size('ink') do
           78  +				local ink = i:get_stack('ink',j)
           79  +				ink:take_item(count)
           80  +				i:set_stack('ink',j,ink)
           81  +			end
           82  +		end
           83  +
           84  +		update_disassembler(pos)
           85  +	end;
           86  +	allow_metadata_inventory_put = function(pos,list,idx,stack,user)
           87  +		local name = stack:get_name()
           88  +		if list == 'paper' then
           89  +			if name == 'default:paper' then return stack:get_count() end
           90  +		elseif list == 'ink' then
           91  +			if minetest.get_item_group(name,'dye') > 0 then return stack:get_count() end
           92  +		elseif list == 'item' then
           93  +			return stack:get_count()
           94  +		elseif list == 'output' then
           95  +			return 0
           96  +		end
           97  +		return 0
           98  +	end;
           99  +	allow_metadata_inventory_move = function(pos, fl, fi, tl, ti, count)
          100  +		if fl == 'ink' and tl == 'ink'
          101  +			then return count
          102  +			else return 0
          103  +		end
          104  +	end;
          105  +})
          106  +
          107  +minetest.register_craft {
          108  +	output = 'sorcery:disassembler';
          109  +	recipe = {
          110  +		{'group:wood','default:gold_ingot','dye:black'};
          111  +		{'sorcery:vice','screwdriver:screwdriver','xdecor:hammer'};
          112  +		{'stairs:slab_stone', 'stairs:slab_stone', 'stairs:slab_stone'};
          113  +	};
          114  +}

Modified enchanter.lua from [15ff8624ed] to [cca22cad27].

   201    201   			props[#props+1] = {
   202    202   				title = e.name;
   203    203   				desc = e.desc;
   204    204   				color = sorcery.lib.color(e.tone);
   205    205   			}
   206    206   			local inf = mat.data.slots[s.slot].interference
   207    207   			if inf then for k,v in pairs(inf) do
   208         -				interference[k] = interference[k] + v
          208  +				interference[k] = (interference[k] or 0) + v
   209    209   			end end
   210    210   		::skip::end
   211    211   		if #interference > 0 then
   212    212   			if interference.speed then stack = sorcery.data.enchants.pierce.apply(stack,-interference.speed,basecaps) end
   213    213   			if interference.durability then stack = sorcery.data.enchants.endure.apply(stack,-interference.durability,basecaps) end
   214    214   		end
   215    215   		meta = stack:get_meta() -- necessary? unclear
................................................................................
   227    227   
   228    228   minetest.register_node('sorcery:enchanter', {
   229    229   	description = 'Enchanter';
   230    230   	drawtype = 'mesh';
   231    231   	mesh = 'sorcery-enchanter.obj';
   232    232   	paramtype = 'light';
   233    233   	paramtype2 = 'facedir';
   234         -	groups = { cracky = 2, oddly_breakable_by_hand = 2 };
          234  +	groups = { cracky = 2, oddly_breakable_by_hand = 2, sorcery_magitech = 1 };
   235    235   	sunlight_propagates = true;
   236    236   	selection_box = hitbox;
   237    237   	collision_box = hitbox;
   238    238   	after_dig_node = sorcery.lib.node.purge_container;
   239    239   	tiles = {
   240    240   		"default_obsidian.png";
   241    241   		"default_steel_block.png";

Added farcaster.lua version [12914a5106].

            1  +local constants = {
            2  +	farcaster_nonlocal_cost = 0.1;
            3  +	-- the amount of power it takes to cast 50 nodes away
            4  +}
            5  +minetest.register_node('sorcery:raycaster', {
            6  +	description = 'Raycaster';
            7  +	groups = { cracky = 2; sorcery_ley_device = 1; sorcery_magitech = 1; };
            8  +	paramtype2 = 'facedir';
            9  +	tiles = {
           10  +		'sorcery_farcaster_linear_top.png';
           11  +		'sorcery_farcaster_linear_bottom.png';
           12  +		'sorcery_farcaster_linear_side.png';
           13  +	};
           14  +	_sorcery = {
           15  +		ley = {
           16  +			mode = 'consume', affinity = {'mandatic'};
           17  +			power = function(pos,delta)
           18  +				local tune = sorcery.attunement.verify(pos)
           19  +				if tune then return 0.3 else return 0 end
           20  +			end
           21  +		};
           22  +		attune = {
           23  +			class = 'sorcery:raycaster', accepts = 'sorcery:raycaster';
           24  +			source = true, target = true, reciprocal = true;
           25  +		};
           26  +		farcaster = {
           27  +			partner = function(pos)
           28  +				local tune = sorcery.attunement.verify(pos)
           29  +				print('   *!* verifying farcaster tuning',tune)
           30  +				if not tune then return nil end
           31  +				minetest.load_area(tune.partner)
           32  +				local vis = false
           33  +				local ignored
           34  +				repeat
           35  +					ignored = false
           36  +					for _,p in pairs(sorcery.lib.node.offsets.neighbors) do
           37  +						local sum = vector.add(pos,p)
           38  +						local _, stop = minetest.line_of_sight(sum,tune.partner) 
           39  +						if vector.equals(stop, tune.partner) then
           40  +							vis = true 
           41  +							break
           42  +						else
           43  +							if minetest.get_node(stop).name == 'ignore' then
           44  +								minetest.load_area(stop)
           45  +								ignored = true
           46  +							end
           47  +						end
           48  +					end
           49  +				until ignored == false
           50  +				if vis == true
           51  +					then return tune.partner
           52  +					else return nil
           53  +				end
           54  +			end;
           55  +		};
           56  +	};
           57  +})
           58  +
           59  +minetest.register_node('sorcery:farcaster', {
           60  +	description = 'Farcaster';
           61  +	paramtype2 = 'facedir';
           62  +	groups = { cracky = 2; sorcery_ley_device = 1; sorcery_magitech = 1; };
           63  +	tiles = {
           64  +		'sorcery_farcaster_nonlocal_top.png';
           65  +		'sorcery_farcaster_nonlocal_top.png';
           66  +		'sorcery_farcaster_nonlocal_side.png';
           67  +		'sorcery_farcaster_nonlocal_side.png';
           68  +		'sorcery_farcaster_nonlocal_back.png';
           69  +		'sorcery_farcaster_nonlocal_front.png';
           70  +	};
           71  +	_sorcery = {
           72  +		ley = { mode = 'consume'; affinity = {'mandatic'};
           73  +			power = function(pos,delta)
           74  +				local tune = sorcery.attunement.verify(pos)
           75  +				if not tune then
           76  +					return 0
           77  +				else
           78  +					return (vector.distance(pos,tune.partner) / 50) * constants.farcaster_nonlocal_cost
           79  +				end
           80  +			end;
           81  +		};
           82  +		attune = {
           83  +			class = 'sorcery:farcaster', accepts = 'sorcery:farcaster';
           84  +			source = true, target = true, reciprocal = true;
           85  +		};
           86  +		farcaster = {
           87  +			partner = function(pos)
           88  +				local tune = sorcery.attunement.verify(pos)
           89  +				if not tune then return nil end
           90  +
           91  +				return tune.partner
           92  +			end;
           93  +		}
           94  +	};
           95  +})
           96  +
           97  +sorcery.farcaster = {}
           98  +sorcery.farcaster.junction = function(start,minconduct)
           99  +	local stack = {{pos = start, hops = 0, route = {}}}
          100  +	local checked, network = {},{}
          101  +	local checkedp = function(pos)
          102  +		for _,v in pairs(checked) do
          103  +			if vector.equals(pos,v) then return true end
          104  +		end
          105  +		return false
          106  +	end
          107  +	local i = 1 repeat
          108  +		local caps = sorcery.ley.netcaps(stack[i].pos,1,nil,minconduct)
          109  +		network[#network+1] = {
          110  +			caps = caps;
          111  +			hops = stack[i].hops;
          112  +			route = stack[i].route;
          113  +		}
          114  +		for _,d in pairs(caps.net.devices.consume) do
          115  +			if not checkedp(d.pos) then
          116  +				checked[#checked+1] = d.pos
          117  +				local def = minetest.registered_nodes[d.id]
          118  +				if def and def._sorcery and def._sorcery.farcaster then
          119  +					local fc = def._sorcery.farcaster
          120  +					local p = fc.partner(d.pos)
          121  +					if p ~= nil and d.powerdraw >= d.minpower and not checkedp(p) then
          122  +						local nr = table.copy(stack[i].route)
          123  +						checked[#checked+1] = p
          124  +						nr[#nr+1] = d.pos
          125  +						stack[#stack+1] = {
          126  +							pos = p;
          127  +							route = nr;
          128  +							hops = stack[i].hops + 1;
          129  +						}
          130  +					else
          131  +					end
          132  +				end
          133  +			end
          134  +		end
          135  +	i = i + 1 until i > #stack
          136  +
          137  +	return network
          138  +end

Modified forcefield.lua from [4c792fc807] to [72bf5182e0].

    39     39   		maxcost = #tgts * constants.cost_per_barrier * time;
    40     40   		mincost = math.min(1,#tgts) * constants.cost_per_barrier * time;
    41     41   		targets = tgts;
    42     42   	}
    43     43   end
    44     44   for i=1,10 do
    45     45   	minetest.register_node('sorcery:air_barrier_' .. tostring(i), {
    46         -		drawtype = 'airlike';
           46  +		drawtype = 'glasslike';
    47     47   		walkable = true;
    48     48   		pointable = false;
    49     49   		sunlight_propagates = true;
    50     50   		paramtype = 'light';
    51     51   		light_source = i;
           52  +		tiles = {'sorcery_transparent.png'};
    52     53   		groups = {
           54  +			air = 1;
           55  +			sorcery_air = 1;
    53     56   			sorcery_force_barrier = i;
    54     57   		};
    55     58   		-- _proto = {
    56     59   		-- 	strength = i;
    57     60   		-- };
    58     61   		on_construct = function(pos)
    59     62   			minetest.get_node_timer(pos):start(1)
................................................................................
   102    105   end
   103    106   minetest.register_node('sorcery:emitter_barrier', {
   104    107   	description = "Barrier Screen Emitter";
   105    108   	paramtype2 = 'facedir';
   106    109   	groups = {
   107    110   		cracky = 2;
   108    111   		sorcery_ley_device = 1;
          112  +		sorcery_magitech = 1;
   109    113   	};
   110    114   	tiles = {
   111    115   		'sorcery_emitter_barrier_top.png';
   112    116   		'sorcery_emitter_barrier_bottom.png';
   113    117   		'sorcery_emitter_barrier_front.png^[transformR270';
   114    118   		'sorcery_emitter_barrier_front.png^[transformFXR90';
   115    119   		'sorcery_emitter_barrier_side.png';

Modified gems.lua from [67735ebab8] to [2f2f7ff693].

    74     74   	for _, kind in pairs { 'amplifier','rectifier','concave','convex' } do
    75     75   		local id = 'sorcery:lens_' .. kind .. '_' .. name
    76     76   		minetest.register_tool(id, {
    77     77   			inventory_image = sorcery.lib.image('sorcery_lens_overlay_gold.png'):
    78     78   				blit(sorcery.lib.image('sorcery_lens_' .. kind .. '.png'):
    79     79   					multiply(sorcery.lib.color(gem.tone):brighten(1.1))):
    80     80   				render();
    81         -			description = sorcery.lib.str.capitalize(name) .. ' ' .. kind .. ' lens';
           81  +			description = sorcery.lib.str.capitalize(name) .. ' ' .. sorcery.lib.str.capitalize(kind) .. ' Lens';
    82     82   			groups = { sorcery_enchanting_lens = 1 };
    83     83   			_proto = {
    84     84   				gem = name;
    85     85   				kind = kind;
    86     86   			};
    87     87   		})
    88     88   	end
................................................................................
   175    175   		minetest.override_item(ore, {drop = newdrops})
   176    176   		-- might be possible to just edit it in place, since we're
   177    177   		-- referring to registered_nodes anyway, but i don't want
   178    178   		-- to chance it; god knows what's going on under the hood
   179    179   	end
   180    180   end
   181    181   
   182         -if minetest.get_modpath('xdecor') then
   183         -	local og = minetest.registered_tools['xdecor:hammer'].groups
   184         -	og.crafttool = 1
   185         -	minetest.override_item('xdecor:hammer', {groups = og})
   186         -end
   187         -
   188         -minetest.register_on_craft(function(stack,crafter,recipe,grid)
   189         -	local ctoolclass = {
   190         -		[1] = 200;
   191         -		[2] = 100;
   192         -		[3] = 50;
   193         -		[4] = 10;
   194         -		[5] = 5;
   195         -	}
   196         -	for i=1,grid:get_size('craft') do
   197         -		local s = grid:get_stack('craft',i)
   198         -		local v = minetest.get_item_group(s:get_name(),'crafttool')
   199         -		if v ~= 0 then
   200         -			local dmg = 65536 / ctoolclass[v]
   201         -			local tool = recipe[i] 
   202         -			tool:add_wear(dmg)
   203         -			grid:set_stack('craft',i,tool)
   204         -		end
   205         -	end
   206         -	return nil
   207         -end)
   208    182   for g,v in pairs(sorcery.data.gems) do sorcery.register_gem(g,v) end
   209    183   
   210    184   sorcery.gem = {
   211    185   	getdrops = function(fac)
   212    186   		items = {}
   213    187   		for g,v in pairs(sorcery.data.gems) do
   214    188   			items[#items + 1] = {

Modified harvester.lua from [97dec98beb] to [40c411e2ef].

    16     16   minetest.register_node('sorcery:harvester', {
    17     17   	description = 'Harvester';
    18     18   	drawtype = 'mesh';
    19     19   	paramtype = 'light';
    20     20   	paramtype2 = 'facedir';
    21     21   	mesh = 'sorcery-harvester.obj';
    22     22   	after_dig_node = sorcery.lib.node.purge_container;
    23         -	groups = { cracky = 2; oddly_breakable_by_hand = 1; };
           23  +	groups = { cracky = 2; oddly_breakable_by_hand = 1; sorcery_magitech = 1; };
    24     24   	sunlight_propagates = true;
    25     25   	selection_box = hitbox;
    26     26   	collision_box = hitbox;
    27     27   	tiles = {
    28     28   		amethyst:render();
    29     29   		'default_copper_block.png';
    30     30   		'default_stone.png';

Modified infuser.lua from [3997cbe28f] to [b29818210a].

   203    203   		"default_stone.png",
   204    204   		"default_copper_block.png",
   205    205   		"default_steel_block.png",
   206    206   		"default_bronze_block.png",
   207    207   		"default_tin_block.png",
   208    208   	};
   209    209   	paramtype2 = 'facedir';
   210         -	groups = {cracky = 2, oddly_breakable_by_hand = 1, heavy = 1};
          210  +	groups = {
          211  +		cracky = 2, oddly_breakable_by_hand = 1, heavy = 1;
          212  +		sorcery_alchemy = 1, sorcery_magitech = 1;
          213  +	};
   211    214   	selection_box = {
   212    215   		type = 'fixed';
   213    216   		fixed = {
   214    217   			-0.37, -0.5, -0.37,
   215    218   			 0.37,  0.5,  0.37
   216    219   		};
   217    220   	};

Modified init.lua from [752c791349] to [73a80c3c4b].

    25     25   -- and load them automatically, as interdependencies
    26     26   -- exist (especially with /lib) and we need to be very
    27     27   -- careful about the order they're loaded in
    28     28   
    29     29   sorcery.unit('data') {'ui'}
    30     30   sorcery.unit('lib') {
    31     31   	-- convenience
    32         -	'str', 'node';
           32  +	'str';
    33     33   	-- serialization
    34     34   	'marshal', 'json';
    35     35   	-- data structures
    36     36   	'tbl', 'class';
    37     37   	-- wrappers
    38     38   	'color', 'image', 'ui';
           39  +	-- game
           40  +	'node';
    39     41   }
    40     42   
    41     43   sorcery.unit() { 'compat', 'matreg' }
    42     44   sorcery.unit('data') {
    43     45   	'compat';
    44     46   	'affinities'; 'gods';
    45     47   	'enchants', 'spells';
................................................................................
    47     49   	'potions', 'oils', 'greases',
    48     50   		'draughts', 'elixirs',
    49     51   		'philters', 'extracts';
    50     52   	'register';
    51     53   }
    52     54   
    53     55   for _,u in pairs {
    54         -	'ores'; 'gems';	'leylines';
           56  +	'attunement'; 'ores'; 'gems'; 'leylines';
    55     57   	'potions'; 'infuser'; 'altar'; 'wands';
    56         -	'tools'; 'enchanter'; 'harvester';
           58  +	'tools'; 'crafttools'; 'enchanter'; 'harvester';
    57     59   	'metallurgy-hot', 'metallurgy-cold';
    58     60   	'entities'; 'recipes'; 'coins';
    59     61   	'interop'; 'tnodes'; 'forcefield';
           62  +	'farcaster'; 'portal'; 'cookbook'; 'disassembly';
    60     63   } do sorcery.load(u) end

Modified leylines.lua from [8532b8e5fe] to [c6bfabb8a9].

   158    158   	minetest.register_node(id, {
   159    159   		description = 'Half-' .. b[1] .. ' Conduit';
   160    160   		paramtype2 = 'facedir';
   161    161   		groups = {
   162    162   			cracky = 2;
   163    163   			choppy = 1;
   164    164   			sorcery_ley_device = 1;
   165         -			sorcery_ley_conduit = 1;
   166    165   		};
   167    166   		_sorcery = {
   168    167   			ley = { mode = 'signal'; power = 5; }
   169    168   		};
   170    169   		tiles = tiles;
   171    170   	})
   172    171   	minetest.register_craft {
................................................................................
   207    206   			drawtype = 'nodebox';
   208    207   			groups = {
   209    208   				sorcery_ley_device = 1; snappy = 3; attached = 1;
   210    209   				sorcery_ley_cable = 1;
   211    210   			};
   212    211   			_sorcery = {
   213    212   				ley = { mode = 'signal', power = metal.conduct };
          213  +				recipe = { note = 'Conducts up to ' .. metal.conduct .. ' thaum/sec'; };
   214    214   			};
   215    215   			sunlight_propagates = true;
   216    216   			node_box = {
   217    217   				type = 'connected';
   218    218   				disconnected   = { -0.05, -0.35, -0.40; 0.05, -0.25, 0.40 };
   219    219   				connect_front  = { -0.05, -0.35, -0.50; 0.05, -0.25, 0.05 };
   220    220   				connect_back   = { -0.05, -0.35, -0.05; 0.05, -0.25, 0.50 };
................................................................................
   305    305   			'default_stone.png';
   306    306   			'default_copper_block.png';
   307    307   			emerald:render();
   308    308   		};
   309    309   		groups = {
   310    310   			cracky = 2;
   311    311   			sorcery_ley_device = 1;
          312  +			sorcery_magitech = 1;
   312    313   		};
   313    314   		on_construct = function(pos)
   314    315   			local meta = minetest.get_meta(pos)
   315    316   			meta:set_string('infotext','Condenser')
   316    317   		end;
   317    318   		_sorcery = {
   318    319   			ley = { mode = 'produce';
................................................................................
   374    375   				local sum = vector.add(pos,p)
   375    376   				if not foundp(sum) then
   376    377   					checked[#checked + 1] = sum
   377    378   					local nodename = minetest.get_node(sum).name
   378    379   					if nodename == 'ignore' then
   379    380   						minetest.load_area(sum)
   380    381   						nodename = minetest.get_node(sum).name
          382  +						print('**** ignorenode, loaded',nodename)
   381    383   					end
   382    384   					if minetest.get_item_group(nodename,'sorcery_ley_device') ~= 0
   383    385   					   or sorcery.data.compat.ley[nodename] then
   384    386   						local d = sorcery.ley.sample(pos,1,nodename,{query={mode=true}})
   385    387   						assert(d.mode == 'signal'
   386    388   						    or d.mode == 'consume'
   387    389   						    or d.mode == 'produce')
................................................................................
   485    487   	meta:set_string('sorcery:ley',sorcery.ley.encode(l))
   486    488   end
   487    489   
   488    490   sorcery.ley.sample = function(pos,timespan,name,flags)
   489    491   	-- returns how much ley-force can be transmitted by a
   490    492   	-- device over timespan
   491    493   	local ret = {}
          494  +	minetest.load_area(pos)
   492    495   	name = name or minetest.get_node(pos).name
   493    496   	flags = flags or {}
   494    497   	flags.query = flags.query or {
   495    498   		mode = true; power = true; affinity = true;
   496    499   		minpower = true; maxpower = true;
   497    500   	}
   498    501   	local props = minetest.registered_nodes[name]._sorcery
................................................................................
   561    564   	if ret.power then
   562    565   		if flags.query.minpower and not ret.minpower then ret.minpower = power end
   563    566   		if flags.query.maxpower and not ret.maxpower then ret.maxpower = power end
   564    567   	end
   565    568   	return ret
   566    569   end
   567    570   
   568         -sorcery.ley.netcaps = function(pos,timespan,exclude)
   569         -	local net = sorcery.ley.mapnet(pos)
          571  +sorcery.ley.netcaps = function(pos,timespan,exclude,minconduct)
          572  +	local net = sorcery.ley.mapnet(pos,minconduct)
   570    573   	local maxpower = 0
   571    574   	local freepower = 0
   572    575   	local affs,usedaffs = {},{}
   573    576   	local flexpowerdevs = {}
   574    577   	local devself
   575    578   	for _,n in pairs(net.devices.produce) do
   576    579   		if vector.equals(pos,n.pos) then devself = n end

Modified lib/node.lua from [a0d38cfe10] to [ea0569acf8].

            1  +local ofs = {
            2  +	neighbors = {
            3  +		{x =  1, y =  0, z =  0};
            4  +		{x = -1, y =  0, z =  0};
            5  +		{x =  0, y =  1, z =  0};
            6  +		{x =  0, y = -1, z =  0};
            7  +		{x =  0, y =  0, z =  1};
            8  +		{x =  0, y =  0, z = -1};
            9  +	};
           10  +	planecorners = {
           11  +		{x =  1, y =  0, z =  1};
           12  +		{x = -1, y =  0, z =  1};
           13  +		{x = -1, y =  0, z = -1};
           14  +		{x =  1, y =  0, z = -1};
           15  +
           16  +		{x =  1, y =  1, z =  0};
           17  +		{x = -1, y =  1, z =  0};
           18  +		{x = -1, y = -1, z =  0};
           19  +		{x =  1, y = -1, z =  0};
           20  +	};
           21  +	cubecorners = {
           22  +		{x =  1, y =  1, z =  1};
           23  +		{x = -1, y =  1, z =  1};
           24  +		{x = -1, y = -1, z =  1};
           25  +		{x = -1, y = -1, z = -1};
           26  +		{x =  1, y = -1, z = -1};
           27  +		{x =  1, y =  1, z = -1};
           28  +		{x =  1, y = -1, z =  1};
           29  +		{x = -1, y =  1, z = -1};
           30  +	};
           31  +	nextto = {
           32  +		{x =  1, y =  0, z =  0};
           33  +		{x = -1, y =  0, z =  0};
           34  +		{x =  0, y =  0, z =  1};
           35  +		{x =  0, y =  0, z = -1};
           36  +	};
           37  +}
           38  +
           39  +ofs.adjoining = sorcery.lib.tbl.append(sorcery.lib.tbl.append(
           40  +	ofs.neighbors,ofs.planecorners),ofs.cubecorners)
           41  +
     1     42   return {
           43  +	offsets = ofs;
     2     44   	purge_container = function(pos,node,meta,user)
     3     45   		local offset = function(pos,range)
     4     46   			local r = function(min,max)
     5     47   				return (math.random() * (max - min)) + min
     6     48   			end
     7     49   			return {
     8     50   				x = pos.x + r(0 - range, range);
................................................................................
    14     56   			for _, item in pairs(inv) do
    15     57   				if not item:is_empty() then
    16     58   					minetest.add_item(offset(pos,0.4), item)
    17     59   				end
    18     60   			end
    19     61   		end
    20     62   	end;
           63  +
           64  +	amass = function(startpoint,names,directions)
           65  +		if not directions then directions = ofs.neighbors end
           66  +		local nodes, positions, checked = {},{},{}
           67  +		local checkedp = function(pos)
           68  +			for _,v in pairs(checked) do
           69  +				if vector.equals(pos,v) then return true end
           70  +			end
           71  +			return false
           72  +		end
           73  +		local i,stack = 1,{startpoint} repeat
           74  +			local pos = stack[i]
           75  +			local n = minetest.get_node(pos).name
           76  +			if sorcery.lib.tbl.has(names, n) then -- match found
           77  +				-- record the find
           78  +				nodes[pos] = n
           79  +				if positions[n] then positions[n][#positions[n]] = pos
           80  +				else positions[n] = {pos} end
           81  +
           82  +				-- check selected neighbors to see if any need scanning
           83  +				for _,d in pairs(directions) do
           84  +					local sum = vector.add(pos, d)
           85  +					if not checkedp(sum) then
           86  +						stack[#stack + 1] = sum
           87  +					end
           88  +				end
           89  +			end
           90  +			checked[#checked+1] = pos
           91  +			i = i + 1
           92  +		until i > #stack
           93  +		return nodes, positions
           94  +	end;
    21     95   }

Modified lib/tbl.lua from [99c5f4dbba] to [5997708826].

     1      1   local fn = {}
            2  +
            3  +fn.shuffle = function(list)
            4  +	for i = #list, 2, -1 do
            5  +		local j = math.random(i)
            6  +		list[i], list[j] = list[j], list[i]
            7  +	end
            8  +end
            9  +
           10  +fn.scramble = function(list)
           11  +	local new = table.copy(list)
           12  +	fn.shuffle(new)
           13  +	return new
           14  +end
     2     15   
     3     16   fn.copy = function(t)
     4     17   	local new = {}
     5     18   	for i,v in pairs(t) do new[i] = v end
     6     19   	setmetatable(new,getmetatable(t))
     7     20   	return new
     8     21   end

Modified metallurgy-cold.lua from [c1d9a4ce4b] to [3d415e629d].

   107    107   			metal = mat
   108    108   		end
   109    109   	end
   110    110   	local mp = item:get_definition()._matprop
   111    111   		or sorcery.data.compat.grindables[item:get_name()]
   112    112   		or {}
   113    113   
   114         -	again = true
   115    114   	if metal then mp = {
   116    115   		hardness = mp.hardness or metal.data.hardness;
   117    116   		grindvalue = ((mp.grindvalue or metal.value) or (metal and constants.metal_grindvalue));
   118    117   		powder = mp.powder or metal.data.parts.powder;
   119    118   		grindcost = mp.grindcost or constants.metal_grindcost; -- invariant for metal
   120    119   	} end
   121    120   
................................................................................
   136    135   	return mp
   137    136   end
   138    137   minetest.register_node('sorcery:mill',{
   139    138   	description = 'Mill';
   140    139   	groups = {
   141    140   		cracky = 2;
   142    141   		sorcery_ley_device = 1;
          142  +		sorcery_metallurgy = 1;
   143    143   	};
   144    144   	paramtype2 = 'facedir';
   145    145   	after_dig_node = sorcery.lib.node.purge_container;
   146    146   	on_construct = function(pos)
   147    147   		local meta = minetest.get_meta(pos)
   148    148   		local inv = meta:get_inventory()
   149    149   		inv:set_size('input',1)
................................................................................
   333    333   }
   334    334   for name,metal in pairs(sorcery.data.metals) do
   335    335   	local i,f = metal.parts.ingot, metal.parts.fragment
   336    336   	local id = 'sorcery:mill_grindhead_' .. name
   337    337   	minetest.register_tool(id,{
   338    338   		description = sorcery.lib.str.capitalize(name) .. ' Grinding Head';
   339    339   		inventory_image = sorcery.lib.image('sorcery_mill_grindhead.png'):multiply(sorcery.lib.color(metal.tone)):render();
   340         -		groups = { sorcery_mill_grindhead = 1 };
          340  +		groups = { sorcery_mill_grindhead = 1, sorcery_metallurgy = 1 };
   341    341   		_proto = {
   342    342   			metal = name;
   343    343   		};
   344    344   	});
   345    345   	minetest.register_craft {
   346    346   		output = id;
   347    347   		recipe = {
   348    348   			{f,i,f};
   349    349   			{i,'',i};
   350    350   			{f,i,f};
   351    351   		};
   352    352   	}
   353    353   end

Modified metallurgy-hot.lua from [45fd80ebe6] to [222da491b8].

    22     22   
    23     23   local fragments_per_ingot = 4
    24     24   
    25     25   for _, c in pairs { 'clay', 'aluminum', 'platinum', 'duranium' } do
    26     26   	minetest.register_craftitem('sorcery:crucible_' .. c, {
    27     27   		description = sorcery.lib.str.capitalize(c .. ' crucible');
    28     28   		inventory_image = 'sorcery_crucible_' .. c .. '.png';
           29  +		groups = { sorcery_metallurgy = 1; }
    29     30   	})
    30     31   end
    31     32   
    32     33   minetest.register_craftitem('sorcery:crucible_clay_molding', {
    33     34   	description = sorcery.lib.str.capitalize('Crucible molding');
    34     35   	inventory_image = 'sorcery_crucible_clay_molding.png';
           36  +	groups = { sorcery_metallurgy = 1; }
    35     37   })
    36     38   
    37     39   minetest.register_craft {
    38     40   	recipe = {
    39     41   		{ 'default:clay_lump', '', 'default:clay_lump'};
    40     42   		{ 'default:clay_lump', '', 'default:clay_lump'};
    41     43   		{ 'default:clay_lump', 'default:clay_lump', 'default:clay_lump'};
................................................................................
   299    301   			description = desc;
   300    302   			drawtype = "mesh";
   301    303   			after_dig_node = sorcery.lib.node.purge_container;
   302    304   			mesh = 'sorcery-kiln-' .. state .. '.obj';
   303    305   			drop = id;
   304    306   			groups = {
   305    307   				cracky = (state == 'open' and 2) or nil;
          308  +				sorcery_metallurgy = 1;
   306    309   			};
   307    310   			sunlight_propagates = true;
   308    311   			paramtype1 = 'light';
   309    312   			paramtype2 = 'facedir';
   310    313   			selection_box = box[state];
   311    314   			collision_box = box[state];
   312    315   			tiles = tex[state];
................................................................................
   380    383   		minetest.register_node((active and id .. '_active') or id, {
   381    384   			_proto = kind;
   382    385   			description = desc;
   383    386   			drop = id;
   384    387   			after_dig_node = sorcery.lib.node.purge_container;
   385    388   			groups = {
   386    389   				cracky = (active and 2) or nil;
          390  +				sorcery_metallurgy = 1;
   387    391   			};
   388    392   			paramtype2 = 'facedir';
   389    393   			light_source = (active and 9) or 0;
   390    394   			on_construct = function(pos)
   391    395   				local meta = minetest.get_meta(pos)
   392    396   				local inv = meta:get_inventory()
   393    397   				inv:set_size('input',kind.size)

Added models/sorcery-disassembler.obj version [bc7345c28d].

            1  +# Blender v2.82 (sub 7) OBJ File: 'disassembler.blend'
            2  +# www.blender.org
            3  +mtllib sorcery-disassembler.mtl
            4  +o screwdriver.001_Cube.009
            5  +v 0.043647 -0.410865 0.263791
            6  +v -0.235855 -0.208462 0.264985
            7  +v 0.042206 -0.413038 0.294867
            8  +v -0.237295 -0.210634 0.296060
            9  +v 0.032923 -0.425665 0.262260
           10  +v -0.246578 -0.223261 0.263453
           11  +v 0.031483 -0.427837 0.293335
           12  +v -0.248019 -0.225433 0.294529
           13  +v -0.069214 -0.329136 0.264273
           14  +v -0.070654 -0.331309 0.295349
           15  +v -0.081378 -0.346108 0.293817
           16  +v -0.079937 -0.343936 0.262742
           17  +v 0.303506 -0.237945 -0.358781
           18  +v 0.303506 -0.207010 -0.358781
           19  +v 0.379922 -0.237945 -0.125462
           20  +v 0.379922 -0.207010 -0.125462
           21  +v 0.274108 -0.237945 -0.349152
           22  +v 0.274108 -0.207010 -0.349152
           23  +v 0.350524 -0.237945 -0.115833
           24  +v 0.350524 -0.207010 -0.115833
           25  +v 0.370843 -0.237945 -0.153184
           26  +v 0.312586 -0.237945 -0.331059
           27  +v 0.312586 -0.207010 -0.331059
           28  +v 0.370843 -0.207010 -0.153184
           29  +v 0.283187 -0.237945 -0.321430
           30  +v 0.341444 -0.237945 -0.143555
           31  +v 0.341444 -0.207010 -0.143555
           32  +v 0.283187 -0.207010 -0.321430
           33  +v 0.339948 -0.266738 -0.340020
           34  +v 0.330869 -0.266738 -0.367742
           35  +v 0.330869 -0.178217 -0.367742
           36  +v 0.398205 -0.178217 -0.162145
           37  +v 0.407285 -0.178217 -0.134424
           38  +v 0.407285 -0.266738 -0.134424
           39  +v 0.323161 -0.266738 -0.106872
           40  +v 0.323161 -0.178217 -0.106872
           41  +v 0.314081 -0.266738 -0.134594
           42  +v 0.255825 -0.178217 -0.312469
           43  +v 0.246745 -0.178217 -0.340191
           44  +v 0.246745 -0.266738 -0.340191
           45  +v 0.398205 -0.266738 -0.162146
           46  +v 0.339948 -0.178217 -0.340020
           47  +v 0.255825 -0.266738 -0.312469
           48  +v 0.314081 -0.178217 -0.134594
           49  +v 0.297486 -0.237945 -0.377162
           50  +v 0.297486 -0.207010 -0.377162
           51  +v 0.385942 -0.207010 -0.107080
           52  +v 0.385942 -0.237945 -0.107080
           53  +v 0.356544 -0.237945 -0.097452
           54  +v 0.356544 -0.207010 -0.097452
           55  +v 0.268088 -0.207010 -0.367534
           56  +v 0.268088 -0.237945 -0.367534
           57  +v 0.288658 -0.237945 -0.404117
           58  +v 0.288658 -0.207010 -0.404117
           59  +v 0.259260 -0.207010 -0.394488
           60  +v 0.259260 -0.237945 -0.394488
           61  +v 0.288658 -0.316916 -0.404117
           62  +v 0.297486 -0.316916 -0.377162
           63  +v 0.259260 -0.316916 -0.394488
           64  +v 0.268088 -0.316916 -0.367534
           65  +v 0.251861 -0.207010 -0.417080
           66  +v 0.281259 -0.207010 -0.426708
           67  +v 0.281259 -0.237945 -0.426708
           68  +v 0.251861 -0.237945 -0.417080
           69  +v 0.379922 -0.237945 -0.125462
           70  +v 0.379922 -0.207010 -0.125462
           71  +v 0.303506 -0.237945 -0.358781
           72  +v 0.303506 -0.207010 -0.358781
           73  +v 0.350523 -0.237945 -0.115833
           74  +v 0.350523 -0.207010 -0.115833
           75  +v 0.274108 -0.237945 -0.349152
           76  +v 0.274108 -0.207010 -0.349152
           77  +v 0.312586 -0.237945 -0.331059
           78  +v 0.370843 -0.237945 -0.153184
           79  +v 0.370843 -0.207010 -0.153184
           80  +v 0.312586 -0.207010 -0.331059
           81  +v 0.341444 -0.237945 -0.143555
           82  +v 0.283187 -0.237945 -0.321430
           83  +v 0.283187 -0.207010 -0.321430
           84  +v 0.341444 -0.207010 -0.143555
           85  +v 0.398205 -0.266738 -0.162146
           86  +v 0.407285 -0.266738 -0.134424
           87  +v 0.407285 -0.178217 -0.134424
           88  +v 0.339948 -0.178217 -0.340020
           89  +v 0.330869 -0.178217 -0.367742
           90  +v 0.330869 -0.266738 -0.367742
           91  +v 0.246745 -0.266738 -0.340191
           92  +v 0.246745 -0.178217 -0.340191
           93  +v 0.255825 -0.266738 -0.312469
           94  +v 0.314081 -0.178217 -0.134594
           95  +v 0.323161 -0.178217 -0.106872
           96  +v 0.323161 -0.266738 -0.106872
           97  +v 0.339948 -0.266738 -0.340020
           98  +v 0.398205 -0.178217 -0.162146
           99  +v 0.314081 -0.266738 -0.134594
          100  +v 0.255825 -0.178217 -0.312469
          101  +v 0.385942 -0.237945 -0.107080
          102  +v 0.385942 -0.207010 -0.107080
          103  +v 0.297486 -0.207010 -0.377162
          104  +v 0.297486 -0.237945 -0.377162
          105  +v 0.268088 -0.237945 -0.367534
          106  +v 0.268088 -0.207010 -0.367534
          107  +v 0.356544 -0.207010 -0.097452
          108  +v 0.356544 -0.237945 -0.097452
          109  +v 0.341714 -0.237945 -0.242121
          110  +v 0.341714 -0.207010 -0.242121
          111  +v 0.312316 -0.237945 -0.232493
          112  +v 0.312316 -0.207010 -0.232493
          113  +v 0.394770 -0.237945 -0.080126
          114  +v 0.394770 -0.207010 -0.080126
          115  +v 0.365372 -0.207010 -0.070497
          116  +v 0.365372 -0.237945 -0.070497
          117  +v 0.394770 -0.316916 -0.080126
          118  +v 0.385942 -0.316916 -0.107080
          119  +v 0.365372 -0.316916 -0.070497
          120  +v 0.356544 -0.316916 -0.097452
          121  +v 0.372771 -0.207010 -0.047906
          122  +v 0.402169 -0.207010 -0.057534
          123  +v 0.402169 -0.237945 -0.057534
          124  +v 0.372771 -0.237945 -0.047906
          125  +vt 0.424217 -0.000000
          126  +vt 0.424217 1.000000
          127  +vt 0.575783 1.000000
          128  +vt 0.575783 -0.000000
          129  +vt 0.455431 -0.000000
          130  +vt 0.455431 1.000000
          131  +vt 0.544569 1.000000
          132  +vt 0.544569 -0.000000
          133  +vt 0.575783 -0.000000
          134  +vt 0.575783 1.000000
          135  +vt 0.424217 1.000000
          136  +vt 0.424217 -0.000000
          137  +vt 0.544569 -0.000000
          138  +vt 0.544569 1.000000
          139  +vt 0.455431 1.000000
          140  +vt 0.455431 -0.000000
          141  +vt 0.125000 0.500000
          142  +vt 0.375000 0.500000
          143  +vt 0.375000 0.750000
          144  +vt 0.125000 0.750000
          145  +vt 12.373487 1.325346
          146  +vt 12.594831 1.037083
          147  +vt 13.358246 1.748821
          148  +vt 13.136902 2.037083
          149  +vt 0.420366 0.453243
          150  +vt 0.420366 0.612510
          151  +vt 0.272130 0.760747
          152  +vt 0.272130 0.305006
          153  +vt 0.420366 0.453243
          154  +vt 0.579633 0.453243
          155  +vt 0.727871 0.305006
          156  +vt 0.272130 0.305006
          157  +vt 0.271175 0.453243
          158  +vt 0.417201 0.453243
          159  +vt 0.417201 0.046672
          160  +vt 0.271175 0.046672
          161  +vt 0.579633 0.612510
          162  +vt 0.420366 0.612510
          163  +vt 0.272130 0.760747
          164  +vt 0.727871 0.760747
          165  +vt 0.579633 1.148786
          166  +vt 0.420366 1.148786
          167  +vt 0.420366 0.666967
          168  +vt 0.579633 0.666967
          169  +vt 0.417201 0.453243
          170  +vt 0.271175 0.453243
          171  +vt 0.271175 0.046672
          172  +vt 0.417201 0.046672
          173  +vt 0.420366 1.148786
          174  +vt 0.579633 1.148786
          175  +vt 0.579633 0.666967
          176  +vt 0.420366 0.666967
          177  +vt 1.148786 0.453243
          178  +vt 1.148786 0.612510
          179  +vt 0.666967 0.612510
          180  +vt 0.666967 0.453243
          181  +vt 0.420366 0.453243
          182  +vt 0.579633 0.453243
          183  +vt 0.579633 0.046672
          184  +vt 0.420366 0.046672
          185  +vt 0.417201 0.612510
          186  +vt 0.271175 0.612510
          187  +vt 0.666967 0.305006
          188  +vt 0.666967 0.760747
          189  +vt 0.516783 0.760747
          190  +vt 0.516783 0.305006
          191  +vt 0.272130 0.666967
          192  +vt 0.727871 0.666967
          193  +vt 0.727871 0.516783
          194  +vt 0.272130 0.516783
          195  +vt 0.727871 0.666967
          196  +vt 0.272130 0.666967
          197  +vt 0.272130 0.516783
          198  +vt 0.727871 0.516783
          199  +vt 0.579633 0.453243
          200  +vt 0.420366 0.453243
          201  +vt 0.420366 0.046672
          202  +vt 0.579633 0.046672
          203  +vt 0.417201 0.612510
          204  +vt 0.271175 0.612510
          205  +vt 0.516783 0.305006
          206  +vt 0.516783 0.760747
          207  +vt 0.666967 0.760747
          208  +vt 0.666967 0.305006
          209  +vt 0.579633 0.612510
          210  +vt 0.579633 0.453243
          211  +vt 0.727871 0.305006
          212  +vt 0.727871 0.760747
          213  +vt 0.420366 0.271175
          214  +vt 0.579633 0.271175
          215  +vt 0.579633 0.148786
          216  +vt 0.420366 0.148786
          217  +vt 0.579633 0.417201
          218  +vt 0.420366 0.417201
          219  +vt 0.420366 0.271175
          220  +vt 0.579633 0.271175
          221  +vt 0.579633 0.516783
          222  +vt 0.420366 0.516783
          223  +vt 0.516783 0.453243
          224  +vt 0.516783 0.612510
          225  +vt 0.516783 0.612510
          226  +vt 0.516783 0.453243
          227  +vt 0.420366 0.516783
          228  +vt 0.579633 0.516783
          229  +vt 0.579633 0.417201
          230  +vt 0.420366 0.417201
          231  +vt 0.666967 0.453243
          232  +vt 0.666967 0.612510
          233  +vt 1.148786 0.612510
          234  +vt 1.148786 0.453243
          235  +vt 0.579633 0.453243
          236  +vt 0.579633 0.612510
          237  +vt 0.420366 0.612510
          238  +vt 0.420366 0.453243
          239  +vt 0.148786 0.453243
          240  +vt 0.148786 0.612510
          241  +vt 0.148786 0.612510
          242  +vt 0.148786 0.453243
          243  +vt 0.420366 0.148786
          244  +vt 0.579633 0.148786
          245  +vt 0.420366 0.453243
          246  +vt 0.272130 0.305006
          247  +vt 0.272130 0.760747
          248  +vt 0.420366 0.612510
          249  +vt 0.420366 0.453243
          250  +vt 0.272130 0.305006
          251  +vt 0.727871 0.305006
          252  +vt 0.579633 0.453243
          253  +vt 0.271175 0.453243
          254  +vt 0.271175 0.046672
          255  +vt 0.417201 0.046672
          256  +vt 0.417201 0.453243
          257  +vt 0.579633 0.612510
          258  +vt 0.727871 0.760747
          259  +vt 0.272130 0.760747
          260  +vt 0.420366 0.612510
          261  +vt 0.579633 0.666967
          262  +vt 0.420366 0.666967
          263  +vt 0.417201 0.453243
          264  +vt 0.417201 0.046672
          265  +vt 0.271175 0.046672
          266  +vt 0.271175 0.453243
          267  +vt 0.420366 0.666967
          268  +vt 0.579633 0.666967
          269  +vt 0.666967 0.453243
          270  +vt 0.666967 0.612510
          271  +vt 0.420366 0.453243
          272  +vt 0.420366 0.046672
          273  +vt 0.579633 0.046672
          274  +vt 0.579633 0.453243
          275  +vt 0.417201 0.612510
          276  +vt 0.271175 0.612510
          277  +vt 0.666967 0.305006
          278  +vt 0.516783 0.305006
          279  +vt 0.516783 0.760747
          280  +vt 0.666967 0.760747
          281  +vt 0.272130 0.666967
          282  +vt 0.272130 0.516783
          283  +vt 0.727871 0.516783
          284  +vt 0.727871 0.666967
          285  +vt 0.727871 0.666967
          286  +vt 0.727871 0.516783
          287  +vt 0.272130 0.516783
          288  +vt 0.272130 0.666967
          289  +vt 0.579633 0.453243
          290  +vt 0.579633 0.046672
          291  +vt 0.420366 0.046672
          292  +vt 0.420366 0.453243
          293  +vt 0.271175 0.612510
          294  +vt 0.417201 0.612510
          295  +vt 0.516783 0.305006
          296  +vt 0.666967 0.305006
          297  +vt 0.666967 0.760747
          298  +vt 0.516783 0.760747
          299  +vt 0.579633 0.612510
          300  +vt 0.727871 0.760747
          301  +vt 0.727871 0.305006
          302  +vt 0.579633 0.453243
          303  +vt 0.420366 0.271175
          304  +vt 0.420366 0.148786
          305  +vt 0.579633 0.148786
          306  +vt 0.579633 0.271175
          307  +vt 0.579633 0.417201
          308  +vt 0.579633 0.271175
          309  +vt 0.420366 0.271175
          310  +vt 0.420366 0.417201
          311  +vt 0.579633 0.516783
          312  +vt 0.420366 0.516783
          313  +vt 0.516783 0.453243
          314  +vt 0.516783 0.612510
          315  +vt 0.516783 0.612510
          316  +vt 0.516783 0.453243
          317  +vt 0.420366 0.516783
          318  +vt 0.420366 0.417201
          319  +vt 0.579633 0.417201
          320  +vt 0.579633 0.516783
          321  +vt 0.666967 0.453243
          322  +vt 0.666967 0.612510
          323  +vt 0.579633 0.453243
          324  +vt 0.420366 0.453243
          325  +vt 0.420366 0.612510
          326  +vt 0.579633 0.612510
          327  +vt 0.148786 0.612510
          328  +vt 0.148786 0.453243
          329  +vt 0.148786 0.453243
          330  +vt 0.148786 0.612510
          331  +vt 0.579633 0.148786
          332  +vt 0.420366 0.148786
          333  +vt -3.590328 3.610900
          334  +vt -3.901390 2.979239
          335  +vt -4.590328 3.318507
          336  +vt -4.279266 3.950168
          337  +vt -7.329282 -3.981636
          338  +vt -8.018219 -3.642368
          339  +vt -7.707157 -3.010707
          340  +vt -7.018219 -3.349975
          341  +vn 0.5847 0.8069 0.0835
          342  +vn -0.0462 -0.0697 0.9965
          343  +vn -0.5847 -0.8069 -0.0835
          344  +vn 0.0462 0.0697 -0.9965
          345  +vn 0.8099 -0.5865 -0.0035
          346  +vn -0.8099 0.5865 0.0035
          347  +vn -0.3112 0.0000 -0.9503
          348  +vn 0.3112 0.0000 0.9503
          349  +vn 0.9503 0.0000 -0.3112
          350  +vn 0.0000 1.0000 0.0000
          351  +vn -0.9503 0.0000 0.3112
          352  +vn 0.0000 -1.0000 -0.0000
          353  +g screwdriver.001_Cube.009_copper
          354  +usemtl copper
          355  +s off
          356  +f 9/1/1 2/2/1 4/3/1 10/4/1
          357  +f 10/5/2 4/6/2 8/7/2 11/8/2
          358  +f 11/9/3 8/10/3 6/11/3 12/12/3
          359  +f 12/13/4 6/14/4 2/15/4 9/16/4
          360  +f 3/17/5 7/18/5 5/19/5 1/20/5
          361  +f 2/21/6 6/22/6 8/23/6 4/24/6
          362  +f 13/25/7 14/26/7 31/27/7 30/28/7
          363  +f 22/29/8 25/30/8 43/31/8 29/32/8
          364  +f 53/33/9 45/34/9 58/35/9 57/36/9
          365  +f 28/37/8 23/38/8 42/39/8 38/40/8
          366  +f 108/41/10 106/42/10 23/43/10 28/44/10
          367  +f 52/45/11 56/46/11 59/47/11 60/48/11
          368  +f 105/49/12 107/50/12 25/51/12 22/52/12
          369  +f 107/53/11 108/54/11 28/55/11 25/56/11
          370  +f 45/57/8 52/58/8 60/59/8 58/60/8
          371  +f 46/61/9 45/34/9 53/33/9 54/62/9
          372  +f 43/63/11 38/64/11 39/65/11 40/66/11
          373  +f 29/67/12 43/68/12 40/69/12 30/70/12
          374  +f 38/71/10 42/72/10 31/73/10 39/74/10
          375  +f 56/75/7 53/76/7 57/77/7 59/78/7
          376  +f 52/45/11 51/79/11 55/80/11 56/46/11
          377  +f 30/81/9 31/82/9 42/83/9 29/84/9
          378  +f 18/85/7 17/86/7 40/87/7 39/88/7
          379  +f 17/86/7 13/25/7 30/28/7 40/87/7
          380  +f 25/30/8 28/37/8 38/40/8 43/31/8
          381  +f 14/26/7 18/85/7 39/88/7 31/27/7
          382  +f 23/38/8 22/29/8 29/32/8 42/39/8
          383  +f 53/89/12 56/90/12 64/91/12 63/92/12
          384  +f 51/93/10 46/94/10 54/95/10 55/96/10
          385  +f 18/97/10 14/98/10 46/94/10 51/93/10
          386  +f 17/99/11 18/100/11 51/79/11 52/45/11
          387  +f 14/101/9 13/102/9 45/34/9 46/61/9
          388  +f 13/103/12 17/104/12 52/105/12 45/106/12
          389  +f 22/107/9 23/108/9 106/109/9 105/110/9
          390  +f 64/111/7 61/112/7 62/113/7 63/114/7
          391  +f 54/62/9 53/33/9 63/115/9 62/116/9
          392  +f 56/46/11 55/80/11 61/117/11 64/118/11
          393  +f 55/96/10 54/95/10 62/119/10 61/120/10
          394  +f 65/121/8 82/122/8 83/123/8 66/124/8
          395  +f 74/125/7 81/126/7 95/127/7 77/128/7
          396  +f 109/129/9 113/130/9 114/131/9 97/132/9
          397  +f 80/133/7 90/134/7 94/135/7 75/136/7
          398  +f 108/41/10 80/137/10 75/138/10 106/42/10
          399  +f 104/139/11 116/140/11 115/141/11 112/142/11
          400  +f 105/49/12 74/143/12 77/144/12 107/50/12
          401  +f 107/53/11 77/145/11 80/146/11 108/54/11
          402  +f 97/147/7 114/148/7 116/149/7 104/150/7
          403  +f 98/151/9 110/152/9 109/129/9 97/132/9
          404  +f 95/153/11 92/154/11 91/155/11 90/156/11
          405  +f 81/157/12 82/158/12 92/159/12 95/160/12
          406  +f 90/161/10 91/162/10 83/163/10 94/164/10
          407  +f 112/165/8 115/166/8 113/167/8 109/168/8
          408  +f 104/139/11 112/142/11 111/169/11 103/170/11
          409  +f 82/171/9 81/172/9 94/173/9 83/174/9
          410  +f 70/175/8 91/176/8 92/177/8 69/178/8
          411  +f 69/178/8 92/177/8 82/122/8 65/121/8
          412  +f 77/128/7 95/127/7 90/134/7 80/133/7
          413  +f 66/124/8 83/123/8 91/176/8 70/175/8
          414  +f 75/136/7 94/135/7 81/126/7 74/125/7
          415  +f 109/179/12 119/180/12 120/181/12 112/182/12
          416  +f 103/183/10 111/184/10 110/185/10 98/186/10
          417  +f 70/187/10 103/183/10 98/186/10 66/188/10
          418  +f 69/189/11 104/139/11 103/170/11 70/190/11
          419  +f 66/191/9 98/151/9 97/132/9 65/192/9
          420  +f 65/193/12 97/194/12 104/195/12 69/196/12
          421  +f 74/197/9 105/110/9 106/109/9 75/198/9
          422  +f 120/199/8 119/200/8 118/201/8 117/202/8
          423  +f 110/152/9 118/203/9 119/204/9 109/129/9
          424  +f 112/142/11 120/205/11 117/206/11 111/169/11
          425  +f 111/184/10 117/207/10 118/208/10 110/185/10
          426  +f 12/12/5 9/1/5 10/5/5 11/9/5
          427  +f 115/209/12 116/210/12 114/211/12 113/212/12
          428  +f 59/213/12 57/214/12 58/215/12 60/216/12
          429  +o screwdriver.002_Cube.014
          430  +v 0.001121 -0.421942 -0.279823
          431  +v 0.001121 -0.376060 -0.279823
          432  +v 0.163420 -0.421942 -0.113813
          433  +v 0.163420 -0.376060 -0.113813
          434  +v -0.031688 -0.421942 -0.247749
          435  +v -0.031688 -0.376060 -0.247749
          436  +v 0.130612 -0.421942 -0.081738
          437  +v 0.130612 -0.376060 -0.081738
          438  +v 0.500000 -0.426985 0.500000
          439  +v 0.074306 -0.426985 0.500000
          440  +v 0.500000 -0.426985 0.103149
          441  +v 0.074306 -0.426985 0.103149
          442  +v 0.500000 -0.225107 0.103149
          443  +v 0.500000 -0.225107 0.500000
          444  +v 0.074306 -0.225107 0.500000
          445  +v 0.074306 -0.225107 0.103149
          446  +v 0.500000 -0.225107 0.301574
          447  +v 0.074306 -0.225107 0.301574
          448  +v 0.500000 -0.077495 0.301574
          449  +v 0.500000 -0.077495 0.500000
          450  +v 0.074306 -0.077495 0.500000
          451  +v 0.074306 -0.077495 0.301574
          452  +v 0.099049 -0.225107 0.276863
          453  +v 0.099049 -0.225107 0.127860
          454  +v 0.475257 -0.225107 0.127860
          455  +v 0.475257 -0.225107 0.276863
          456  +v 0.099049 -0.403485 0.276863
          457  +v 0.099049 -0.403485 0.127860
          458  +v 0.475257 -0.403485 0.127860
          459  +v 0.475257 -0.403485 0.276863
          460  +v 0.474281 -0.077495 0.327183
          461  +v 0.474281 -0.077495 0.474391
          462  +v 0.100026 -0.077495 0.474391
          463  +v 0.100025 -0.077495 0.327183
          464  +v 0.474281 -0.403355 0.327183
          465  +v 0.474281 -0.403355 0.474391
          466  +v 0.100026 -0.403355 0.474391
          467  +v 0.100025 -0.403355 0.327183
          468  +v -0.347737 -0.288676 -0.035482
          469  +v -0.347737 -0.343523 -0.021635
          470  +v -0.283226 -0.343523 -0.021635
          471  +v -0.283226 -0.288676 -0.035482
          472  +v -0.347737 -0.371696 -0.364314
          473  +v -0.347737 -0.426543 -0.350466
          474  +v -0.283226 -0.426543 -0.350466
          475  +v -0.283226 -0.371696 -0.364314
          476  +v 0.042940 -0.412040 0.297443
          477  +v 0.044608 -0.409524 0.261457
          478  +v -0.069920 -0.330311 0.297925
          479  +v 0.030522 -0.429178 0.295669
          480  +v -0.082339 -0.347449 0.296151
          481  +v 0.032190 -0.426662 0.259683
          482  +v -0.080671 -0.344933 0.260165
          483  +v -0.068252 -0.327795 0.261939
          484  +vt 0.000000 0.401186
          485  +vt 0.000000 0.598814
          486  +vt 1.000000 0.598814
          487  +vt 1.000000 0.401186
          488  +vt 1.000000 0.401186
          489  +vt 1.000000 0.598814
          490  +vt 0.000000 0.598814
          491  +vt 0.000000 0.401186
          492  +vt 0.401186 1.000000
          493  +vt 0.598814 1.000000
          494  +vt 0.598814 0.000000
          495  +vt 0.401186 0.000000
          496  +vt 0.598814 1.000000
          497  +vt 0.401186 1.000000
          498  +vt 0.401186 0.000000
          499  +vt 0.598814 0.000000
          500  +vt -0.603816 -2.866437
          501  +vt -0.603816 -1.866437
          502  +vt 0.396184 -1.866437
          503  +vt 0.396184 -2.866437
          504  +vt -3.780913 -8.696232
          505  +vt -2.780914 -8.696232
          506  +vt -2.780914 -7.696233
          507  +vt -3.780913 -7.696233
          508  +vt 0.069733 0.070792
          509  +vt 1.001979 0.070792
          510  +vt 1.001979 0.545024
          511  +vt 0.535856 0.545024
          512  +vt 0.069733 0.545024
          513  +vt 0.535856 0.545024
          514  +vt 0.069733 0.545024
          515  +vt 0.069733 0.891781
          516  +vt 0.535856 0.891781
          517  +vt 0.000000 0.070792
          518  +vt 1.000000 0.070792
          519  +vt 1.000000 0.545024
          520  +vt 0.000000 0.545024
          521  +vt 1.000000 0.070792
          522  +vt 0.000000 0.070792
          523  +vt 0.000000 0.545024
          524  +vt 1.000000 0.545024
          525  +vt 1.001979 0.070792
          526  +vt 0.069733 0.070792
          527  +vt 1.001979 0.545024
          528  +vt 1.001979 0.000000
          529  +vt 1.001979 1.000000
          530  +vt 0.943929 0.941876
          531  +vt 0.943929 0.058124
          532  +vt 0.535856 0.000000
          533  +vt 0.535856 1.000000
          534  +vt 0.475698 0.939583
          535  +vt 0.475698 0.060417
          536  +vt 0.000000 0.891781
          537  +vt 1.000000 0.891781
          538  +vt 0.000000 0.545024
          539  +vt 1.000000 0.545024
          540  +vt 1.000000 0.891781
          541  +vt 0.000000 0.891781
          542  +vt 0.535856 0.891781
          543  +vt 0.069733 0.891781
          544  +vt 0.058124 0.545024
          545  +vt 0.941876 0.545024
          546  +vt 0.941876 0.125995
          547  +vt 0.058124 0.125995
          548  +vt 0.535856 1.000000
          549  +vt 0.535856 0.000000
          550  +vt 0.593906 0.058124
          551  +vt 0.593906 0.941876
          552  +vt 0.943929 0.941876
          553  +vt 0.593906 0.941876
          554  +vt 0.593906 0.058124
          555  +vt 0.943929 0.058124
          556  +vt 0.593906 0.545024
          557  +vt 0.943929 0.545024
          558  +vt 0.943929 0.125995
          559  +vt 0.593906 0.125995
          560  +vt 0.943929 0.545024
          561  +vt 0.593906 0.545024
          562  +vt 0.593906 0.125995
          563  +vt 0.943929 0.125995
          564  +vt 0.941876 0.545024
          565  +vt 0.058124 0.545024
          566  +vt 0.058124 0.125995
          567  +vt 0.941876 0.125995
          568  +vt 0.060417 0.891781
          569  +vt 0.939583 0.891781
          570  +vt 0.939583 -0.066303
          571  +vt 0.060417 -0.066303
          572  +vt 0.069733 1.000000
          573  +vt 0.069733 0.000000
          574  +vt 0.129891 0.060417
          575  +vt 0.129891 0.939583
          576  +vt 0.475698 0.939583
          577  +vt 0.129891 0.939583
          578  +vt 0.129891 0.060417
          579  +vt 0.475698 0.060417
          580  +vt 0.939583 0.891781
          581  +vt 0.060417 0.891781
          582  +vt 0.060417 -0.066303
          583  +vt 0.939583 -0.066303
          584  +vt 0.475698 0.891781
          585  +vt 0.129891 0.891781
          586  +vt 0.129891 -0.066303
          587  +vt 0.475698 -0.066303
          588  +vt 0.129891 0.891781
          589  +vt 0.475698 0.891781
          590  +vt 0.475698 -0.066303
          591  +vt 0.129891 -0.066303
          592  +vt -0.100000 0.595107
          593  +vt -0.100000 0.404893
          594  +vt 0.900000 0.404893
          595  +vt 0.900000 0.595107
          596  +vt 0.595107 0.416603
          597  +vt 0.595107 0.583397
          598  +vt 0.404893 0.583397
          599  +vt 0.404893 0.416603
          600  +vt -0.100000 0.416603
          601  +vt -0.100000 0.583397
          602  +vt 0.900000 0.583397
          603  +vt 0.900000 0.416603
          604  +vt -0.100000 0.583397
          605  +vt -0.100000 0.416603
          606  +vt 0.900000 0.416603
          607  +vt 0.900000 0.583397
          608  +vt -0.100000 0.404893
          609  +vt -0.100000 0.595107
          610  +vt 0.900000 0.595107
          611  +vt 0.900000 0.404893
          612  +vt 0.576208 0.000000
          613  +vt 0.576208 1.000000
          614  +vt 0.423792 1.000000
          615  +vt 0.423792 0.000000
          616  +vt 0.629579 0.000000
          617  +vt 0.629579 1.000000
          618  +vt 0.370421 1.000000
          619  +vt 0.370421 0.000000
          620  +vt 0.423792 0.000000
          621  +vt 0.423792 1.000000
          622  +vt 0.576208 1.000000
          623  +vt 0.576208 0.000000
          624  +vt 0.370421 0.000000
          625  +vt 0.370421 1.000000
          626  +vt 0.629579 1.000000
          627  +vt 0.629579 0.000000
          628  +vt 1.000000 -0.000000
          629  +vt 1.000000 1.000000
          630  +vt 0.000077 0.999923
          631  +vt 0.000077 0.000077
          632  +vt 0.000000 1.000000
          633  +vt 1.000000 1.000000
          634  +vt 1.000000 0.000000
          635  +vt 0.000000 0.000000
          636  +vt 4.684376 -5.655330
          637  +vt 3.857829 -5.655330
          638  +vt 3.684376 -4.672564
          639  +vt 4.510924 -4.672564
          640  +vt 0.000000 1.000000
          641  +vt 1.000000 1.000000
          642  +vt 1.000000 0.000000
          643  +vt 0.000000 0.000000
          644  +vn 0.7151 0.0000 -0.6991
          645  +vn -0.7151 0.0000 0.6991
          646  +vn 0.0000 -1.0000 0.0000
          647  +vn 0.0000 1.0000 -0.0000
          648  +vn 0.6991 0.0000 0.7151
          649  +vn -0.6991 0.0000 -0.7151
          650  +vn 1.0000 0.0000 -0.0000
          651  +vn -1.0000 0.0000 0.0000
          652  +vn -0.0000 0.0000 -1.0000
          653  +vn 0.0000 0.0000 1.0000
          654  +vn 0.0000 0.9696 -0.2448
          655  +vn -0.0000 -0.2448 -0.9696
          656  +vn 0.0000 -0.9696 0.2448
          657  +vn 0.0462 0.0697 -0.9965
          658  +vn -0.5847 -0.8069 -0.0835
          659  +vn -0.0462 -0.0697 0.9965
          660  +vn 0.5847 0.8069 0.0835
          661  +vn -0.8099 0.5865 0.0035
          662  +vn 0.8099 -0.5865 -0.0035
          663  +vn 0.0000 0.2448 0.9696
          664  +g screwdriver.002_Cube.014_wood
          665  +usemtl wood
          666  +s off
          667  +f 121/217/13 122/218/13 124/219/13 123/220/13
          668  +f 127/221/14 128/222/14 126/223/14 125/224/14
          669  +f 123/225/15 127/226/15 125/227/15 121/228/15
          670  +f 128/229/16 124/230/16 122/231/16 126/232/16
          671  +f 123/233/17 124/234/17 128/235/17 127/236/17
          672  +f 121/237/18 125/238/18 126/239/18 122/240/18
          673  +f 129/241/19 131/242/19 133/243/19 137/244/19 134/245/19
          674  +f 138/246/20 135/247/20 141/248/20 142/249/20
          675  +f 131/250/21 132/251/21 136/252/21 133/253/21
          676  +f 130/254/22 129/255/22 134/256/22 135/257/22
          677  +f 132/258/20 130/259/20 135/247/20 138/246/20 136/260/20
          678  +f 133/261/16 136/262/16 144/263/16 145/264/16
          679  +f 139/265/16 142/266/16 154/267/16 151/268/16
          680  +f 135/257/22 134/256/22 140/269/22 141/270/22
          681  +f 137/271/21 138/272/21 142/273/21 139/274/21
          682  +f 134/245/19 137/244/19 139/275/19 140/276/19
          683  +f 145/277/22 144/278/22 148/279/22 149/280/22
          684  +f 138/281/16 137/282/16 146/283/16 143/284/16
          685  +f 137/282/16 133/261/16 145/264/16 146/283/16
          686  +f 136/262/16 138/281/16 143/284/16 144/263/16
          687  +f 148/285/16 147/286/16 150/287/16 149/288/16
          688  +f 146/289/20 145/290/20 149/291/20 150/292/20
          689  +f 144/293/19 143/294/19 147/295/19 148/296/19
          690  +f 143/297/21 146/298/21 150/299/21 147/300/21
          691  +f 151/301/22 154/302/22 158/303/22 155/304/22
          692  +f 141/305/16 140/306/16 152/307/16 153/308/16
          693  +f 142/266/16 141/305/16 153/308/16 154/267/16
          694  +f 140/306/16 139/265/16 151/268/16 152/307/16
          695  +f 158/309/16 157/310/16 156/311/16 155/312/16
          696  +f 153/313/21 152/314/21 156/315/21 157/316/21
          697  +f 154/317/19 153/318/19 157/319/19 158/320/19
          698  +f 152/321/20 151/322/20 155/323/20 156/324/20
          699  +f 159/325/23 162/326/23 166/327/23 163/328/23
          700  +f 164/329/24 163/330/24 166/331/24 165/332/24
          701  +f 160/333/20 159/334/20 163/335/20 164/336/20
          702  +f 162/337/19 161/338/19 165/339/19 166/340/19
          703  +f 161/341/25 160/342/25 164/343/25 165/344/25
          704  +f 172/345/26 173/346/26 174/347/26 168/348/26
          705  +f 170/349/27 171/350/27 173/351/27 172/352/27
          706  +f 167/353/28 169/354/28 171/355/28 170/356/28
          707  +f 168/357/29 174/358/29 169/359/29 167/360/29
          708  +f 173/361/30 171/362/30 169/363/30 174/364/30
          709  +f 167/365/31 170/366/31 172/367/31 168/368/31
          710  +f 160/369/32 161/370/32 162/371/32 159/372/32
          711  +f 131/373/15 129/374/15 130/375/15 132/376/15
          712  +o screwdriver.003_Cube.015
          713  +v 0.158085 -0.383521 -0.108598
          714  +v 0.158085 -0.414482 -0.108598
          715  +v 0.135946 -0.414482 -0.086954
          716  +v 0.135946 -0.383521 -0.086954
          717  +v 0.296978 -0.383521 0.033471
          718  +v 0.296978 -0.414482 0.033471
          719  +v 0.274839 -0.414482 0.055115
          720  +v 0.274839 -0.383521 0.055115
          721  +v 0.296978 -0.393841 0.033471
          722  +v 0.296978 -0.404161 0.033471
          723  +v 0.274839 -0.393841 0.055115
          724  +v 0.274839 -0.404161 0.055115
          725  +v 0.312696 -0.393841 0.049548
          726  +v 0.312696 -0.404161 0.049548
          727  +v 0.290557 -0.393841 0.071192
          728  +v 0.290557 -0.404161 0.071192
          729  +v 0.300570 -0.393841 0.029960
          730  +v 0.300570 -0.404161 0.029960
          731  +v 0.271248 -0.393841 0.058626
          732  +v 0.271248 -0.404161 0.058626
          733  +v 0.316288 -0.393841 0.046037
          734  +v 0.316288 -0.404161 0.046037
          735  +v 0.286966 -0.393841 0.074704
          736  +v 0.286966 -0.404161 0.074704
          737  +v -0.002015 -0.417557 -0.276758
          738  +v -0.002015 -0.380446 -0.276758
          739  +v -0.028552 -0.380446 -0.250814
          740  +v -0.028552 -0.417557 -0.250814
          741  +v -0.007652 -0.417557 -0.282523
          742  +v -0.007652 -0.380446 -0.282523
          743  +v -0.034188 -0.380446 -0.256579
          744  +v -0.034188 -0.417557 -0.256579
          745  +v -0.251199 -0.388445 0.143113
          746  +v -0.251199 -0.170935 0.088198
          747  +v -0.379763 -0.388445 0.143113
          748  +v -0.379763 -0.170935 0.088198
          749  +v -0.251199 -0.424855 -0.001101
          750  +v -0.251199 -0.207344 -0.056016
          751  +v -0.379763 -0.424855 -0.001101
          752  +v -0.379763 -0.207344 -0.056016
          753  +v -0.237672 -0.210997 0.269398
          754  +v -0.238682 -0.212520 0.291190
          755  +v -0.246202 -0.222898 0.290116
          756  +v -0.245192 -0.221375 0.268324
          757  +v -0.254752 -0.198628 0.269471
          758  +v -0.255762 -0.200151 0.291263
          759  +v -0.263282 -0.210529 0.290188
          760  +v -0.262272 -0.209006 0.268397
          761  +v -0.256924 -0.201625 0.269161
          762  +v -0.257934 -0.203149 0.290952
          763  +v -0.261110 -0.207532 0.290499
          764  +v -0.260100 -0.206008 0.268707
          765  +v -0.274942 -0.188814 0.271518
          766  +v -0.275740 -0.190018 0.288748
          767  +v -0.278916 -0.194401 0.288294
          768  +v -0.278118 -0.193197 0.271065
          769  +v 0.377330 -0.285952 -0.349122
          770  +v 0.377330 -0.070448 -0.349122
          771  +v 0.392567 -0.285952 -0.302599
          772  +v 0.392567 -0.070448 -0.302599
          773  +v 0.220302 -0.285952 -0.297693
          774  +v 0.220302 -0.070448 -0.297693
          775  +v 0.235539 -0.285952 -0.251169
          776  +v 0.235539 -0.070448 -0.251169
          777  +v 0.377330 -0.255225 -0.349122
          778  +v 0.377330 -0.172742 -0.349122
          779  +v 0.392567 -0.172742 -0.302599
          780  +v 0.392567 -0.255226 -0.302599
          781  +v 0.235539 -0.172742 -0.251169
          782  +v 0.235539 -0.255226 -0.251169
          783  +v 0.220302 -0.172742 -0.297693
          784  +v 0.220302 -0.255226 -0.297693
          785  +v 0.396207 -0.070448 -0.291484
          786  +v 0.239179 -0.070448 -0.240055
          787  +v 0.396207 -0.172742 -0.291484
          788  +v 0.239179 -0.172742 -0.240055
          789  +v 0.395886 -0.255226 -0.292463
          790  +v 0.395886 -0.285952 -0.292463
          791  +v 0.238858 -0.285952 -0.241034
          792  +v 0.238858 -0.255226 -0.241034
          793  +v 0.296629 -0.240812 -0.271177
          794  +v 0.281392 -0.240812 -0.317701
          795  +v 0.296629 -0.220446 -0.271177
          796  +v 0.281392 -0.204143 -0.317701
          797  +v 0.281392 -0.207521 -0.317701
          798  +v 0.296629 -0.204143 -0.271177
          799  +v 0.331477 -0.207521 -0.282591
          800  +v 0.316240 -0.204143 -0.329114
          801  +v 0.331477 -0.204143 -0.282591
          802  +v 0.331477 -0.240812 -0.282591
          803  +v 0.316240 -0.240812 -0.329114
          804  +v 0.433728 -0.285952 -0.176921
          805  +v 0.433728 -0.070448 -0.176921
          806  +v 0.418491 -0.285952 -0.223445
          807  +v 0.418491 -0.070448 -0.223445
          808  +v 0.276700 -0.285952 -0.125492
          809  +v 0.276700 -0.070448 -0.125492
          810  +v 0.261463 -0.285952 -0.172016
          811  +v 0.261463 -0.070448 -0.172016
          812  +v 0.433728 -0.255225 -0.176921
          813  +v 0.433728 -0.172742 -0.176921
          814  +v 0.418491 -0.172742 -0.223445
          815  +v 0.418491 -0.255226 -0.223445
          816  +v 0.261463 -0.172742 -0.172016
          817  +v 0.261463 -0.255226 -0.172016
          818  +v 0.276700 -0.172742 -0.125492
          819  +v 0.276700 -0.255226 -0.125492
          820  +v 0.414851 -0.070448 -0.234559
          821  +v 0.257823 -0.070448 -0.183130
          822  +v 0.414851 -0.172742 -0.234559
          823  +v 0.257823 -0.172742 -0.183130
          824  +v 0.415171 -0.255226 -0.233580
          825  +v 0.415171 -0.285952 -0.233580
          826  +v 0.258143 -0.285952 -0.182151
          827  +v 0.258143 -0.255226 -0.182151
          828  +v 0.322553 -0.240812 -0.192024
          829  +v 0.337790 -0.240812 -0.145500
          830  +v 0.322553 -0.220446 -0.192024
          831  +v 0.337790 -0.204143 -0.145500
          832  +v 0.337790 -0.207521 -0.145500
          833  +v 0.322553 -0.204143 -0.192024
          834  +v 0.357401 -0.207521 -0.203437
          835  +v 0.372638 -0.204143 -0.156913
          836  +v 0.357401 -0.204143 -0.203437
          837  +v 0.357401 -0.240812 -0.203437
          838  +v 0.372638 -0.240812 -0.156913
          839  +v 0.380855 -0.429536 -0.404467
          840  +v 0.372027 -0.429536 -0.431422
          841  +v 0.184718 -0.429536 -0.340229
          842  +v 0.175890 -0.429536 -0.367184
          843  +v 0.368023 -0.316916 -0.443648
          844  +v 0.368023 -0.429536 -0.443648
          845  +v 0.171886 -0.316916 -0.379410
          846  +v 0.171886 -0.429536 -0.379410
          847  +v 0.394770 -0.429536 -0.080126
          848  +v 0.365372 -0.429536 -0.070497
          849  +v 0.385942 -0.429536 -0.107080
          850  +v 0.356544 -0.429536 -0.097452
          851  +v 0.341714 -0.429536 -0.242121
          852  +v 0.312316 -0.429536 -0.232493
          853  +v 0.469312 -0.429536 -0.134385
          854  +v 0.478140 -0.429536 -0.107431
          855  +v 0.273174 -0.429536 -0.070147
          856  +v 0.282002 -0.429536 -0.043193
          857  +v 0.425083 -0.429536 -0.269426
          858  +v 0.228946 -0.429536 -0.205188
          859  +v 0.398775 -0.429536 -0.067900
          860  +v 0.369376 -0.429536 -0.058271
          861  +v 0.482144 -0.316916 -0.095204
          862  +v 0.482144 -0.429536 -0.095204
          863  +v 0.286007 -0.316916 -0.030966
          864  +v 0.286007 -0.429536 -0.030966
          865  +vt 0.466448 0.281802
          866  +vt 0.533552 0.281802
          867  +vt 0.533552 0.712415
          868  +vt 0.466448 0.712415
          869  +vt 0.466448 0.511184
          870  +vt 0.466448 0.533552
          871  +vt 0.533552 0.533552
          872  +vt 0.533552 0.511184
          873  +vt 0.281802 0.466448
          874  +vt 0.281802 0.533552
          875  +vt 0.712415 0.533552
          876  +vt 0.712415 0.511184
          877  +vt 0.712415 0.488816
          878  +vt 0.712415 0.466448
          879  +vt 0.281802 0.533552
          880  +vt 0.281802 0.466448
          881  +vt 0.712415 0.466448
          882  +vt 0.712415 0.488816
          883  +vt 0.712415 0.511184
          884  +vt 0.712415 0.533552
          885  +vt 0.533552 0.281802
          886  +vt 0.466448 0.281802
          887  +vt 0.466448 0.712415
          888  +vt 0.533552 0.712415
          889  +vt 0.466448 0.466448
          890  +vt 0.466448 0.488816
          891  +vt 0.533552 0.488816
          892  +vt 0.533552 0.466448
          893  +vt 0.466448 0.712415
          894  +vt 0.466448 0.761147
          895  +vt 0.455562 0.761147
          896  +vt 0.455562 0.712415
          897  +vt 0.466448 0.488816
          898  +vt 0.466448 0.511184
          899  +vt 0.533552 0.511184
          900  +vt 0.533552 0.488816
          901  +vt 0.544438 0.488816
          902  +vt 0.544438 0.511184
          903  +vt 0.533552 0.712415
          904  +vt 0.466448 0.712415
          905  +vt 0.466448 0.761147
          906  +vt 0.533552 0.761147
          907  +vt 0.533552 0.712415
          908  +vt 0.533552 0.761147
          909  +vt 0.712415 0.511184
          910  +vt 0.712415 0.488816
          911  +vt 0.761147 0.488816
          912  +vt 0.761147 0.511184
          913  +vt 0.712415 0.488816
          914  +vt 0.712415 0.511184
          915  +vt 0.761147 0.511184
          916  +vt 0.761147 0.488816
          917  +vt 0.455562 0.511184
          918  +vt 0.455562 0.488816
          919  +vt 0.544438 0.761147
          920  +vt 0.544438 0.712415
          921  +vt 0.455562 0.488816
          922  +vt 0.455562 0.511184
          923  +vt 0.455562 0.712415
          924  +vt 0.455562 0.761147
          925  +vt 0.544438 0.712415
          926  +vt 0.544438 0.761147
          927  +vt 0.544438 0.511184
          928  +vt 0.544438 0.488816
          929  +vt 0.540216 -0.221379
          930  +vt 0.459784 -0.221379
          931  +vt 0.459784 -0.238854
          932  +vt 0.540216 -0.238854
          933  +vt 0.540216 0.459784
          934  +vt 0.540216 0.540216
          935  +vt 0.459784 0.540216
          936  +vt 0.459784 0.459784
          937  +vt -0.221379 0.459784
          938  +vt -0.221379 0.540216
          939  +vt -0.238854 0.540216
          940  +vt -0.238854 0.459784
          941  +vt 0.459784 -0.221379
          942  +vt 0.540216 -0.221379
          943  +vt 0.540216 -0.238854
          944  +vt 0.459784 -0.238854
          945  +vt -0.221379 0.540216
          946  +vt -0.221379 0.459784
          947  +vt -0.238854 0.459784
          948  +vt -0.238854 0.540216
          949  +vt 0.213456 0.000000
          950  +vt 0.213456 1.000000
          951  +vt 0.786544 1.000000
          952  +vt 0.786544 0.000000
          953  +vt 0.057985 0.000000
          954  +vt 0.057985 1.000000
          955  +vt 0.721007 1.000000
          956  +vt 0.721007 0.000000
          957  +vt 0.573077 0.000076
          958  +vt 0.573077 0.999924
          959  +vt 0.000076 0.999924
          960  +vt 0.000076 0.000076
          961  +vt 0.721007 0.000000
          962  +vt 0.721007 1.000000
          963  +vt 0.057985 1.000000
          964  +vt 0.057985 0.000000
          965  +vt 0.057985 0.786544
          966  +vt 0.721007 0.786544
          967  +vt 0.721007 0.213456
          968  +vt 0.057985 0.213456
          969  +vt 0.721007 0.786544
          970  +vt 0.057985 0.786544
          971  +vt 0.057985 0.213456
          972  +vt 0.721007 0.213456
          973  +vt -4.674511 -10.751538
          974  +vt -4.674511 -9.751538
          975  +vt -3.674511 -9.751538
          976  +vt -3.674511 -10.751538
          977  +vt 0.753081 -0.031154
          978  +vt 0.246919 -0.031154
          979  +vt 0.246919 0.456970
          980  +vt 0.753081 0.456970
          981  +vt 0.351158 0.246919
          982  +vt 0.648842 0.246919
          983  +vt 0.562862 0.246919
          984  +vt 0.437138 0.246919
          985  +vt 0.351158 -0.031154
          986  +vt 0.648842 -0.031154
          987  +vt 0.648842 0.456970
          988  +vt 0.351158 0.456970
          989  +vt 0.648842 -0.031154
          990  +vt 0.351158 -0.031154
          991  +vt 0.351158 0.456970
          992  +vt 0.648842 0.456970
          993  +vt 0.246919 -0.031154
          994  +vt 0.753081 -0.031154
          995  +vt 0.753081 0.456970
          996  +vt 0.246919 0.456970
          997  +vt 0.246919 0.456970
          998  +vt 0.753081 0.456970
          999  +vt 0.700094 0.968846
         1000  +vt 0.299906 0.968846
         1001  +vt 0.648842 0.753081
         1002  +vt 0.351158 0.753081
         1003  +vt 0.437138 0.753081
         1004  +vt 0.562862 0.753081
         1005  +vt 0.562862 0.700094
         1006  +vt 0.437138 0.700094
         1007  +vt 0.437138 0.299906
         1008  +vt 0.562862 0.299906
         1009  +vt 0.753081 0.456970
         1010  +vt 0.246919 0.456970
         1011  +vt 0.299906 0.968846
         1012  +vt 0.700094 0.968846
         1013  +vt 0.437138 0.456970
         1014  +vt 0.562862 0.456970
         1015  +vt 0.562862 0.968846
         1016  +vt 0.437138 0.968846
         1017  +vt 0.562862 0.456970
         1018  +vt 0.437138 0.456970
         1019  +vt 0.437138 0.968846
         1020  +vt 0.562862 0.968846
         1021  +vt 0.330609 0.624954
         1022  +vt 0.330609 1.099628
         1023  +vt 0.557773 1.099628
         1024  +vt 0.557773 0.624954
         1025  +vt 0.875000 0.500000
         1026  +vt 0.625000 0.500000
         1027  +vt 0.625000 0.500000
         1028  +vt 0.875000 0.500000
         1029  +vt 0.557773 0.624954
         1030  +vt 0.557773 1.099628
         1031  +vt 0.330609 1.099628
         1032  +vt 0.330609 0.624954
         1033  +vt 0.541667 0.750000
         1034  +vt 0.625000 0.750000
         1035  +vt 0.625000 1.000000
         1036  +vt 0.541667 1.000000
         1037  +vt 0.125000 0.500000
         1038  +vt 0.375000 0.500000
         1039  +vt 0.375000 0.750000
         1040  +vt 0.125000 0.750000
         1041  +vt 0.875000 0.750000
         1042  +vt 0.458333 0.750000
         1043  +vt 0.458333 1.000000
         1044  +vt 0.375000 1.000000
         1045  +vt 0.506529 0.855413
         1046  +vt 0.472895 0.855413
         1047  +vt 0.472895 0.894587
         1048  +vt 0.557773 0.099628
         1049  +vt 0.557773 0.242209
         1050  +vt 0.330609 0.242209
         1051  +vt 0.330609 0.099628
         1052  +vt 0.458333 0.250000
         1053  +vt 0.458333 0.500000
         1054  +vt 0.458333 0.500000
         1055  +vt 0.458333 0.250000
         1056  +vt 0.541667 0.250000
         1057  +vt 0.506529 0.355413
         1058  +vt 0.472895 0.355413
         1059  +vt 0.472895 0.394587
         1060  +vt 0.493471 0.394587
         1061  +vt 0.330609 0.099628
         1062  +vt 0.330609 0.242209
         1063  +vt 0.557773 0.242209
         1064  +vt 0.557773 0.099628
         1065  +vt 0.541667 0.250000
         1066  +vt 0.625000 0.250000
         1067  +vt 0.541667 0.500000
         1068  +vt 0.612042 0.624954
         1069  +vt 0.612042 1.099628
         1070  +vt 0.612042 1.099628
         1071  +vt 0.612042 0.624954
         1072  +vt 0.541667 0.500000
         1073  +vt 0.375000 0.250000
         1074  +vt 0.375000 0.500000
         1075  +vt 0.607264 0.242209
         1076  +vt 0.607264 0.099628
         1077  +vt 0.607264 0.099628
         1078  +vt 0.607264 0.242209
         1079  +vt 0.125000 0.500000
         1080  +vt 0.375000 0.667406
         1081  +vt 0.375000 0.717256
         1082  +vt 0.601970 0.717256
         1083  +vt 0.625000 0.717256
         1084  +vt 0.625000 0.667407
         1085  +vt 0.513850 0.667407
         1086  +vt 0.375000 0.032744
         1087  +vt 0.375000 0.082593
         1088  +vt 0.601970 0.082593
         1089  +vt 0.625000 0.082593
         1090  +vt 0.625000 0.032744
         1091  +vt 0.125000 0.667407
         1092  +vt 0.125000 0.717256
         1093  +vt 0.875000 0.717256
         1094  +vt 0.875000 0.667406
         1095  +vt 0.509942 0.394587
         1096  +vt 0.509942 0.355413
         1097  +vt 0.509942 0.894588
         1098  +vt 0.509942 0.855413
         1099  +vt 0.330609 0.624954
         1100  +vt 0.557773 0.624954
         1101  +vt 0.557773 1.099628
         1102  +vt 0.330609 1.099628
         1103  +vt 0.875000 0.500000
         1104  +vt 0.875000 0.500000
         1105  +vt 0.625000 0.500000
         1106  +vt 0.625000 0.500000
         1107  +vt 0.557773 0.624954
         1108  +vt 0.330609 0.624954
         1109  +vt 0.330609 1.099628
         1110  +vt 0.557773 1.099628
         1111  +vt 0.541667 0.750000
         1112  +vt 0.541667 1.000000
         1113  +vt 0.625000 1.000000
         1114  +vt 0.625000 0.750000
         1115  +vt 0.125000 0.500000
         1116  +vt 0.125000 0.750000
         1117  +vt 0.375000 0.750000
         1118  +vt 0.375000 0.500000
         1119  +vt 0.875000 0.750000
         1120  +vt 0.375000 1.000000
         1121  +vt 0.458333 1.000000
         1122  +vt 0.458333 0.750000
         1123  +vt 0.472895 0.894587
         1124  +vt 0.472895 0.855413
         1125  +vt 0.506529 0.855413
         1126  +vt 0.557773 0.099628
         1127  +vt 0.330609 0.099628
         1128  +vt 0.330609 0.242209
         1129  +vt 0.557773 0.242209
         1130  +vt 0.458333 0.250000
         1131  +vt 0.458333 0.250000
         1132  +vt 0.458333 0.500000
         1133  +vt 0.458333 0.500000
         1134  +vt 0.493471 0.394587
         1135  +vt 0.472895 0.394587
         1136  +vt 0.472895 0.355413
         1137  +vt 0.506529 0.355413
         1138  +vt 0.541667 0.250000
         1139  +vt 0.330609 0.099628
         1140  +vt 0.557773 0.099628
         1141  +vt 0.557773 0.242209
         1142  +vt 0.330609 0.242209
         1143  +vt 0.541667 0.250000
         1144  +vt 0.541667 0.500000
         1145  +vt 0.625000 0.250000
         1146  +vt 0.612042 1.099628
         1147  +vt 0.612042 0.624954
         1148  +vt 0.612042 0.624954
         1149  +vt 0.612042 1.099628
         1150  +vt 0.541667 0.500000
         1151  +vt 0.375000 0.250000
         1152  +vt 0.375000 0.500000
         1153  +vt 0.607264 0.099628
         1154  +vt 0.607264 0.242209
         1155  +vt 0.607264 0.242209
         1156  +vt 0.607264 0.099628
         1157  +vt 0.125000 0.500000
         1158  +vt 0.375000 0.667406
         1159  +vt 0.513850 0.667407
         1160  +vt 0.625000 0.667407
         1161  +vt 0.625000 0.717256
         1162  +vt 0.601970 0.717256
         1163  +vt 0.375000 0.717256
         1164  +vt 0.375000 0.032744
         1165  +vt 0.625000 0.032744
         1166  +vt 0.625000 0.082593
         1167  +vt 0.601970 0.082593
         1168  +vt 0.375000 0.082593
         1169  +vt 0.125000 0.667407
         1170  +vt 0.125000 0.717256
         1171  +vt 0.875000 0.667406
         1172  +vt 0.875000 0.717256
         1173  +vt 0.509942 0.355413
         1174  +vt 0.509942 0.394587
         1175  +vt 0.509942 0.855413
         1176  +vt 0.509942 0.894588
         1177  +vt 0.000000 -0.000000
         1178  +vt 1.000000 0.000000
         1179  +vt 1.000000 1.000000
         1180  +vt 0.000000 1.000000
         1181  +vt 0.781448 0.659162
         1182  +vt 0.218553 0.659162
         1183  +vt 0.218553 0.352007
         1184  +vt 0.781448 0.352007
         1185  +vt 0.218553 0.112445
         1186  +vt 0.218553 0.500000
         1187  +vt 0.457814 0.500000
         1188  +vt 0.542185 0.500000
         1189  +vt 0.781448 0.500000
         1190  +vt 0.781448 0.112445
         1191  +vt 0.218553 0.035088
         1192  +vt 0.781448 0.035088
         1193  +vt 0.781448 0.000000
         1194  +vt 0.218553 0.000000
         1195  +vt 0.542185 0.964912
         1196  +vt 0.542185 1.000000
         1197  +vt 0.781448 1.000000
         1198  +vt 0.781448 0.964912
         1199  +vt 0.457814 0.964912
         1200  +vt 0.457814 1.000000
         1201  +vt 0.457814 0.887555
         1202  +vt 0.542185 0.887555
         1203  +vt 0.218553 0.887555
         1204  +vt 0.781448 0.887555
         1205  +vt 0.218553 0.964912
         1206  +vt 0.457814 0.352007
         1207  +vt 0.218553 0.352007
         1208  +vt 0.218553 0.659162
         1209  +vt 0.781448 0.659162
         1210  +vt 0.781448 0.352007
         1211  +vt 0.542185 0.352007
         1212  +vt 1.000000 0.659162
         1213  +vt 0.000000 0.659162
         1214  +vt 0.000000 0.352007
         1215  +vt 0.035088 0.352007
         1216  +vt 0.112445 0.352007
         1217  +vt 0.500000 0.352007
         1218  +vt 0.887555 0.352007
         1219  +vt 0.964912 0.352007
         1220  +vt 1.000000 0.352007
         1221  +vt 0.887555 0.352007
         1222  +vt 0.500000 0.352007
         1223  +vt 0.112445 0.352007
         1224  +vt 0.035088 0.352007
         1225  +vt 0.000000 0.352007
         1226  +vt 0.000000 0.659162
         1227  +vt 1.000000 0.659162
         1228  +vt 1.000000 0.352007
         1229  +vt 0.964912 0.352007
         1230  +vt 0.218553 1.000000
         1231  +vn 0.0000 1.0000 0.0000
         1232  +vn 0.6991 0.0000 0.7151
         1233  +vn 0.7151 0.0000 -0.6991
         1234  +vn -0.7151 0.0000 0.6991
         1235  +vn 0.0000 -1.0000 -0.0000
         1236  +vn -0.6991 0.0000 -0.7151
         1237  +vn 0.0000 0.2448 0.9696
         1238  +vn -1.0000 -0.0000 0.0000
         1239  +vn -0.0000 -0.2448 -0.9696
         1240  +vn 1.0000 -0.0000 -0.0000
         1241  +vn 0.0000 -0.9696 0.2448
         1242  +vn -0.0000 0.9696 -0.2448
         1243  +vn 0.5847 0.8069 0.0835
         1244  +vn 0.5857 -0.3478 -0.7321
         1245  +vn 0.0462 0.0697 -0.9965
         1246  +vn -0.0462 -0.0697 0.9965
         1247  +vn -0.5847 -0.8069 -0.0835
         1248  +vn 0.8360 -0.5487 0.0000
         1249  +vn -0.8099 0.5865 0.0035
         1250  +vn -0.0374 0.1297 -0.9908
         1251  +vn -0.1293 -0.0089 0.9916
         1252  +vn 0.9503 0.0000 -0.3112
         1253  +vn -0.9503 0.0000 0.3112
         1254  +vn -0.3112 0.0000 -0.9503
         1255  +vn 0.3112 0.0000 0.9503
         1256  +vn 0.9503 0.0000 -0.3113
         1257  +vn 0.8099 -0.5865 -0.0035
         1258  +g screwdriver.003_Cube.015_steel
         1259  +usemtl steel
         1260  +s off
         1261  +f 175/377/33 178/378/33 182/379/33 179/380/33
         1262  +f 183/381/34 179/382/34 182/383/34 185/384/34
         1263  +f 176/385/35 175/386/35 179/387/35 183/388/35 184/389/35 180/390/35
         1264  +f 178/391/36 177/392/36 181/393/36 186/394/36 185/395/36 182/396/36
         1265  +f 177/397/37 176/398/37 180/399/37 181/400/37
         1266  +f 180/401/34 184/402/34 186/403/34 181/404/34
         1267  +f 183/405/33 187/406/33 195/407/33 191/408/33
         1268  +f 188/409/34 187/410/34 189/411/34 190/412/34
         1269  +f 185/384/38 186/403/38 194/413/38 193/414/38
         1270  +f 186/415/37 184/416/37 188/417/37 190/418/37
         1271  +f 183/405/33 185/419/33 189/420/33 187/406/33
         1272  +f 193/421/36 194/422/36 198/423/36 197/424/36
         1273  +f 192/425/35 191/426/35 195/427/35 196/428/35
         1274  +f 184/402/38 183/381/38 191/429/38 192/430/38
         1275  +f 186/415/37 190/418/37 198/431/37 194/432/37
         1276  +f 187/410/34 188/409/34 196/433/34 195/434/34
         1277  +f 188/417/37 184/416/37 192/435/37 196/436/37
         1278  +f 189/420/33 185/419/33 193/437/33 197/438/33
         1279  +f 190/412/34 189/411/34 197/439/34 198/440/34
         1280  +f 201/441/33 200/442/33 204/443/33 205/444/33
         1281  +f 206/445/38 205/446/38 204/447/38 203/448/38
         1282  +f 202/449/36 201/450/36 205/451/36 206/452/36
         1283  +f 199/453/37 202/454/37 206/455/37 203/456/37
         1284  +f 200/457/35 199/458/35 203/459/35 204/460/35
         1285  +f 207/461/39 208/462/39 210/463/39 209/464/39
         1286  +f 209/465/40 210/466/40 214/467/40 213/468/40
         1287  +f 213/469/41 214/470/41 212/471/41 211/472/41
         1288  +f 211/473/42 212/474/42 208/475/42 207/476/42
         1289  +f 209/477/43 213/478/43 211/479/43 207/480/43
         1290  +f 214/481/44 210/482/44 208/483/44 212/484/44
         1291  +f 176/398/38 177/397/38 178/391/38 175/377/38
         1292  +f 199/485/34 200/486/34 201/487/34 202/488/34
         1293  +f 216/489/45 215/490/45 219/491/45 220/492/45
         1294  +f 219/493/46 222/494/46 226/495/46 223/496/46
         1295  +f 215/497/47 218/498/47 222/499/47 219/500/47
         1296  +f 217/501/48 216/502/48 220/503/48 221/504/48
         1297  +f 218/505/49 217/506/49 221/507/49 222/508/49
         1298  +f 226/509/49 225/510/49 229/511/49 230/512/49
         1299  +f 221/513/50 220/514/50 224/515/50 225/516/50
         1300  +f 222/494/51 221/513/51 225/516/51 226/495/51
         1301  +f 220/514/51 219/493/51 223/496/51 224/515/51
         1302  +f 229/517/51 228/518/51 227/519/51 230/520/51
         1303  +f 224/521/45 223/522/45 227/523/45 228/524/45
         1304  +f 223/525/52 226/526/52 230/527/52 227/528/52
         1305  +f 225/529/53 224/530/53 228/531/53 229/532/53
         1306  +f 240/533/54 232/534/54 234/535/54 241/536/54
         1307  +f 234/537/33 238/538/33 248/539/33 247/540/33
         1308  +f 243/541/55 238/542/55 236/543/55 245/544/55
         1309  +f 245/545/56 236/546/56 232/547/56 240/548/56
         1310  +f 233/549/37 237/550/37 235/551/37 231/552/37
         1311  +f 238/538/33 234/537/33 232/553/33 236/546/33
         1312  +f 235/551/56 246/554/56 239/555/56 231/556/56
         1313  +f 246/554/56 245/545/56 259/557/56 256/558/56 265/559/56 239/555/56
         1314  +f 237/560/55 244/561/55 246/562/55 235/563/55
         1315  +f 244/561/55 243/541/55 245/544/55 246/562/55
         1316  +f 242/564/33 244/565/33 254/566/33 251/567/33
         1317  +f 242/564/57 241/568/57 261/569/57 264/570/57 255/571/57 257/572/57 244/565/57
         1318  +f 231/573/54 239/574/54 242/575/54 233/576/54
         1319  +f 239/574/54 240/533/54 241/536/54 242/575/54
         1320  +f 249/577/57 247/578/57 248/539/57 250/579/57
         1321  +f 238/542/55 243/541/55 250/580/55 248/581/55
         1322  +f 241/536/58 234/535/58 247/582/58 249/583/58
         1323  +f 243/584/37 241/568/37 249/577/37 250/579/37
         1324  +f 252/585/57 251/567/57 254/566/57 253/586/57
         1325  +f 233/576/54 242/575/54 251/587/54 252/588/54
         1326  +f 244/561/55 237/560/55 253/589/55 254/590/55
         1327  +f 237/550/37 233/549/37 252/591/37 253/586/37
         1328  +f 255/592/54 256/593/54 259/594/54 258/595/54 260/596/54 257/597/54
         1329  +f 265/598/55 264/599/55 261/600/55 263/601/55 262/602/55
         1330  +f 264/603/33 265/604/33 256/593/33 255/592/33
         1331  +f 260/596/37 258/595/37 262/605/37 263/606/37
         1332  +f 244/565/57 257/572/57 260/607/57 263/608/57 261/569/57 241/568/57 243/584/57
         1333  +f 239/555/56 265/559/56 262/609/56 258/610/56 259/557/56 245/545/56 240/548/56
         1334  +f 275/611/54 276/612/54 269/613/54 267/614/54
         1335  +f 269/615/33 282/616/33 283/617/33 273/618/33
         1336  +f 278/619/55 280/620/55 271/621/55 273/622/55
         1337  +f 280/623/57 275/624/57 267/625/57 271/626/57
         1338  +f 268/627/37 266/628/37 270/629/37 272/630/37
         1339  +f 273/618/33 271/626/33 267/631/33 269/615/33
         1340  +f 270/629/57 266/632/57 274/633/57 281/634/57
         1341  +f 281/634/57 274/633/57 300/635/57 291/636/57 294/637/57 280/623/57
         1342  +f 272/638/55 270/639/55 281/640/55 279/641/55
         1343  +f 279/641/55 281/640/55 280/620/55 278/619/55
         1344  +f 277/642/33 286/643/33 289/644/33 279/645/33
         1345  +f 277/642/56 279/645/56 292/646/56 290/647/56 299/648/56 296/649/56 276/650/56
         1346  +f 266/651/54 268/652/54 277/653/54 274/654/54
         1347  +f 274/654/54 277/653/54 276/612/54 275/611/54
         1348  +f 284/655/56 285/656/56 283/617/56 282/657/56
         1349  +f 273/622/55 283/658/55 285/659/55 278/619/55
         1350  +f 276/612/54 284/660/54 282/661/54 269/613/54
         1351  +f 278/662/37 285/656/37 284/655/37 276/650/37
         1352  +f 287/663/56 288/664/56 289/644/56 286/643/56
         1353  +f 268/652/54 287/665/54 286/666/54 277/653/54
         1354  +f 279/641/55 289/667/55 288/668/55 272/638/55
         1355  +f 272/630/37 288/664/37 287/669/37 268/627/37
         1356  +f 290/670/54 292/671/54 295/672/54 293/673/54 294/674/54 291/675/54
         1357  +f 300/676/55 297/677/55 298/678/55 296/679/55 299/680/55
         1358  +f 299/681/33 290/670/33 291/675/33 300/682/33
         1359  +f 295/672/37 298/683/37 297/684/37 293/673/37
         1360  +f 279/645/56 278/662/56 276/650/56 296/649/56 298/685/56 295/686/56 292/646/56
         1361  +f 274/633/57 275/624/57 280/623/57 294/637/57 293/687/57 297/688/57 300/635/57
         1362  +f 305/689/33 307/690/33 325/691/33 323/692/33
         1363  +f 307/693/56 305/694/56 306/695/56 308/696/56
         1364  +f 301/697/37 319/698/37 313/699/37 314/700/37 320/701/37 303/702/37
         1365  +f 302/703/37 304/704/37 308/705/37 306/706/37
         1366  +f 304/704/37 302/703/37 301/697/37 303/702/37
         1367  +f 310/707/37 322/708/37 326/709/37 318/710/37
         1368  +f 309/711/37 321/712/37 322/708/37 310/707/37
         1369  +f 311/713/37 309/711/37 310/707/37 312/714/37
         1370  +f 312/714/37 314/700/37 313/699/37 311/713/37
         1371  +f 313/699/37 319/698/37 315/715/37 311/713/37
         1372  +f 312/714/37 317/716/37 320/701/37 314/700/37
         1373  +f 311/713/37 315/715/37 316/717/37 309/711/37
         1374  +f 310/707/37 318/710/37 317/716/37 312/714/37
         1375  +f 321/718/57 324/719/57 323/720/57 325/721/57 326/722/57 322/723/57
         1376  +f 325/724/55 307/725/55 308/726/55 304/727/55 303/728/55 320/729/55 317/730/55 318/731/55 326/732/55
         1377  +f 315/733/54 319/734/54 301/735/54 302/736/54 306/737/54 305/738/54 323/739/54 324/740/54 316/741/54
         1378  +f 316/717/37 324/742/37 321/712/37 309/711/37
         1379  +f 215/497/59 216/502/59 217/506/59 218/498/59
         1380  +o screwdriver.004_Cube.016
         1381  +v -0.500000 -0.426985 -0.500000
         1382  +v -0.500000 -0.500000 -0.500000
         1383  +v 0.500000 -0.426985 -0.500000
         1384  +v 0.500000 -0.500000 -0.500000
         1385  +v -0.500000 -0.426985 0.500000
         1386  +v -0.500000 -0.500000 0.500000
         1387  +v 0.500000 -0.426985 0.500000
         1388  +v 0.500000 -0.500000 0.500000
         1389  +vt 1.000000 0.000000
         1390  +vt 1.000000 1.000000
         1391  +vt -0.000000 1.000000
         1392  +vt 0.000000 0.000000
         1393  +vt 0.021155 0.465926
         1394  +vt 0.021155 0.538941
         1395  +vt 1.021155 0.538941
         1396  +vt 1.021155 0.465926
         1397  +vt 1.021155 0.465926
         1398  +vt 1.021155 0.538941
         1399  +vt 0.021155 0.538941
         1400  +vt 0.021155 0.465926
         1401  +vt 0.021155 1.010579
         1402  +vt 1.021155 1.010579
         1403  +vt 1.021155 0.010579
         1404  +vt 0.021155 0.010579
         1405  +vt 0.010579 0.465926
         1406  +vt 0.010579 0.538941
         1407  +vt 1.010579 0.538941
         1408  +vt 1.010579 0.465926
         1409  +vt 1.010579 0.465926
         1410  +vt 1.010579 0.538941
         1411  +vt 0.010579 0.538941
         1412  +vt 0.010579 0.465926
         1413  +vn 0.0000 1.0000 0.0000
         1414  +vn -1.0000 0.0000 0.0000
         1415  +vn 1.0000 0.0000 -0.0000
         1416  +vn 0.0000 -1.0000 -0.0000
         1417  +vn 0.0000 0.0000 1.0000
         1418  +vn -0.0000 0.0000 -1.0000
         1419  +g screwdriver.004_Cube.016_stone
         1420  +usemtl stone
         1421  +s off
         1422  +f 327/743/60 331/744/60 333/745/60 329/746/60
         1423  +f 332/747/61 331/748/61 327/749/61 328/750/61
         1424  +f 330/751/62 329/752/62 333/753/62 334/754/62
         1425  +f 332/755/63 328/756/63 330/757/63 334/758/63
         1426  +f 334/759/64 333/760/64 331/761/64 332/762/64
         1427  +f 328/763/65 327/764/65 329/765/65 330/766/65
         1428  +o screwdriver.005_Cube.017
         1429  +v -0.180198 -0.430345 0.353438
         1430  +v -0.180198 -0.273910 0.353438
         1431  +v -0.336633 -0.430345 0.353438
         1432  +v -0.336633 -0.273910 0.353438
         1433  +v -0.180198 -0.430345 0.197003
         1434  +v -0.180198 -0.273910 0.197003
         1435  +v -0.336633 -0.430345 0.197003
         1436  +v -0.336633 -0.273910 0.197003
         1437  +v -0.214051 -0.273910 0.319585
         1438  +v -0.302780 -0.273910 0.319585
         1439  +v -0.302780 -0.273910 0.230856
         1440  +v -0.214051 -0.273910 0.230856
         1441  +v -0.214051 -0.247453 0.319585
         1442  +v -0.302780 -0.247453 0.319585
         1443  +v -0.302780 -0.247453 0.230856
         1444  +v -0.214051 -0.247453 0.230856
         1445  +v -0.233435 -0.247453 0.300201
         1446  +v -0.283396 -0.247453 0.300201
         1447  +v -0.283396 -0.247453 0.250240
         1448  +v -0.233435 -0.247453 0.250240
         1449  +v -0.233435 -0.284338 0.300201
         1450  +v -0.283396 -0.284338 0.300201
         1451  +v -0.283396 -0.284338 0.250240
         1452  +v -0.233435 -0.284338 0.250240
         1453  +vt 0.000000 0.000000
         1454  +vt 0.000000 1.000000
         1455  +vt 1.000000 1.000000
         1456  +vt 1.000000 0.000000
         1457  +vt 0.000000 0.000000
         1458  +vt 0.000000 1.000000
         1459  +vt 1.000000 1.000000
         1460  +vt 1.000000 0.000000
         1461  +vt 0.000000 1.000000
         1462  +vt 0.000000 0.000000
         1463  +vt 1.000000 0.000000
         1464  +vt 1.000000 1.000000
         1465  +vt 0.072331 0.927669
         1466  +vt 0.927669 0.927669
         1467  +vt 0.927669 0.072331
         1468  +vt 0.072331 0.072331
         1469  +vt 0.000000 0.000000
         1470  +vt 0.216403 0.216403
         1471  +vt 0.216403 0.783597
         1472  +vt 0.000000 0.350907
         1473  +vt 1.000000 0.350907
         1474  +vt 1.000000 0.649093
         1475  +vt 0.000000 0.649093
         1476  +vt 1.000000 0.000000
         1477  +vt 0.783597 0.216403
         1478  +vt 0.783597 0.783597
         1479  +vt 1.000000 0.000000
         1480  +vt 1.000000 1.000000
         1481  +vt 0.781535 0.781535
         1482  +vt 0.781535 0.218465
         1483  +vt 1.000000 0.350907
         1484  +vt 0.000000 0.350907
         1485  +vt 0.000000 0.649093
         1486  +vt 1.000000 0.649093
         1487  +vt 0.000000 0.350907
         1488  +vt 0.000000 0.649093
         1489  +vt 1.000000 0.350907
         1490  +vt 1.000000 0.649093
         1491  +vt 1.000000 0.658562
         1492  +vt 0.000000 0.658562
         1493  +vt 0.000000 0.341438
         1494  +vt 1.000000 0.341438
         1495  +vt 0.000000 1.000000
         1496  +vt 0.000000 0.000000
         1497  +vt 0.218465 0.218465
         1498  +vt 0.218465 0.781535
         1499  +vt 1.000000 0.658562
         1500  +vt 1.000000 0.341438
         1501  +vt 1.000000 0.658562
         1502  +vt 0.000000 0.658562
         1503  +vt 0.000000 0.341438
         1504  +vt 1.000000 0.341438
         1505  +vt 0.000000 0.658562
         1506  +vt 0.000000 0.341438
         1507  +vn 0.0000 0.0000 1.0000
         1508  +vn -1.0000 0.0000 0.0000
         1509  +vn -0.0000 0.0000 -1.0000
         1510  +vn 1.0000 0.0000 -0.0000
         1511  +vn 0.0000 -1.0000 -0.0000
         1512  +vn 0.0000 1.0000 -0.0000
         1513  +g screwdriver.005_Cube.017_gold
         1514  +usemtl gold
         1515  +s off
         1516  +f 335/767/66 336/768/66 338/769/66 337/770/66
         1517  +f 337/771/67 338/772/67 342/773/67 341/774/67
         1518  +f 341/774/68 342/773/68 340/775/68 339/776/68
         1519  +f 339/777/69 340/778/69 336/768/69 335/767/69
         1520  +f 337/779/70 341/780/70 339/781/70 335/782/70
         1521  +f 338/772/71 336/783/71 343/784/71 344/785/71
         1522  +f 343/786/69 346/787/69 350/788/69 347/789/69
         1523  +f 336/783/71 340/790/71 346/791/71 343/784/71
         1524  +f 342/773/71 338/772/71 344/785/71 345/792/71
         1525  +f 340/790/71 342/773/71 345/792/71 346/791/71
         1526  +f 350/793/71 349/794/71 353/795/71 354/796/71
         1527  +f 345/797/67 344/798/67 348/799/67 349/800/67
         1528  +f 346/801/68 345/797/68 349/800/68 350/802/68
         1529  +f 344/803/66 343/786/66 347/789/66 348/804/66
         1530  +f 352/805/68 351/806/68 355/807/68 356/808/68
         1531  +f 348/809/71 347/810/71 351/811/71 352/812/71
         1532  +f 347/810/71 350/793/71 354/796/71 351/811/71
         1533  +f 349/794/71 348/809/71 352/812/71 353/795/71
         1534  +f 351/806/67 354/813/67 358/814/67 355/807/67
         1535  +f 353/815/69 352/816/69 356/817/69 357/818/69
         1536  +f 354/819/66 353/815/66 357/818/66 358/820/66
         1537  +f 355/807/71 358/814/71 357/818/71 356/817/71
         1538  +o screwdriver.006_Cube.018
         1539  +v -0.233435 -0.263296 0.300201
         1540  +v -0.283396 -0.263296 0.300201
         1541  +v -0.283396 -0.263296 0.250240
         1542  +v -0.233435 -0.263296 0.250240
         1543  +v -0.233435 -0.270554 0.300201
         1544  +v -0.283396 -0.270554 0.300201
         1545  +v -0.283396 -0.270554 0.250240
         1546  +v -0.233435 -0.270554 0.250240
         1547  +vt 1.000000 1.000000
         1548  +vt 1.000000 0.000000
         1549  +vt 0.000000 0.000000
         1550  +vt 0.000000 1.000000
         1551  +vt 1.000000 1.000000
         1552  +vt 0.000000 1.000000
         1553  +vt 0.000000 0.000000
         1554  +vt 1.000000 0.000000
         1555  +vn 0.0000 -1.0000 0.0000
         1556  +vn 0.0000 1.0000 0.0000
         1557  +vn -1.0000 0.0000 0.0000
         1558  +vn 1.0000 0.0000 0.0000
         1559  +vn 0.0000 0.0000 1.0000
         1560  +vn 0.0000 0.0000 -1.0000
         1561  +g screwdriver.006_Cube.018_ink
         1562  +usemtl ink
         1563  +s off
         1564  +f 361/821/72 362/822/72 359/823/72 360/824/72
         1565  +f 365/825/73 364/826/73 363/827/73 366/828/73
         1566  +f 359/823/74 362/822/74 366/828/74 363/827/74
         1567  +f 361/821/75 360/824/75 364/826/75 365/825/75
         1568  +f 362/822/76 361/821/76 365/825/76 366/828/76
         1569  +f 360/824/77 359/823/77 363/827/77 364/826/77

Modified ores.lua from [caa4bf5370] to [dce6dabf6f].

   103    103   			replacements = {
   104    104   				{'bucket:bucket_water', 'bucket:bucket_empty'};
   105    105   			};
   106    106   		};
   107    107   	end
   108    108   	-- TODO: replace crafting recipe with kiln recipe
   109    109   	minetest.register_craft {
   110         -		output = screw.. ' 4';
          110  +		output = screw.. ' 8';
   111    111   		recipe = {
   112         -			{fragment,fragment,fragment};
   113         -			{'',      fragment,''};
   114         -			{'',      fragment,''};
          112  +			{'',          'xdecor:hammer',''};
          113  +			{        fragment,fragment,fragment};
          114  +			{'',              fragment,''};
          115  +		};
          116  +		replacements = {
          117  +			{'xdecor:hammer','xdecor:hammer'};
   115    118   		};
   116    119   	}
   117    120   	if not sorcery.compat.defp(ingot) then
   118    121   		-- TODO: remove instant_ores dependency
   119    122   		instant_ores.register_metal {
   120    123   			name = 'sorcery:' .. name;
   121    124   			description = sorcery.lib.str.capitalize(name);
................................................................................
   140    143   	minetest.register_craftitem(fragment, {
   141    144   		inventory_image = 'sorcery_' .. name .. '_fragment.png';
   142    145   		description = sorcery.lib.str.capitalize(name) .. ' Fragment';
   143    146   	})
   144    147   	minetest.register_craft {
   145    148   		type = 'cooking';
   146    149   		recipe = powder;
   147         -		cooktime = (metal.cooktime or 4) * 1.5;
          150  +		cooktime = (metal.cooktime or 4) * 0.25;
   148    151   		output = fragment;
   149    152   	}
   150    153   	minetest.register_craft {
   151    154   		type = 'cooking';
   152    155   		recipe = ingot;
   153         -		cooktime = (metal.cooktime or 4) / 2;
          156  +		cooktime = (metal.cooktime or 4) * 0.5;
   154    157   		output = fragment .. ' ' .. tostring(fragments_per_ingot);
   155    158   	}
   156    159   	do local rec = {}
   157    160   		for i=1,fragments_per_ingot do
   158    161   			rec[#rec+1]=fragment 
   159    162   		end
   160    163   		minetest.register_craft {
................................................................................
   177    180   		}))
   178    181   	end
   179    182   	if metal.sinter then
   180    183   		local powders = {}
   181    184   		for _,m in pairs(metal.sinter) do
   182    185   			powders[#powders+1] = 'sorcery:powder_' .. m
   183    186   		end
          187  +		if metal.sinter_catalyst then for _,m in pairs(metal.sinter_catalyst)
          188  +			do powders[#powders+1] = m end end
   184    189   		minetest.register_craft {
   185    190   			type = 'shapeless';
   186    191   			output = powder .. ' ' .. tostring(#powders);
   187    192   			recipe = powders;
   188    193   		};
   189    194   	end
   190    195   end

Added portal.lua version [021fb6f980].

            1  +local constants = {
            2  +	portal_max_height = 5;
            3  +	-- maximum y-distance between a portal pad and its
            4  +	-- corresponding reflector
            5  +	portal_min_height = 1;
            6  +	-- minimum y-distance. should probably be 2 but maybe
            7  +	-- half-size portals will be useful for transporting
            8  +	-- items or something
            9  +	portal_jump_time = 8;
           10  +	-- number of seconds until teleportation occurs
           11  +	portal_jump_cost_local = 1;
           12  +	-- energy required to make a jump from one portal
           13  +	-- to another on the local circuit
           14  +	portal_jump_cost_per_farcaster = 2;
           15  +	-- energy cost required to power each farcaster along
           16  +	-- the route to the final destination (remote only)
           17  +	portal_node_power = 0.1;
           18  +	-- amount of power needed for each portal node to operate
           19  +	-- and be reachable
           20  +}
           21  +minetest.register_node('sorcery:portal_pad', {
           22  +	description = 'Portal Pad';
           23  +	groups = {
           24  +		cracky = 2; sorcery_portal_node = 1;
           25  +		sorcery_magitech = 1;
           26  +	};
           27  +	tiles = {
           28  +		'sorcery_portal_pad_top.png';
           29  +		'sorcery_portal_pad_bottom.png';
           30  +		'sorcery_portal_pad_side.png';
           31  +		'sorcery_portal_pad_side.png';
           32  +		'sorcery_portal_pad_front.png^[transformFX';
           33  +		'sorcery_portal_pad_front.png';
           34  +	};
           35  +})
           36  +
           37  +minetest.register_node('sorcery:portal_reflector', {
           38  +	description = 'Portal Reflector';
           39  +	groups = {
           40  +		cracky = 2; sorcery_portal_node = 1;
           41  +		sorcery_magitech = 1;
           42  +	};
           43  +	tiles = {
           44  +		'sorcery_portal_pad_bottom.png';
           45  +		'sorcery_portal_pad_top.png';
           46  +		'sorcery_portal_pad_side.png^[transformFY';
           47  +		'sorcery_portal_pad_side.png^[transformFY';
           48  +		'sorcery_portal_pad_front.png^[transformFY^[transformFX';
           49  +		'sorcery_portal_pad_front.png^[transformFY';
           50  +	};
           51  +})
           52  +
           53  +
           54  +
           55  +local portal_composition = function(pos)
           56  +	-- make sure a reasonable amount of the block is loaded
           57  +	-- so we have a shot at finding a working portal
           58  +	minetest.load_area(
           59  +		vector.add(pos, {x =  5, y =  1 + constants.portal_max_height, z =  5}),
           60  +		vector.add(pos, {x = -5, y = -1 - constants.portal_max_height, z = -5})
           61  +	)
           62  +	-- starting at a portal node, search connected blocks
           63  +	-- recursively to locate portal pads and their paired
           64  +	-- partners. return a table characterizing the portal
           65  +	-- return false if no portal found
           66  +	
           67  +	-- first search immediate neighbors. the portal node
           68  +	-- can be connected to either reflectors or pads
           69  +	local startpoint, startwithpads
           70  +	for _, d in pairs(sorcery.lib.node.offsets.neighbors) do
           71  +		local sum = vector.add(pos,d)
           72  +		local name = minetest.get_node(sum).name
           73  +		if name == 'sorcery:portal_pad' then
           74  +			startwithpads = true
           75  +		elseif name == 'sorcery:portal_reflector' then
           76  +			startwithpads = false
           77  +		else goto skip end
           78  +		startpoint = sum
           79  +		do break end
           80  +	::skip::end
           81  +
           82  +	-- if startpoint is not set, a valid portal was not found
           83  +	if not startpoint then return nil end
           84  +	local search, partner
           85  +	if startwithpads then search = 'sorcery:portal_pad'
           86  +	                     partner = 'sorcery:portal_reflector'
           87  +	                 else search = 'sorcery:portal_reflector'
           88  +	                     partner = 'sorcery:portal_pad' end
           89  +
           90  +	local firsthalf = sorcery.lib.node.amass(startpoint,{search},sorcery.lib.node.offsets.nextto)
           91  +	local min,max,maxheight = nil, nil, 0
           92  +	local telepairs = {}
           93  +	for pos in pairs(firsthalf) do
           94  +		local found = false
           95  +		for i=constants.portal_min_height,constants.portal_max_height do
           96  +			local p = vector.add(pos, {y=(startwithpads and i or 0-i),x=0,z=0})
           97  +			local n = minetest.get_node(p).name
           98  +			if n == partner then
           99  +				found = true
          100  +				maxheight = math.max(maxheight, i)
          101  +				telepairs[#telepairs + 1] = {
          102  +					pad = startwithpads and pos or p;
          103  +					reflector = startwithpads and p or pos;
          104  +					height = i;
          105  +				}
          106  +			elseif n ~= 'air' and minetest.get_item_group(n,'air') == 0 then
          107  +				goto skippad
          108  +			end
          109  +		end
          110  +		if found then
          111  +			if min then min = {
          112  +				x = math.min(min.x, pos.x);
          113  +				y = math.min(min.y, pos.y);
          114  +				z = math.min(min.z, pos.z);
          115  +			} else min = pos end
          116  +			if max then max = {
          117  +				x = math.max(max.x, pos.x);
          118  +				y = math.max(max.y, pos.y);
          119  +				z = math.max(max.z, pos.z);
          120  +			} else max = pos end
          121  +		end
          122  +	::skippad::end
          123  +
          124  +	if #telepairs == 0 then return nil end
          125  +
          126  +	return {
          127  +		nodes = telepairs;
          128  +		dimensions = {
          129  +			padmin = min;
          130  +			padmax = max;
          131  +			height = maxheight;
          132  +		};
          133  +	}
          134  +end
          135  +
          136  +local caster_farnet = function(pos)
          137  +	local tune = sorcery.attunement.verify(pos)
          138  +	if not tune then return nil end 
          139  +
          140  +	local partner = minetest.get_node(tune.partner)
          141  +	if partner.name ~= 'sorcery:farcaster' then return nil end
          142  +
          143  +	local ptune = sorcery.attunement.verify(tune.partner)
          144  +	if ptune.code == tune.code and vector.equals(ptune.partner, pos) then
          145  +		return tune.partner
          146  +	end
          147  +	return nil
          148  +end
          149  +
          150  +local portal_context = {
          151  +	users = {}
          152  +}
          153  +
          154  +local portal_circuit = function(start)
          155  +	local circuit = {}
          156  +	local network = sorcery.farcaster.junction(start,constants.portal_jump_cost_local) -- get the ley of the land. GEDDIT)
          157  +	for _, n in pairs(network) do
          158  +		for _, d in pairs(n.caps.net.devices.consume) do
          159  +			if d.id == 'sorcery:portal_node' and portal_composition(d.pos) then
          160  +				circuit[#circuit+1] = {
          161  +					pos = d.pos;
          162  +					hops = n.hops;
          163  +					route = n.route;
          164  +				}
          165  +				print(' ! found portal node',d.pos)
          166  +			else
          167  +				print('   -- skipping node',d.pos,d.id)
          168  +			end
          169  +		end
          170  +	end
          171  +	return circuit
          172  +end
          173  +
          174  +local portal_disposition = function(dev)
          175  +	local dim = vector.subtract(dev.dimensions.padmax, dev.dimensions.padmin)
          176  +	local radius = math.max(dim.x, dim.z, dev.dimensions.height)
          177  +	local center = vector.add(vector.divide(dim,2), dev.dimensions.padmin)
          178  +	local objs = minetest.get_objects_inside_radius(center, radius)
          179  +	local users = {}
          180  +	local occupads = {}
          181  +	for _,obj in pairs(objs) do
          182  +		if minetest.is_player(obj) then
          183  +			local pos = obj:get_pos()
          184  +			for _,n in pairs(dev.nodes) do
          185  +				-- is the player between a pad and reflector pair?
          186  +				if math.abs(pos.x - n.pad.x) < 0.5 and
          187  +				   math.abs(pos.z - n.pad.z) < 0.5 and
          188  +				   pos.y >= n.pad.y and pos.y <= n.reflector.y then
          189  +				   users[#users+1] = {
          190  +					   object = obj;
          191  +					   slot = n;
          192  +				   }
          193  +				   occupads[n] = true
          194  +				   goto skip
          195  +			   end
          196  +			end
          197  +		end
          198  +	::skip::end
          199  +
          200  +	local freepads = {}
          201  +	for _,n in pairs(dev.nodes) do
          202  +		if not occupads[n] then
          203  +			freepads[#freepads+1] = n
          204  +		end
          205  +	end
          206  +
          207  +	return {
          208  +		users = users;
          209  +		freepads = freepads;
          210  +		radius = radius;
          211  +		center = center;
          212  +		bounds = dim;
          213  +	}
          214  +end
          215  +
          216  +local portal_destination_evaluate = function(circuit,pos)
          217  +	-- evaluation of the local network occurs before this function
          218  +	-- is ever even called, so we only need to worry about the
          219  +	-- farcaster-related transmission costs
          220  +	for i,c in pairs(circuit) do
          221  +		if vector.equals(c.pos,pos) then
          222  +			print('found destination in circuit table',i,dump(c))
          223  +			-- the destination is listed in the circuit table
          224  +			for j,r in pairs(c.route) do
          225  +				local nc = sorcery.ley.netcaps(pos,1)
          226  +				print('checking route for sufficient energy to power farcasters', j, nc.freepower)
          227  +				if nc.freepower < constants.portal_jump_cost_per_farcaster then
          228  +					return false -- only one route to any given portal node
          229  +					-- will be listed in the circuit table, so bail early
          230  +					-- maybe in the future farcasters should charge up,
          231  +					-- and power should be deducted when they are used?
          232  +				end
          233  +			end
          234  +			-- we've tested every leg of the route, sufficient power is
          235  +			-- available
          236  +			return true
          237  +		end
          238  +	end
          239  +	return false
          240  +end
          241  +
          242  +local portal_pick_destination = function(dev,circuit,partner)
          243  +	if partner then
          244  +		print('paired: evaluating partner')
          245  +		if portal_destination_evaluate(circuit,partner)
          246  +			then return partner end
          247  +		print('partner failed eval')
          248  +	end
          249  +
          250  +	local scrambled = sorcery.lib.tbl.scramble(circuit)
          251  +	for i=1,#scrambled do
          252  +		print('evaluating destination',i,dump(scrambled[i]))
          253  +		if portal_destination_evaluate(circuit,scrambled[i].pos)
          254  +			then return scrambled[i].pos end
          255  +		print('eval failed')
          256  +	end
          257  +	print('no viable destinations in net')
          258  +end
          259  +
          260  +-- minetest.register_lbm {
          261  +-- 	name = 'sorcery:activate_portals';
          262  +-- 	label = 'activate portals';
          263  +-- 	run_at_every_load = true;
          264  +-- 	nodenames = { 'sorcery:portal_node' };
          265  +-- 	action = function(pos,node)
          266  +-- 		minetest.get_node_timer(pos).start(2)
          267  +-- 	end;
          268  +-- }
          269  +
          270  +minetest.register_node('sorcery:portal_node', {
          271  +	description = 'Portal Node';
          272  +	groups = {
          273  +		cracky = 2; sorcery_portal_node = 2;
          274  +		sorcery_ley_device = 1;
          275  +		sorcery_magitech = 1;
          276  +	};
          277  +	on_construct = function(pos)
          278  +		local meta = minetest.get_meta(pos)
          279  +		meta:set_string('infotext','Portal Node')
          280  +		minetest.get_node_timer(pos):start(1)
          281  +	end;
          282  +	on_timer = function(pos,delta)
          283  +		local dev = portal_composition(pos)
          284  +		if not dev then return false end
          285  +		local dsp = portal_disposition(dev)
          286  +		local crc = portal_circuit(pos)
          287  +		local cap = sorcery.ley.netcaps(pos,delta)
          288  +		local tune = sorcery.attunement.verify(pos)
          289  +		local partner -- raw position of partner node, if any
          290  +		if tune and tune.partner then
          291  +			minetest.load_area(tune.partner)
          292  +			-- we are attuned to a partner, but is it in the circuit?
          293  +			for _,v in pairs(crc) do
          294  +				if vector.equals(v.pos,tune.partner) then
          295  +					print('found partner in circuit')
          296  +					partner = tune.partner
          297  +					break
          298  +				end
          299  +			end
          300  +		end
          301  +
          302  +		print("power reqs",cap.self.minpower,cap.self.powerdraw)
          303  +		if cap.self.minpower ~= cap.self.powerdraw then
          304  +			print("not enough power")
          305  +			return true
          306  +		end
          307  +
          308  +		-- clean out user table
          309  +		for name,user in pairs(portal_context.users) do
          310  +			if user and vector.equals(user.portal, pos) then
          311  +				local found = false
          312  +				for _,u in pairs(dsp.users) do
          313  +					if u.object:get_player_name() == name then
          314  +						found = true
          315  +					end
          316  +				end
          317  +				if not found then
          318  +					portal_context.users[name] = nil
          319  +				end
          320  +			end
          321  +		end
          322  +
          323  +		-- one user per pad only!
          324  +		for _,n in pairs(dev.nodes) do
          325  +			for _,u in pairs(dsp.users) do
          326  +				if u.slot == n then
          327  +					local pname = u.object:get_player_name()
          328  +					if not portal_context.users[pname] then
          329  +						portal_context.users[pname] = { time = 0, portal = pos } end
          330  +					local user = portal_context.users[pname]
          331  +					if not vector.equals(pos,user.portal) then
          332  +						user.time = 0
          333  +						user.portal = pos
          334  +					end
          335  +					local cap = sorcery.ley.netcaps(pos,delta)
          336  +					local jc = (constants.portal_jump_cost_local*delta)
          337  +					print('free power',cap.freepower,jc)
          338  +					if not user.dest and cap.freepower >= jc  then
          339  +						user.dest = portal_pick_destination(dev,crc,partner)
          340  +					else
          341  +						print('powerdraw',cap.self.powerdraw)
          342  +					end
          343  +					if not user.dest then goto skippad else
          344  +						minetest.load_area(user.dest)
          345  +					end
          346  +					local fac = (user.time / constants.portal_jump_time);
          347  +					minetest.add_particlespawner {
          348  +						time = 1, amount = 100 + (fac * 200);
          349  +						minsize = 0.2 + fac*0.7, maxsize = 0.4 + fac*0.9;
          350  +						minvel = {y = 0.2, x=0,z=0}, maxvel = {y = 0.5, x=0,z=0};
          351  +						minacc = {y = 0.0, x=0,z=0}, maxacc = {y = 0.3, x=0,z=0};
          352  +						minpos = vector.add(n.pad,{x = -0.5, y = 0.5, z = -0.5});
          353  +						maxpos = vector.add(n.pad,{x =  0.5, y = 0.5, z =  0.5});
          354  +						texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(255,119,255)):render();
          355  +						glow = 14;
          356  +						minexptime = 1, maxexptime = 1.3;
          357  +						animation = {
          358  +							type = 'vertical_frames';
          359  +							aspect_w = 16, aspect_h = 16;
          360  +						};
          361  +					}
          362  +					if user.time >= (constants.portal_jump_time * 0.5) then
          363  +						minetest.add_particlespawner {
          364  +							time = 2;
          365  +							amount = 500 * fac;
          366  +							minpos = { x = -0.3, y =    0, z = -0.3 };
          367  +							maxpos = { x =  0.3, y =  1.5, z =  0.3 };
          368  +							minvel = { x = -0.3, y =  0.4, z = -0.3 };
          369  +							maxvel = { x =  0.3, y =  0.6, z =  0.3 };
          370  +							maxacc = { x =    0, y =  0.5, z =    0 };
          371  +							texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(255,144,226)):render();
          372  +							minexptime = 1.5;
          373  +							maxexptime = 2;
          374  +							minsize = 0.4;
          375  +							maxsize = 1.6 * fac;
          376  +							glow = 14;
          377  +							attached = u.object;
          378  +							animation = {
          379  +								type = 'vertical_frames', length = 2.1;
          380  +								aspect_w = 16, aspect_h = 16;
          381  +							};
          382  +						}
          383  +					end
          384  +					if user.time >= constants.portal_jump_time then
          385  +						local dd = portal_disposition(portal_composition(user.dest))
          386  +						if #dd.freepads > 0 then
          387  +							local destpad = dd.freepads[math.random(#dd.freepads)].pad
          388  +							local rng = function(min,max)
          389  +								return (math.random() * (max - min)) + min
          390  +							end
          391  +							local oldpos = u.object:get_pos()
          392  +							local colors = {
          393  +								{255,95,201}; {199,95,255};
          394  +								{142,95,255}; {255,95,154};
          395  +							}
          396  +							for i = 1,128 do
          397  +								local vel = {
          398  +									x = rng(-0.6,1.2), y = rng(-0.6,1.2), z = rng(-0.6,1.2)
          399  +								}
          400  +								local life = rng(0.5,5)
          401  +								minetest.add_particle {
          402  +									pos = vector.add(oldpos, {x = rng(-0.3,0.3), y = rng(0,1.5), z = rng(-0.3,0.3)});
          403  +									velocity = vel;
          404  +									expirationtime = life;
          405  +									acceleration = vector.multiply(vel, -0.1);
          406  +									texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(colors[math.random(#colors)]):brighten(rng(1.0,1.4))):render();
          407  +									glow = 14;
          408  +									animation = {
          409  +										type = 'vertical_frames', length = life + 0.1;
          410  +										aspect_w = 16, aspect_h = 16;
          411  +									};
          412  +								}
          413  +							end
          414  +							u.object:set_pos(vector.add(destpad, {y=0.5,z=0,x=0}))
          415  +							user.dest = nil
          416  +							portal_context[pname] = nil
          417  +						end
          418  +					else
          419  +						user.time = user.time + delta
          420  +					end
          421  +
          422  +					break
          423  +				end
          424  +			end
          425  +		::skippad::end
          426  +		return true
          427  +	end;
          428  +	tiles = {
          429  +		'sorcery_portal_top.png';
          430  +		'sorcery_portal_top.png';
          431  +		'sorcery_portal_side.png';
          432  +		'sorcery_portal_side.png';
          433  +		'sorcery_portal_front.png';
          434  +		'sorcery_portal_front.png';
          435  +	};
          436  +	_sorcery = {
          437  +		attune = {
          438  +			class = 'sorcery:portal';
          439  +			accepts = 'sorcery:portal';
          440  +			source = true, target = true;
          441  +			reciprocal = false;
          442  +		};
          443  +		ley = {
          444  +			mode = 'consume', affinity = {'mandatic'};
          445  +			power = function(pos,delta)
          446  +				-- return power use if device is currently in process
          447  +				-- of teleporting a player; otherwise, return 0
          448  +				local cost = constants.portal_node_power
          449  +				for _,u in pairs(portal_context.users) do
          450  +					if u.dest and vector.equals(u.portal, pos) then
          451  +						print('user is on pad',dump(pos))
          452  +						cost = cost + constants.portal_jump_cost_local
          453  +					end
          454  +				end
          455  +				return cost * delta
          456  +			end;
          457  +		};
          458  +		
          459  +		on_leychange = function(pos) minetest.get_node_timer(pos):start(1) end;
          460  +	};
          461  +})
          462  +
          463  +sorcery.portal = {
          464  +	composition = portal_composition;
          465  +	disposition = portal_disposition;
          466  +	circuit = portal_circuit;
          467  +}

Modified potions.lua from [fc0276bae8] to [f457c3868d].

    54     54   	minetest.register_craftitem('sorcery:' .. name, extra)
    55     55   end
    56     56   
    57     57   sorcery.register_potion('blood', 'Blood', 'A bottle of sacrificial blood, imbued\nwith stolen life force', u.color(219,19,14))
    58     58   sorcery.register_potion('potion_water', 'Water Bottle', 'A bottle of plain water', u.color(43,90,162))
    59     59   sorcery.register_potion('holy_water', 'Holy Water','A bottle of consecrated water',u.color(94,138,206),'sparkle',6)
    60     60   
    61         -local create_infusion_recipe = function(id,potion,default_basis)
           61  +local create_infusion_recipe = function(id,potion,default_basis,proto)
    62     62   	if potion.infusion then
    63     63   		sorcery.data.register.infusion {
    64     64   			infuse = potion.infusion;
    65     65   			into = potion.basis or default_basis;
    66     66   			output = 'sorcery:' .. id;
           67  +			_proto = proto;
    67     68   		}
    68     69   	end
    69     70   end
    70     71   
    71     72   for n,v in pairs(sorcery.data.potions) do
    72     73   	local color = u.color(v.color)
    73     74   	local kind = v.style
    74     75   	local glow = v.glow
    75     76   	local id = 'potion_' .. string.lower(n)
    76     77   	local desc = 'A ' .. ((glow and 'glowing ') or '') ..
    77     78   		'bottle of ' .. string.lower(n) .. 
    78     79   		((kind == 'sparkle' and ', fiercely bubbling') or '') ..
    79     80   		' liquid'
    80         -	sorcery.register_potion(id, n .. ' Potion', desc, color, kind, glow, {
           81  +	local fullname = n .. ' Potion'
           82  +	sorcery.register_potion(id, fullname, desc, color, kind, glow, {
    81     83   		_proto = v;
    82     84   		groups = {
    83     85   			sorcery_potion = 1;
    84     86   			sorcery_magical = 1;
    85     87   		};
    86     88   	})
    87         -	create_infusion_recipe(id,v,'sorcery:potion_serene')
           89  +	create_infusion_recipe(id,v,'sorcery:potion_serene',{data=v,name=fullname})
    88     90   end
    89     91   
    90     92   for n,potion in pairs(sorcery.data.draughts) do
    91     93   	local name = 'draught_' .. n
    92     94   	local behavior = {
    93     95   		_proto = potion;
    94     96   		groups = {
................................................................................
   129    131   				else
   130    132   					minetest.add_item(user.get_pos(), ret)
   131    133   				end
   132    134   			end
   133    135   			return stack
   134    136   		end
   135    137   	}
   136         -	sorcery.register_potion(name, potion.name .. ' Draught',
          138  +	local fullname = potion.name .. ' Draught'
          139  +	sorcery.register_potion(name, fullname,
   137    140   		potion.desc,
   138    141   		u.color(potion.color),
   139    142   		potion.style or 'dull',
   140    143   		potion.glow or 0,
   141    144   		behavior)
   142         -	create_infusion_recipe(name,potion,'sorcery:potion_luminous')
          145  +	create_infusion_recipe(name,potion,'sorcery:potion_luminous',{data=potion,name=fullname})
   143    146   end
   144    147   
   145    148   for n,elixir in pairs(sorcery.data.elixirs) do
   146    149   	local color = u.color(elixir.color)
   147    150   	local id = 'elixir_' .. string.lower(n)
   148         -	sorcery.register_potion(id, 'Elixir of ' .. n, nil, color, 'dull', false, {
          151  +	local fullname = 'Elixir of ' .. n
          152  +	sorcery.register_potion(id, fullname, nil, color, 'dull', false, {
   149    153   		_proto = elixir;
   150    154   		groups = {
   151    155   			sorcery_elixir = 1;
   152    156   			sorcery_magical = 1;
   153    157   		};
   154    158   	})
   155         -	create_infusion_recipe(id,elixir,'sorcery:potion_misty')
          159  +	create_infusion_recipe(id,elixir,'sorcery:potion_misty',{data=elixir,name=fullname})
   156    160   end
   157    161   
   158    162   for n,v in pairs(sorcery.data.oils) do
   159    163   	local color = u.color(v.color)
   160    164   	local kind = v.style
   161    165   	local id = 'oil_' .. n
   162    166   	n = v.name or u.str.capitalize(n)
................................................................................
   165    169   	})
   166    170   end
   167    171   
   168    172   for n,v in pairs(sorcery.data.greases) do
   169    173   	local color = u.color(v.color)
   170    174   	local kind = v.style
   171    175   	sorcery.register_oil('grease_' .. n, u.str.capitalize(n) .. ' Grease', nil, color, kind, {
   172         -		groups = { sorcery_grease = 2 }
          176  +		groups = { sorcery_grease = 1 }
   173    177   	})
   174    178   end
   175    179   
   176    180   for n,v in pairs(sorcery.data.philters) do
   177    181   	local color = u.color(v.color)
   178    182   	local id = 'philter_' .. n
   179    183   	local name = v.name or u.str.capitalize(n)
   180         -	sorcery.register_potion(id, name .. ' Philter', v.desc, color, 'sparkle',v.glow or 4, {
          184  +	local fullname = name .. ' Philter'
          185  +	sorcery.register_potion(id, fullname, v.desc, color, 'sparkle',v.glow or 4, {
   181    186   		_proto = v;
   182    187   		_protoname = n;
   183    188   		groups = {
   184    189   			sorcery_magical = 1;
   185    190   			sorcery_philter = 1;
   186    191   		};
   187    192   	})
   188         -	create_infusion_recipe(id,v,'sorcery:potion_viscous')
          193  +	create_infusion_recipe(id,v,'sorcery:potion_viscous',{data=v,name=fullname})
   189    194   end
   190    195   
   191    196   for n,v in pairs(sorcery.data.extracts) do
   192    197   	local item = v[1]
   193    198   	local color = u.color(v[2])
   194    199   	local name = 'extract_' .. n
   195         -	sorcery.register_potion(name, u.str.capitalize(n) .. ' Extract', nil, color, 'sparkle', false)
          200  +	sorcery.register_potion(name, u.str.capitalize(n) .. ' Extract', nil, color, 'sparkle', false, {
          201  +		groups = {
          202  +			sorcery_extracts = 1;
          203  +		};
          204  +	})
   196    205   
   197    206   	local add_alcohol = function(booze)
   198    207   		minetest.register_craft {
   199    208   			type = "shapeless";
   200    209   			recipe = {
   201    210   				booze;
   202    211   				item, item, item;

Modified recipes.lua from [c451769631] to [e76efbfb0c].

   247    247   		{ 'default:tin_ingot', 'bucket:bucket_empty', 'default:tin_ingot'};
   248    248   		{ 'default:bronze_ingot', 'sorcery:infuser_chamber', 'default:copper_ingot'};
   249    249   		{ 'sorcery:infuser_tube', 'sorcery:infuser_tube', 'sorcery:infuser_tube' };
   250    250   	};
   251    251   	output = "sorcery:infuser";
   252    252   }
   253    253   
          254  +minetest.register_craft {
          255  +	output = "sorcery:displacer";
          256  +	recipe = {
          257  +		{'sorcery:platinum_ingot','sorcery:leyline_stabilizer','sorcery:platinum_ingot'};
          258  +		{'sorcery:inverter_coil','sorcery:core_syncretic','sorcery:inverter_coil'};
          259  +		{'sorcery:platinum_ingot','default:chest','sorcery:platinum_ingot'};
          260  +	};
          261  +}
   254    262   
   255         ----- altar
   256         --- candles
          263  +minetest.register_craft {
          264  +	output = "sorcery:displacement_node";
          265  +	recipe = {
          266  +		{'sorcery:platinum_ingot','sorcery:screw_tungsten','sorcery:platinum_ingot'};
          267  +		{'basic_materials:copper_wire','sorcery:core_syncretic','doors:trapdoor_steel'};
          268  +		{'sorcery:platinum_ingot','sorcery:screw_tungsten','sorcery:platinum_ingot'};
          269  +	};
          270  +	replacements = {
          271  +		{'basic_materials:copper_wire','basic_materials:empty_spool'};
          272  +	};
          273  +}
          274  +
          275  +minetest.register_craft {
          276  +	output = 'sorcery:raycaster';
          277  +	recipe = {
          278  +		{'sorcery:gem_amethyst', 'sorcery:gem_amethyst', 'sorcery:gem_amethyst'};
          279  +		{'default:gold_ingot','sorcery:beam_generator','default:gold_ingot'};
          280  +		{'sorcery:gem_amethyst', 'sorcery:gem_amethyst', 'sorcery:gem_amethyst'};
          281  +	};
          282  +}
          283  +
          284  +minetest.register_craft {
          285  +	output = 'sorcery:tuning_disc';
          286  +	recipe = {
          287  +		{'sorcery:inverter_coil','sorcery:silver_ingot',''};
          288  +		{'sorcery:leyline_stabilizer','sorcery:silver_ingot','sorcery:gem_emerald'};
          289  +		{'sorcery:inverter_coil','sorcery:silver_ingot',''};
          290  +	};
          291  +}
          292  +
          293  +minetest.register_craft {
          294  +	output = 'sorcery:farcaster';
          295  +	recipe = {
          296  +		{'default:gold_ingot','sorcery:iridium_ingot','default:gold_ingot'};
          297  +		{'sorcery:core_mandatic','default:diamondblock','sorcery:tuning_disc'};
          298  +		{'default:gold_ingot','sorcery:iridium_ingot','default:gold_ingot'};
          299  +	};
          300  +}
          301  +
          302  +minetest.register_craft {
          303  +	output = 'sorcery:portal_node';
          304  +	recipe = {
          305  +		{'sorcery:tungsten_ingot','sorcery:core_mandatic','sorcery:tungsten_ingot'};
          306  +		{'sorcery:aluminum_ingot','sorcery:platinumblock','sorcery:aluminum_ingot'};
          307  +		{'sorcery:tungsten_ingot','sorcery:core_mandatic','sorcery:tungsten_ingot'};
          308  +	};
          309  +}
          310  +
          311  +minetest.register_craft {
          312  +	output = 'sorcery:portal_reflector';
          313  +	recipe = {
          314  +		{'basic_materials:steel_bar','default:tin_ingot','basic_materials:steel_bar'};
          315  +		{'sorcery:gem_amethyst','sorcery:inverter_coil','sorcery:gem_amethyst'};
          316  +		{'basic_materials:steel_bar','xpanes:bar_flat','basic_materials:steel_bar'};
          317  +	}
          318  +}
          319  +
          320  +minetest.register_craft {
          321  +	output = 'sorcery:portal_pad';
          322  +	recipe = {
          323  +		{'basic_materials:steel_bar','xpanes:bar_flat','basic_materials:steel_bar'};
          324  +		{'sorcery:gem_amethyst','sorcery:beam_generator','sorcery:gem_amethyst'};
          325  +		{'basic_materials:steel_bar','default:tin_ingot','basic_materials:steel_bar'};
          326  +	}
          327  +}
          328  +
          329  +minetest.register_craftitem('sorcery:tuning_disc',{
          330  +	description = 'Tuning Disc';
          331  +	inventory_image = 'sorcery_tuning_disc.png';
          332  +	groups = {
          333  +		sorcery_magitech = 1; metal = 1;
          334  +	};
          335  +});
          336  +
   257    337   minetest.register_craftitem('sorcery:core_counterpraxic',{
   258    338   	description = 'Counterpraxis Core';
   259    339   	inventory_image = 'sorcery_core_counterpraxic.png';
          340  +	groups = {
          341  +		sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1;
          342  +	};
          343  +});
          344  +
          345  +minetest.register_craftitem('sorcery:core_mandatic',{
          346  +	description = 'Mandatic Core';
          347  +	inventory_image = 'sorcery_core_mandatic.png';
          348  +	groups = {
          349  +		sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1;
          350  +	};
          351  +});
          352  +
          353  +minetest.register_craftitem('sorcery:core_syncretic',{
          354  +	description = 'Syncresis Core';
          355  +	inventory_image = 'sorcery_core_sycretic.png';
          356  +	groups = {
          357  +		sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1;
          358  +	};
   260    359   });
   261         ---
          360  +
   262    361   minetest.register_craftitem('sorcery:suppression_matrix',{
   263    362   	description = 'Suppression Matrix';
   264    363   	inventory_image = 'sorcery_suppression_matrix.png';
          364  +	groups = {
          365  +		sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1;
          366  +	};
   265    367   });
   266    368   
   267    369   minetest.register_craftitem('sorcery:inverter_coil',{
   268    370   	description = 'Inverter Coil';
   269    371   	inventory_image = 'sorcery_inverter_coil.png';
          372  +	groups = {
          373  +		sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1;
          374  +	};
   270    375   });
   271    376   
   272    377   minetest.register_craftitem('sorcery:beam_generator',{
   273    378   	description = 'Beam Generator';
   274    379   	inventory_image = 'sorcery_beam_generator.png';
          380  +	groups = {
          381  +		sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1;
          382  +	};
   275    383   });
   276    384   
   277    385   minetest.register_craftitem('sorcery:leyline_stabilizer',{
   278    386   	description = 'Leyline Stabilizer';
   279    387   	inventory_image = 'sorcery_leyline_stabilizer.png';
          388  +	groups = {
          389  +		sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1;
          390  +	};
   280    391   });
   281    392   
   282    393   minetest.register_craftitem('sorcery:field_emitter',{
   283    394   	description = 'Field Emitter';
   284    395   	inventory_image = 'sorcery_field_emitter.png';
          396  +	groups = {
          397  +		sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1;
          398  +	};
   285    399   })
   286    400   
   287    401   minetest.register_craft {
   288    402   	output = 'sorcery:leyline_stabilizer';
   289    403   	recipe = {
   290    404   		{'basic_materials:copper_wire','group:sorcery_ley_cable','basic_materials:copper_wire'};
   291    405   		{'sorcery:grease_neutralizing','group:sorcery_ley_cable','sorcery:grease_neutralizing'};
................................................................................
   323    437   	output = 'sorcery:core_counterpraxic';
   324    438   	recipe = {
   325    439   		{'sorcery:gem_ruby_shard','sorcery:tungsten_ingot','sorcery:gem_ruby_shard'};
   326    440   		{'sorcery:tungsten_ingot','sorcery:gem_emerald','sorcery:tungsten_ingot'};
   327    441   		{'sorcery:gem_ruby_shard','sorcery:tungsten_ingot','sorcery:gem_ruby_shard'};
   328    442   	};
   329    443   }
          444  +
          445  +minetest.register_craft {
          446  +	output = 'sorcery:core_syncretic';
          447  +	recipe = {
          448  +		{'sorcery:gem_sapphire_shard','default:gold_ingot','sorcery:gem_sapphire_shard'};
          449  +		{'default:gold_ingot','sorcery:gem_diamond','default:gold_ingot'};
          450  +		{'sorcery:gem_sapphire_shard','default:gold_ingot','sorcery:gem_sapphire_shard'};
          451  +	};
          452  +}
          453  +
          454  +minetest.register_craft {
          455  +	output = 'sorcery:core_mandatic';
          456  +	recipe = {
          457  +		{'sorcery:gem_amethyst_shard','sorcery:silver_ingot','sorcery:gem_amethyst_shard'};
          458  +		{'sorcery:silver_ingot','sorcery:gem_sapphire','sorcery:silver_ingot'};
          459  +		{'sorcery:gem_amethyst_shard','sorcery:silver_ingot','sorcery:gem_amethyst_shard'};
          460  +	};
          461  +}
   330    462   
   331    463   minetest.register_craft {
   332    464   	output = 'sorcery:inverter_coil';
   333    465   	recipe = {
   334    466   		{'sorcery:screw_platinum','basic_materials:steel_wire','sorcery:screw_platinum'};
   335    467   		{'basic_materials:copper_wire','default:tin_ingot','basic_materials:copper_wire'};
   336    468   		{'sorcery:screw_platinum','basic_materials:steel_wire','sorcery:screw_platinum'};
................................................................................
   372    504   		{'default:steel_ingot','default:furnace','default:steel_ingot'};
   373    505   	};
   374    506   	replacements = {
   375    507   		{'basic_materials:copper_wire', 'basic_materials:empty_spool'};
   376    508   	};
   377    509   }
   378    510   
          511  +---- altar
   379    512   minetest.register_craftitem('sorcery:candle', {
   380    513   	-- TODO make candle node
   381    514   	inventory_image = 'sorcery_candle.png';
   382    515   	description = 'Votive Candle';
   383    516   	groups = {
   384    517   		candle = 1;
   385    518   	};

Modified textures/sorcery_core_counterpraxic.png from [39479c1b28] to [e3aaf06222].

cannot compute difference between binary files

Added textures/sorcery_core_mandatic.png version [b6c2d06b72].

cannot compute difference between binary files

Added textures/sorcery_core_syncretic.png version [086b79dff1].

cannot compute difference between binary files

Added textures/sorcery_farcaster_linear_bottom.png version [118744afe2].

cannot compute difference between binary files

Added textures/sorcery_farcaster_linear_side.png version [408a859773].

cannot compute difference between binary files

Added textures/sorcery_farcaster_linear_top.png version [4fda01e825].

cannot compute difference between binary files

Added textures/sorcery_farcaster_nonlocal_back.png version [2b03768188].

cannot compute difference between binary files

Added textures/sorcery_farcaster_nonlocal_front.png version [c925e1401d].

cannot compute difference between binary files

Added textures/sorcery_farcaster_nonlocal_side.png version [c091ae564e].

cannot compute difference between binary files

Added textures/sorcery_farcaster_nonlocal_top.png version [b273235492].

cannot compute difference between binary files

Modified textures/sorcery_field_emitter.png from [fdceff2168] to [aee8d20a12].

cannot compute difference between binary files

Added textures/sorcery_portal_front.png version [64f724c208].

cannot compute difference between binary files

Added textures/sorcery_portal_pad_bottom.png version [be4807eea7].

cannot compute difference between binary files

Added textures/sorcery_portal_pad_front.png version [1bc5617d20].

cannot compute difference between binary files

Added textures/sorcery_portal_pad_side.png version [c75e2555a9].

cannot compute difference between binary files

Added textures/sorcery_portal_pad_top.png version [accc2af1a9].

cannot compute difference between binary files

Added textures/sorcery_portal_side.png version [df1d5fcacb].

cannot compute difference between binary files

Added textures/sorcery_portal_top.png version [ce9e9950a7].

cannot compute difference between binary files

Added textures/sorcery_tuning_disc.png version [babfdd1af1].

cannot compute difference between binary files

Added textures/sorcery_vice.png version [949f16d3cc].

cannot compute difference between binary files

Added textures/sorcery_vidrium_fragment.png version [bb35934799].

cannot compute difference between binary files

Added textures/sorcery_vidrium_powder.png version [a51f419db4].

cannot compute difference between binary files

Modified tnodes.lua from [27d6ea2995] to [a23f444ae8].

     3      3   		drawtype = 'airlike';
     4      4   		light_source = 5 + math.ceil(i * (11/minetest.LIGHT_MAX));
     5      5   		sunlight_propagates = true;
     6      6   		buildable_to = true;
     7      7   		pointable = false;
     8      8   		walkable = false;
     9      9   		floodable = true;
           10  +		groups = { air = 1; sorcery_air = 1; };
    10     11   		on_construct = function(pos)
    11     12   			local meta = minetest.get_meta(pos)
    12     13   			meta:set_float('duration',10)
    13     14   			meta:set_float('timeleft',10)
    14     15   			meta:set_int('power',minetest.LIGHT_MAX)
    15     16   			minetest.get_node_timer(pos):start(1)
    16     17   		end;

Modified wands.lua from [12fce408ba] to [4ea63112cb].

    12     12   	materials = {
    13     13   		wood = {
    14     14   			pine = {
    15     15   				tex = u.image('default_pine_wood.png');
    16     16   			};
    17     17   			apple = {
    18     18   				tex = u.image('default_wood.png');
    19         -				tree = 'default:wood';
    20         -				plank = 'default:plank';
           19  +				tree = 'default:tree';
           20  +				plank = 'default:wood';
    21     21   			};
    22     22   			acacia = {
    23     23   				tex = u.image('default_acacia_wood.png');
    24     24   			};
    25     25   			aspen = {
    26     26   				tex = u.image('default_aspen_wood.png');
    27     27   			};
................................................................................
    30     30   				tree = 'default:jungletree';
    31     31   				plank = 'default:junglewood';
    32     32   			};
    33     33   		};
    34     34   		core = {
    35     35   			obsidian = {
    36     36   				item = 'default:obsidian_shard';
    37         -				sturdiness = 1.3;
    38         -			}
           37  +				sturdiness = 1.5;
           38  +			};
           39  +			cobalt = {
           40  +				item = 'sorcery:powder_cobalt';
           41  +				power = 1.4;
           42  +			};
           43  +			iridium = {
           44  +				item = 'sorcery:powder_iridium';
           45  +				sturdiness = 1.25;
           46  +				power = 1.25;
           47  +			};
           48  +			lithium = {
           49  +				item = 'sorcery:powder_lithium';
           50  +				power = 1.7;
           51  +				reliability = 0.85;
           52  +			};
           53  +			gold = {
           54  +				item = 'sorcery:powder_gold';
           55  +				duration = 1.3;
           56  +				power = 1.3;
           57  +			};
           58  +			tungsten = {
           59  +				item = 'sorcery:powder_tungsten';
           60  +				duration = 1.7;
           61  +				sturdiness = 1.25;
           62  +			};
           63  +			-- add one that only lets the first wielder
           64  +			-- ever use the wand
    39     65   		};
    40     66   		wire = {
    41     67   			gold = {
    42     68   				-- gold limits the amount of wear-and-tear on
    43         -				-- the wand, but causes the effect to weaken as
           69  +				-- the wand, but causes the power to weaken as
    44     70   				-- it empties
    45     71   				tone = u.color(255,255,59);
    46     72   				tex = u.image('default_gold_block.png');
    47     73   			};
    48     74   			copper = {
    49     75   				-- copper causes the wand to recharge more quickly
    50     76   				-- but power levels are unpredictable