Index: altar.lua ================================================================== --- altar.lua +++ altar.lua @@ -60,11 +60,11 @@ sunlight_propagates = true; stack_max = 1; tiles = god.idol.tex; selection_box = { type = "fixed"; fixed = {hitbox}; }; collision_box = { type = "fixed"; fixed = {hitbox}; }; - groups = { cracky = 2, sorcery_idol = 1, heavy = 1}; + groups = { cracky = 2, sorcery_idol = 1, heavy = 1, sorcery_worship = 1}; after_place_node = function(pos, placer, stack, pointat) local meta = minetest.get_meta(pos) local stackmeta = stack:get_meta() meta:set_int('favor', stackmeta:get_int('favor')) @@ -195,11 +195,11 @@ -- loop through the sacrifices accepted by this god and check -- whether the item on the altar is any of them for s, value in pairs(god.sacrifice) do if itemname == s then if value < 0 then - bestow("new_campfire:ash", sorcery.lib.color(254,117,103)) + bestow("sorcery:ash", sorcery.lib.color(254,117,103)) else if idolmeta:get_string('last_sacrifice') == s then -- the gods are getting bored value = math.floor(value / 2) end @@ -293,11 +293,11 @@ collision_box = { type = "fixed", fixed = { {-0.5, -0.5, -0.5, 0.5, -0.09, 0.5} } }; - groups = {cracky = 2, oddly_breakable_by_hand = 2}; + groups = {cracky = 2, oddly_breakable_by_hand = 2, sorcery_worship = 1}; on_construct = function(pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() inv:set_size('item', 1) ADDED attunement.lua Index: attunement.lua ================================================================== --- attunement.lua +++ attunement.lua @@ -0,0 +1,94 @@ +local u = sorcery.lib +local m = u.marshal +local tunepack, tuneunpack = m.transcoder { + code = m.t.u16; -- disambiguate just in case + partner_x = m.t.s32; + partner_y = m.t.s32; + partner_z = m.t.s32; + -- note that the meaning of 'partner' is a bit confusing. attuning + -- is a directional relationship; that is, every item can be tuned + -- to only one item (its partner), but more items can be tuned to + -- it. while it will in most cases be reciprocal, this will not + -- always be the case (e.g. with portals) +} + +sorcery.attunement = { + nodeid = function(node) + local meta = minetest.get_meta(node) + local id + if meta:contains('sorcery:identity') then + id = meta:get_string('sorcery:identity') + else + id = sorcery.lib.str.rand(16) + meta:set_string('sorcery:identity', id) + end + return id + end; + decode = function(raw) + local obj = tuneunpack(u.str.meta_dearmor(raw,true)) + return { + code = obj.code; + partner = { + x = obj.partner_x; + y = obj.partner_y; + z = obj.partner_z; + }; + } + end; + encode = function(tune) + return u.str.meta_armor(tunepack { + code = tune.code; + partner_x = tune.partner.x; + partner_y = tune.partner.y; + partner_z = tune.partner.z; + }, true) + end; + get = function(node) + local raw = minetest.get_meta(node):get_string('sorcery:attune') + if not raw then return nil end + return sorcery.attunement.decode(raw) + end; + verify = function(node) + local tune = sorcery.attunement.get(node) + if not tune then return nil end + local ptnr = sorcery.attunement.get(tune.partner) + if not ptnr then return nil end + + local nodename =minetest.get_node(node).name + local ptnrname =minetest.get_node(tune.partner).name + + local ndef = minetest.registered_nodes[nodename] + local pdef = minetest.registered_nodes[ptnrname] + + if not (ndef and ndef._sorcery and pdef and pdef._sorcery and + ndef._sorcery.attune and pdef._sorcery.attune) then return nil end + + ndef = ndef._sorcery.attune pdef = pdef._sorcery.attune + + if ndef.reciprocal and (not vector.equals(ptnr.partner, node)) then return nil end + + if tune.code == ptnr.code then + return tune, ptnr + end + return nil + end; + set = function(node,tune) + local meta = minetest.get_meta(node) + meta:set_string('sorcery:attune', sorcery.attunement.encode(tune)) + meta:mark_as_private('sorcery:attune') + end; + pair = function(reciprocal,src,dest) + local d, code = sorcery.attunement.get(src) + if reciprocal or not d then + code = math.random(0,65536) + sorcery.attunement.set(src, { + code = code; + partner = dest; + }) + else code = d.code end + sorcery.attunement.set(dest, { + code = code; + partner = src; + }) + end; +} Index: coins.lua ================================================================== --- coins.lua +++ coins.lua @@ -86,11 +86,11 @@ drawtype = 'mesh'; mesh = 'sorcery-coinpress.obj'; sunlight_propagates = true; paramtype = 'light'; paramtype2 = 'facedir'; - groups = { cracky = 2; oddly_breakable_by_hand = 2; }; + groups = { cracky = 2; oddly_breakable_by_hand = 2; sorcery_metallurgy = 1}; tiles = { 'default_wood.png'; 'default_stone.png'; 'default_copper_block.png'; 'default_steel_block.png'; Index: compat.lua ================================================================== --- compat.lua +++ compat.lua @@ -24,11 +24,21 @@ end if silver then minetest.register_alias('sorcery:silver_ingot',silver..'_ingot') minetest.register_alias('sorcery:silver_block',silver..'_block') end + +if minetest.get_modpath("new_campfire") then + minetest.register_alias('sorcery:ash', 'new_campfire:ash') +else + minetest.register_craftitem('sorcery:ash', { + description = 'Ash'; + inventory_image = 'sorcery_iron_powder.png^[colorize:#FFFFFF:100'; + }) + minetest.register_alias('new_campfire:ash', 'sorcery:ash') +end return { defp = function(name) return minetest.registered_items[name] or minetest.registered_aliases[name] end } ADDED cookbook.lua Index: cookbook.lua ================================================================== --- cookbook.lua +++ cookbook.lua @@ -0,0 +1,509 @@ +-- by use of the enchanter, it is possible to reveal a random +-- recipe and enscribe it on a sheet of paper. these sheets of +-- paper can then bound together into books, combining like +-- recipes + +sorcery.cookbook = {} +local constants = { + -- do not show recipes for items in these groups + exclude_groups = { + }; + exclude_names = { + '_stairs'; + '_slab'; + 'slope_'; + }; + -- do not show recipes from this namespace + blacklist_mods = { + 'group'; -- WHY IS THIS NECESSARY + 'moreblocks'; -- too much noise + }; + + recipes_per_cookbook_page = 3; +} + +local slot3x3 = { + {0,0}, {1,0}, {2,0}; + {0,1}, {1,1}, {2,1}; + {0,2}, {1,2}, {2,2}; +} +local props_builtin = function(item) + local props = minetest.registered_items[item]._sorcery + if props and props.recipe then + return props.recipe + end + return {} +end +local modofname = function(id) + local sep = string.find(id,':') + if sep == nil then return nil end -- uh oh + return string.sub(id, 1, sep - 1) +end +local pick_builtin = function(kind) return function(restrict) + -- ow ow ow ow ow ow ow + local names = {} + for k in pairs(minetest.registered_items) do + local rec = minetest.get_craft_recipe(k) + if rec.items ~= nil and (rec.method == kind or (rec.method == 'shapeless' and kind == 'normal')) then -- is this last bit necessary? + local excluded = false + for _,n in pairs(constants.exclude_names) do + if string.find(p,n) then + excluded = true break end + end + if not excluded then for _,g in pairs(constants.exclude_groups) do + if minetest.get_item_group(p, g) > 0 then + excluded = true break end + end end + local props = minetest.registered_items[k]._sorcery + local module = modofname(k) + if not (excluded + or sorcery.lib.tbl.has(constants.blacklist_mods,module) + or (props and props.recipe and props.recipe.secret) + or (restrict and ( + (restrict.mod and module ~= restrict.mod) + or (restrict.group and (minetest.get_item_group(k, restrict.group) == 0)) + ))) then names[#names + 1] = k end + end + end + return names[math.random(#names)] +end end +local find_builtin = function(out) + local rec = {} + local i = minetest.get_craft_recipe(out) + if #i.items == 0 then return nil end + local w = (i.width == 0) and 3 or i.width + for j=1,#i.items do + local row = math.floor((j-1) / w) + local col = (j-1) % w + if i.items[j] then + rec[1 + (row * 3) + col] = i.items[j] + end + end + return rec +end +local desc_builtin = function(i) + local desc = minetest.registered_items[i].description + if not desc then return 'Peculiar Item' end + + local eol = string.find(desc,'\n') + if not eol then return desc else return string.sub(desc,1,eol-1) end +end; + +local bookadjs = { -- sets are in reverse order! + {'Celestial', 'Divine', 'Inspired', 'Heavenly'; + 'Mystic', 'Diabolic', 'Luminous', 'Forsaken'}; + + {'Dark', 'Perfected', 'Flawless', 'Unthinkable'; + 'Impossible', 'Worrisome', 'Unimpeachable'}; + + {'Splendid', 'Magnificent', 'Sublime', 'Grand'; + 'Beneficent', 'Mysterious', 'Peculiar', 'Eerie'; + 'Fulsome', 'Fearsome', 'Curious', 'Fascinating'; + 'Notorious', 'Infamous'}; +} + +sorcery.cookbook.classes = { + craft = { + name = 'Crafting Guide'; + node = 'xdecor:workbench'; + booksuf = 'Manual'; + w = 3, h = 3; + chance = 2; + slots = slot3x3; + pick = pick_builtin('normal'); + find = find_builtin; + desc = desc_builtin; + props = props_builtin; + apply_exclusions = true; + }; + -- smelt = { + -- w = 3, h = 3; + -- slots = slot3x3; + -- }; + cook = { + name = 'Cooking Recipe'; + node = 'default:furnace'; + booksuf = 'Cookbook'; + w = 1, h = 1; + chance = 5; + slots = {{-0.2,0}}; + pick = pick_builtin('cooking'); + find = find_builtin; + props = props_builtin; + apply_exclusions = true; + }; + infuse = { + name = 'Infusion Recipe'; + node = 'sorcery:infuser'; + booksuf = 'Pharmacopeia'; + w = 1, h = 2; + chance = 2; + slots = { + {0,0}; + {0,1}; + }; + pick = function(restrict) + -- TODO make sure affinity restrictions match + return sorcery.data.infusions[math.random(#sorcery.data.infusions)].output + end; + title = function(output) + for _,i in pairs(sorcery.data.infusions) do + print(dump(i)) + if i.output == output then + if i._proto and i._proto.name + then return i._proto.name + else break end + end + end + return 'Mysterious Potion' + end; + find = function(out) + for _,i in pairs(sorcery.data.infusions) do + if i.output == out then + return { i.infuse, i.into } + end + end + end; + props = function(out) + local i = sorcery.cookbook.classes.infuse.find(out) + if i.recipe then return i.info else return {} end + end; + }; + -- wand = { + -- booksuf = 'Grimoire'; + -- } + enchant = { + name = 'Enchantment Matrix'; + node = 'sorcery:enchanter'; + booksuf = 'Grimoire'; + drawslots = false; + chance = 1; + w = 2, h = 2; + pick = function(restrict) + -- TODO make sure affinity restrictions match + local names = {} + for k,v in pairs(sorcery.data.enchants) do + if v.recipe then names[#names+1] = k end + end + return names[math.random(#names)] + end; + icon = function(name) + return 'sorcery_enchant_' .. name .. '.png' + end; + find = function(name) + local rec = {} + local en = sorcery.data.enchants[name] + if not en then return nil end + en = en.recipe + for i,e in pairs(en) do + if e.lens then + rec[i] = 'sorcery:lens_' .. e.lens .. '_' .. e.gem + end + end + return rec + end; + props = function(name) + return sorcery.data.enchants[name].info or {} + end; + slots = { + {0.5,0}; + {0,1}, {1,1} + }; + title = function(name) return sorcery.data.enchants[name].name end; + outdesc = function(name,suffix) + local e = sorcery.data.enchants[name] + return sorcery.lib.ui.tooltip { + title = e.name; + desc = sorcery.lib.str.capitalize(e.desc); + color = sorcery.lib.color(e.tone):readable(); + } + end; + }; + -- spells = { + -- booksuf = 'Spellbook'; + -- slots = { + -- {0,0}, {1,0}; + -- {0,1}, {1,1}; + -- }; + -- }; +} + +local recipe_kinds = sorcery.cookbook.classes + +local namebook = function(kind,author) + local name + if kind then name = recipe_kinds[kind].booksuf + else name = 'Cyclopedia' end + for _,set in pairs(bookadjs) do + if math.random(3) == 1 then + name = set[math.random(#set)] .. ' ' .. name + end + end + + return sorcery.lib.str.capitalize(author) .. "'s " .. name +end + +sorcery.cookbook.pickrecipe = function(kind,restrict) + if kind == nil then + for k,v in pairs(recipe_kinds) do + if math.random(v.chance) == 1 then + kind = k break + end + end + -- local rks = sorcery.lib.tbl.keys(recipe_kinds) + -- kind = rks[math.random(#rks)] + end + + return recipe_kinds[kind].pick(restrict), kind +end + +local render_recipe = function(kind,ingredients,result) + local k = recipe_kinds[kind] + local t = '' + for i=1,#k.slots do + local x, y = k.slots[i][1], k.slots[i][2] + if ingredients[i] and ingredients[i] ~= '' then + local tt + if k.indesc then tt = k.indesc(ingredients[i]) else tt = desc_builtin(ingredients[i]) end + t = t .. string.format([[ + item_image[%f,%f;1,1;%s] + tooltip[%f,%f;1,1;%s] + ]], x,y, minetest.formspec_escape(ingredients[i]), + x,y, minetest.formspec_escape(tt)) + else + if k.drawslots == nil or k.drawslots then + t = string.format('box[%f,%f;0.1,0.1;#00000060]',x+0.45,y+0.45) .. t + end + end + end + local img, ot + local props = k.props(result) + if props.note then + t = t .. string.format([[ + textarea[0,3;4,1;;;%s] + ]], minetest.formspec_escape(props.note)) + end + if k.icon then img = k.icon(result) end + if k.outdesc then ot = k.outdesc(result) else ot = desc_builtin(result) end + -- image[%f,%f;1,1;gui_furnace_arrow_bg.png^[transformR270] + return t .. string.format([[ + item_image[%f,%f;1,1;%s]tooltip[%f,%f;1,1;%s] + ]] --[[box[%f,%f;1,1;#850083A0]] .. [[ + %s[%f,%f;1,1;%s] + tooltip[%f,%f;1,1;%s] + ]], k.w, k.h/2 - 0.5, k.node, + k.w, k.h/2 - 0.5, minetest.formspec_escape(minetest.registered_nodes[k.node].description), + -- k.w+1, k.h/2 - 0.5, + img and 'image' or 'item_image', + k.w+1.1, k.h/2 - 0.5, minetest.formspec_escape(img or result), + k.w+1.1, k.h/2 - 0.5, minetest.formspec_escape(ot)) +end; + +local retrieve_recipe = function(kind,out) + local rec = recipe_kinds[kind] + local ing = rec.find(out) + return render_recipe(kind,ing,out), rec.w, rec.h +end + +sorcery.cookbook.setrecipe = function(stack,k,r,restrict) + local meta = stack:get_meta() + if not r then r,k = sorcery.cookbook.pickrecipe(k,restrict) end + local t = recipe_kinds[k] + meta:set_string('recipe_kind', k) + meta:set_string('recipe_name', r) + meta:set_string('description', + (t.title and t.title(r) or desc_builtin(r)) .. ' ' .. t.name) +end + +minetest.register_craftitem('sorcery:recipe', { + description = 'Recipe'; + inventory_image = 'default_paper.png'; -- fixme + groups = { flammable = 1; book = 1; paper = 1; }; + stack_max = 1; + on_use = function(itemstack, user, target) + local meta = itemstack:get_meta() + if not meta:contains('recipe_kind') then sorcery.cookbook.setrecipe(itemstack) end + local kind = meta:get_string('recipe_kind') + local spec, w, h = retrieve_recipe(kind,meta:get_string('recipe_name')) + minetest.show_formspec(user:get_player_name(), 'sorcery:recipe', string.format([[ + size[%f,%f] + container[1,1] %s container_end[] + ]], w + 4,h + 2, + spec)) + return itemstack + end; +}) + +dungeon_loot.register { + name = 'sorcery:recipe'; + chance = 0.9; + count = {1,7}; +} + +minetest.register_craft { type = 'fuel', recipe = 'sorcery:recipe', burntime = 3 } +minetest.register_craft { + type = 'cooking'; + recipe = 'sorcery:recipe'; + output = 'sorcery:ash'; + cooktime = 3; +} + +default.register_craft_metadata_copy('default:paper','sorcery:recipe') +-- default.register_craft_metadata_copy('default:book','sorcery:cookbook') + +for i=1,8 do + local rcp = {} + for i=1,i do rcp[i] = 'sorcery:recipe' end + rcp[#rcp+1]='default:book' minetest.register_craft { + type = 'shapeless', recipe = rcp, output = 'sorcery:cookbook'; + } + rcp[#rcp]='sorcery:cookbook' minetest.register_craft { + type = 'shapeless', recipe = rcp, output = 'sorcery:cookbook'; + } +end + + +local m = sorcery.lib.marshal +local encbook, decbook = m.transcoder { + pages = m.g.array(8, m.g.struct { + kind = m.t.str; + name = m.t.str; + }) +} + +local bookprops = function(stack) + local meta = stack:get_meta() + if meta:contains('cookbook') then + return decbook(sorcery.lib.str.meta_dearmor(meta:get_string('cookbook'),true)) + else return {pages={}} end +end + +local bookform_ctx = {} +local bookform = function(stack,user) + bookform_ctx[user:get_player_name()] = user:get_wield_index() + + local meta = stack:get_meta() + local book = bookprops(stack) + local pagect = math.ceil(#book.pages / constants.recipes_per_cookbook_page) + local curpage = meta:contains("pagenr") and meta:get_int("pagenr") or 1 + + local pgofs = (curpage - 1) * constants.recipes_per_cookbook_page + local form = string.format([[ + formspec_version[3] + size[10,12]real_coordinates[true] + box[0,0;10,1;#580C39FF]label[0.4,0.5;%s] + button_exit[3,11;4,1;quit;Page %u/%u] + ]], minetest.formspec_escape(meta:get_string('description')), + curpage, pagect) + + if curpage > 1 then form = form .. 'button[0,11;3,1;pageback;< Back]' end + if curpage < pagect then form = form .. 'button[7,11;3,1;pagenext;Next >]' end + + local coords = { + {2,1.3}; + {2,4.5}; + {2,7.7}; + -- {0,1.3}, {4, 1.3}; + -- {0,4.7}, {4, 4.7}; + -- {0,8.1}, {4, 8.1}; + } + print('book:',dump(book)) + print('pgofs',pgofs) + for i=pgofs,(pgofs + constants.recipes_per_cookbook_page-1) do + local maxw, maxh = 3, 2 + if not book.pages[i+1] then break end + local nr = 1+(i - pgofs) + local x,y = coords[nr][1], coords[nr][2] + local k = recipe_kinds[book.pages[i+1].kind] + local ox,oy = maxw - k.w, maxh - k.h + form = form .. string.format('container[%f,%f]%scontainer_end[]',(x+ox)-0.5,y, + retrieve_recipe(book.pages[i+1].kind, book.pages[i+1].name)) + end + + minetest.show_formspec(user:get_player_name(), 'sorcery:cookbook', form) +end + +minetest.register_craftitem('sorcery:cookbook', { + description = 'Catalog'; + inventory_image = 'default_book_written.png'; + groups = { book = 1; flammable = 3 }; + on_use = function(stack,user) + local book = bookprops(stack) + if #book.pages == 0 then return nil end + bookform(stack,user) + end; +}) + +minetest.register_on_player_receive_fields(function(user,form,fields) + if form ~= 'sorcery:cookbook' then return false end + if fields.quit then + bookform_ctx[user:get_player_name()] = nil + return true + end + + local idx = bookform_ctx[user:get_player_name()] + if not idx then return true end + + local uinv = user:get_inventory() + local stack = uinv:get_stack('main', idx) + local book = bookprops(stack) + local meta = stack:get_meta() + + local curpage = meta:contains("pagenr") and meta:get_int("pagenr") or 1 + local pagect = math.ceil(#book.pages / constants.recipes_per_cookbook_page) + + if curpage > 1 and fields.pageback then + meta:set_int('pagenr', curpage - 1) + elseif curpage < pagect and fields.pagenext then + meta:set_int('pagenr', curpage + 1) + end + + uinv:set_stack('main',idx,stack) + bookform(stack,user) +end) + +minetest.register_on_craft(function(stack,player,grid,inv) + if stack:get_name() ~= 'sorcery:cookbook' then return nil end + + local oldbook + local topic, onetopic = nil, true + local recipes = {} + for _,s in pairs(grid) do + if s:get_name() == 'sorcery:recipe' then + recipes[#recipes+1] = s + elseif s:get_name() == 'sorcery:cookbook' then oldbook = s end + end + + oldbook = oldbook or stack + local bookmeta = oldbook:get_meta() + local newbook = not bookmeta:contains('cookbook') + local book = bookprops(oldbook) + + for _,s in pairs(recipes) do + local meta = s:get_meta() + local kind, item + if meta:contains('recipe_kind') then + kind = meta:get_string('recipe_kind') + item = meta:get_string('recipe_name') + else item, kind = sorcery.cookbook.pickrecipe(kind) end + book.pages[#book.pages + 1] = { name = item, kind = kind } + if topic then + if topic ~= kind then onetopic = false end + else topic = kind end + end + + if topic and newbook then + if not onetopic then topic = nil end + bookmeta:set_string('description',namebook(topic,player:get_player_name())) + bookmeta:set_string('owner',player:get_player_name()) + end + + print('new book',bookmeta:get_string('description')) + print('new book',dump(book)) + bookmeta:set_string('cookbook', sorcery.lib.str.meta_armor(encbook(book),true)) + return oldbook +end) + +if minetest.get_modpath('books') then + -- make our own placeable cookbook somehow +end ADDED crafttools.lua Index: crafttools.lua ================================================================== --- crafttools.lua +++ crafttools.lua @@ -0,0 +1,41 @@ +minetest.register_on_craft(function(stack,crafter,recipe,grid) + local ctoolclass = { + [1] = 200; + [2] = 100; + [3] = 50; + [4] = 10; + [5] = 5; + } + for i=1,grid:get_size('craft') do + local s = grid:get_stack('craft',i) + local v = minetest.get_item_group(s:get_name(),'crafttool') + if v ~= 0 then + local dmg = 65536 / ctoolclass[v] + local tool = recipe[i] + tool:add_wear(dmg) + grid:set_stack('craft',i,tool) + end + end + return nil +end) + +if minetest.get_modpath('xdecor') then + local og = minetest.registered_tools['xdecor:hammer'].groups + og.crafttool = 2 + minetest.override_item('xdecor:hammer', {groups = og}) +end + +minetest.register_tool('sorcery:vice', { + description = 'Vice'; + inventory_image = 'sorcery_vice.png'; + group = { crafttool = 3; } +}) +minetest.register_craft { + output = 'sorcery:vice'; + recipe = { + {'default:steel_ingot','sorcery:screw_steel','default:steel_ingot'}; + {'default:bronze_ingot','sorcery:screw_steel','default:bronze_ingot'}; + {'default:tin_ingot','default:tin_ingot','default:tin_ingot'}; + }; +} +-- chisel Index: data/enchants.lua ================================================================== --- data/enchants.lua +++ data/enchants.lua @@ -13,11 +13,11 @@ return { endure = { -- withstand more blows name = 'Endure'; cost = 1; tone = {232,102,255}; - desc = 'durability magnified'; + desc = 'tools last longer before wearing out'; affinity = 'counterpraxic'; groups = allgroups; recipe = { {lens = 'convex', gem = 'amethyst', dmg = 2}; {lens = 'rectifier', gem = 'emerald', dmg = 4}; @@ -73,11 +73,11 @@ }; conserve = { -- use less magical energy name = 'Conserve'; tone = {84,255,144}; cost = 0; - desc = 'enchantments last longer before running out of power to sustain them.'; + desc = 'enchantments last longer before running out of power to sustain them'; groups = allgroups; affinity = 'syncretic'; recipe = { {lens = 'rectifier', gem = 'mese', dmg = 7}; {lens = 'rectifier', gem = 'sapphire', dmg = 2}; @@ -126,10 +126,23 @@ count = 100 * dstfac; } end end end; + }; + glitter = { -- increase odds of finding gem + name = 'Glitter'; + cost = 10; + tone = {255,50,60}; + desc = 'dramatically improve your chances of finding gems while mining veins'; + groups = {'pick','pickaxe'}; + affinity = 'entropic'; + recipe = { + {lens = 'amplifier', gem = 'diamond', dmg = 12}; + {lens = 'rectifier', gem = 'sapphire', dmg = 9}; + {lens = 'convex', gem = 'ruby', dmg = 7}; + }; }; pierce = { -- faster mining speed name = 'Pierce'; cost = 3; tone = {113,240,251}; @@ -176,6 +189,8 @@ end stack:get_meta():set_tool_capabilities(caps) return stack end; }; + -- multiply = {}; -- add a chance of receiving multiple drops of ore/coal + -- leech = {}; -- draw power from local leylines } Index: data/metals.lua ================================================================== --- data/metals.lua +++ data/metals.lua @@ -29,11 +29,11 @@ ingot = 'default:copper_ingot'; block = 'default:copperblock'; tone = {255,176,61}; no_tools = true; no_armor = true; hardness = 2; - conduct = 0.1; + conduct = 0.3; }; brass = { tone = {255,226,87}; dye = 'bright_orange'; artificial = true; @@ -139,11 +139,11 @@ }; electrum = { tone = {212, 255, 0}, alpha = 80; artificial = true; hardness = 1; - conduct = 0.5; + conduct = 2; dye = 'bright_green'; mix = { metals = { silver = 1; gold = 1; @@ -176,11 +176,10 @@ hardness = 6; power = 3; speed = 3.5; cooktime = 30; maxenergy = 3500; - conduct = 2.0; slots = { { affinity = {'counterpraxic'}; confluence = 0.65; interference = {speed = 1}; @@ -193,22 +192,44 @@ rarity = 13; hardness = 2; fuel = 80; no_tools = true; no_armor = true; + }; + vidrium = { + tone = {119,185,221}, alpha = 140; + artificial = true; + dye = 'cyan'; + hardness = 1; + durability = 300; + meltpoint = 2; + cooktime = 20; + no_tools = true, no_armor = true; + conduct = 5; + mix = { + metals = { + lithium = 2; + tin = 4; + gold = 1; + } + }; + sinter = { + 'gold'; 'lithium', 'lithium'; + 'tin', 'tin', 'tin', 'tin'; + }; }; iridium = { tone = {209,88,241}, alpha = 80; dye = 'purple'; rarity = 18; meltpoint = 3; cooktime = 340; hardness = 7; maxenergy = 1800; - conduct = 5; + conduct = 10; durability = 1900; - speed = 3.2; + speed = 3; img = { -- ingot = 'sorcery_iridium_ingot.png'; -- block = 'sorcery_iridium_block.png'; }; slots = { @@ -279,15 +300,13 @@ tungsten = 2; lithium = 1; }; }; sinter = { - 'sorcery:powder_iridium'; - 'sorcery:powder_iridium'; - 'sorcery:powder_tungsten'; - 'sorcery:powder_tungsten'; - 'sorcery:powder_lithium'; + 'lithium'; + 'iridium', 'iridium'; + 'tungsten', 'tungsten'; }; slots = { {affinity={'praxic','entropic'}, confluence = 1.4}; {affinity={'praxic','syncretic'}, confluence = 1.1}; } @@ -298,11 +317,11 @@ cooktime = 330; artificial = true; maxenergy = 4000; hardness = 7; durability = 3300; - conduct = 15; + conduct = 20; speed = 3.4; slots = { {affinity={'praxic'}, confluence = 0.7}; {affinity={'counterpraxic'}, confluence = 1.2}; {affinity={'cognic'}, confluence = 1.1}; @@ -319,24 +338,22 @@ tone = {255,20,80}, alpha = 110; artificial=true; meltpoint = 5; cooktime = 120; hardness = 8; - maxconduct = 10; + maxconduct = 15; speed = 1.7; maxenergy = 2200; durability = 1500; slots = { {affinity={'praxic'},confluence=3}; {affinity={'syncretic'},confluence=2}; }; sinter = { - 'sorcery:powder_lithium'; - 'sorcery:powder_aluminum'; - 'sorcery:powder_iridium'; - 'sorcery:oil_flame'; + 'lithium'; 'aluminum'; 'iridium'; }; + sinter_catalyst = { 'sorcery:oil_flame' }; }; tyrannium = { tone = {46,255,245}, alpha = 80; artificial=true; hardness = 20; Index: data/potions.lua ================================================================== --- data/potions.lua +++ data/potions.lua @@ -7,10 +7,11 @@ Majestic = { color = {253,133,194}; style = 'sparkle'; infusion = 'sorcery:oil_mystic'; basis = 'sorcery:holy_water'; + substitutes = 'Serene'; glow = 8; }; Misty = { color = {186,241,233}; infusion = 'sorcery:grease_fog'; @@ -28,6 +29,10 @@ }; Viscous = { color = {119,51,111}; infusion = 'sorcery:oil_bleak'; }; + Isolating = { + color = {188,78,225}; + infusion = 'sorcery:extract_fern'; + }; } Index: data/spells.lua ================================================================== --- data/spells.lua +++ data/spells.lua @@ -1,13 +1,43 @@ +local cast_sparkle = function(ctx,color,strength,duration) + minetest.add_particlespawner { + amount = 70 * strength; + time = duration or 1.5; + attached = ctx.caster; + texture = sorcery.lib.image('sorcery_spark.png'):multiply(color):render(); + minpos = { x = -0.1, z = 0.5, y = 1.2}; + maxpos = { x = 0.1, z = 0.3, y = 1.6}; + minvel = { x = -0.5, z = -0.5, y = -0.5}; + maxvel = { x = 0.5, z = 0.5, y = 0.5}; + minacc = { x = 0.0, z = 0.0, y = 0.5}; + maxacc = { x = 0.0, z = 0.0, y = 0.5}; + minsize = 0.4, maxsize = 0.8; + minexptime = 1, maxexptime = 1; + glow = 14; + animation = { + type = 'vertical_frames'; + aspect_w = 16; + aspect_h = 16; + length = 1.1; + }; + } +end local enchantment_sparkle = function(ctx,color) + local minvel, maxvel + if minetest.get_node(vector.add(ctx.target.under,{y=1,z=0,x=0})).name == 'air' then + minvel = {x=0,z=0,y= 0.3} maxvel = {x=0,z=0,y= 1.5}; + else + local dir = vector.subtract(ctx.target.under,ctx.target.above) + minvel = vector.multiply(dir, 0.3) + maxvel = vector.multiply(dir, 1.2) + end return minetest.add_particlespawner { amount = 50; time = 0.5; minpos = vector.subtract(ctx.target.under, 0.5); maxpos = vector.add(ctx.target.under, 0.5); - minvel = {x=0,z=0,y= 0.3}, maxvel = {x=0,z=0,y= 1.5}; - minacc = {x=-0.2,z=-0.2,y=-0.1}, maxacc = {x=0.2,z=0.2,y=-0.2}; + minvel = minvel, maxvel = maxvel; minexptime = 1, maxexptime = 2; minsize = 0.5, maxsize = 2; texture = sorcery.lib.image('sorcery_spark.png'):multiply(color):render(); animation = { type = 'vertical_frames'; @@ -234,43 +264,19 @@ desc = 'Reveal the strength and affinities of the local leyline'; cast = function(ctx) local color = ctx.base.gem == 'sapphire'; local duration = (ctx.base.gem == 'amethyst' and 4) or 2; local ley = sorcery.ley.estimate(ctx.caster:get_pos()) - local emit = function(color,strength) - minetest.add_particlespawner { - amount = 70 * strength; - time = duration * strength; - attached = ctx.caster; - texture = sorcery.lib.image('sorcery_spark.png'): - multiply(color:brighten(1.3)):render(); - minpos = { x = -0.1, z = 0.5, y = 1.2}; - maxpos = { x = 0.1, z = 0.3, y = 1.6}; - minvel = { x = -0.5, z = -0.5, y = -0.5}; - maxvel = { x = 0.5, z = 0.5, y = 0.5}; - minacc = { x = 0.0, z = 0.0, y = 0.5}; - maxacc = { x = 0.0, z = 0.0, y = 0.5}; - minsize = 0.4, maxsize = 0.8; - minexptime = 1, maxexptime = 1; - glow = 14; - animation = { - type = 'vertical_frames'; - aspect_w = 16; - aspect_h = 16; - length = 1.1; - }; - } - end local strength = ley.force if color then strength = strength / #ley.aff for _,a in pairs(ley.aff) do - emit(sorcery.lib.color(sorcery.data.affinities[a].color), strength) + cast_sparkle(ctx,sorcery.lib.color(sorcery.data.affinities[a].color):brighten(1.3), strength, duration * strength) end else - emit(sorcery.lib.color(250,255,185), strength) + cast_sparkle(ctx,sorcery.lib.color(250,255,185), strength, duration*strength) end end; }; dowse = { @@ -310,10 +316,64 @@ uses = 38; color = {255,65,207}; leytype = 'syncretic'; affinity = {'pine','verdant','dark'}; desc = 'Establish a connection between mystic mechanisms, like connecting two sides of a portal or impressing targets onto a dowsing wand in an enchanter'; + cast = function(ctx) + if not (ctx.target and ctx.target.type == 'node') then + ctx.meta:set_string('source','') + cast_sparkle(ctx, sorcery.lib.color(234,45,100), 0.3) + return true + end + local n = minetest.registered_nodes[minetest.get_node(ctx.target.under).name] + if not (n and n._sorcery and n._sorcery.attune) then + return false end -- just in case anyone casts on an undefined node + local m = sorcery.lib.marshal + local encpos, decpos = m.transcoder { + x = m.t.s32, y = m.t.s32, z = m.t.s32; + id = m.t.str; + } + local props = n._sorcery.attune + + local rec = ctx.meta:get_string('source') + local src + if rec then + local data = decpos(sorcery.lib.str.meta_dearmor(rec,true)) + local srcpos = {x=data.x,y=data.y,z=data.z} + local srcnode = minetest.get_node(srcpos) + local srcdef = minetest.registered_nodes[srcnode.name] + if srcdef and srcdef._sorcery and srcdef._sorcery.attune then + if sorcery.attunement.nodeid(srcpos) == data.id then + -- check for ink + src = { + pos = srcpos; + props = srcdef._sorcery.attune; + } + end + end + end + + local color + if src and src.props.source and + src.props.class == props.accepts and props.target and + (not vector.equals(src.pos, ctx.target.under)) then + sorcery.attunement.pair(src.props.reciprocal or true, src.pos, ctx.target.under) + ctx.meta:set_string('source','') + color = sorcery.lib.color(255,130,75) + elseif props.source then + ctx.meta:set_string('source', sorcery.lib.str.meta_armor(encpos { + x = ctx.target.under.x; + y = ctx.target.under.y; + z = ctx.target.under.z; + id = sorcery.attunement.nodeid(ctx.target.under); + },true)) + color = sorcery.lib.color(128,75,255) + end + + if color then enchantment_sparkle(ctx,color) + else return false end + end; }; meld = { name = 'melding'; uses = 48; leytype = 'syncretic'; @@ -366,10 +426,122 @@ uses = 32; color = {17,6,212}; leytype = 'occlutic'; affinity = {'jungle','silent'}; desc = 'With an enchanter, disjoin the anchor holding a spell into an object so a new spell can instead be bound in'; + }; + divine = { + name = 'divining'; + desc = 'Steal away the secrets of the cosmos'; + uses = 16; + color= {97,97,255}; + sound = 'xdecor:enchanting'; + leytype = 'cognic'; + affinity = {'pine','shimmering','dark','verdant'}; + cast = function(ctx) + local inks = {'black','red','white','violet','blue','green'} + local getcolor = function(stack) + if stack:is_empty() then return nil end + if minetest.get_item_group(stack:get_name(), 'dye') == 0 then return nil end + for _,ink in pairs(inks) do + if minetest.get_item_group(stack:get_name(), 'color_' ..ink) ~= 0 + then print('found',ink,'ink') return ink end + end + end + if not ctx.target or ctx.target.type ~= 'node' then return false end + local tgt = minetest.get_node(ctx.target.under) + if tgt.name == 'sorcery:enchanter' then + local meta = minetest.get_meta(ctx.target.under) + local inv = meta:get_inventory() + if inv:get_stack('item',1):get_name() == 'default:paper' + and inv:get_stack('item',1):get_count() == 1 + and not inv:is_empty('foci') then + local ink1 = getcolor(inv:get_stack('foci',2)) + local ink2 = getcolor(inv:get_stack('foci',3)) + local restrict, kind, mod = {} do + local ms = inv:get_stack('foci',1) + if not ms:is_empty() then mod = ms:get_name() end + end + print(ink1,ink2,mod) + if ink1 == 'black' and ink2 == 'black' then kind = 'craft' + if mod then + if mod == sorcery.data.metals.cobalt.parts.powder then + restrict.group = 'sorcery_magitech' + elseif mod == sorcery.data.metals.vidrium.parts.powder then + restrict.group = 'sorcery_ley_device' + elseif mod == sorcery.data.metals.aluminum.parts.powder then + restrict.group = 'sorcery_metallurgy' + elseif mod == sorcery.data.metals.lithium.parts.powder then + restrict.group = 'sorcery_enchanting_lens' + elseif mod == sorcery.data.metals.iridium.parts.powder then + restrict.group = 'sorcery_worship' + elseif mod == sorcery.data.metals.gold.parts.powder then + restrict.group = 'sorcery_grease' + elseif mod == sorcery.data.metals.silver.parts.powder then + restrict.group = 'sorcery_oil' + elseif mod == sorcery.data.metals.electrum.parts.powder then + restrict.group = 'sorcery_extract' + elseif mod == 'farming:sugar' then + restrict.mod = 'farming' + else return false end + end + elseif ink1 == 'black' and ink2 == 'white' then kind = 'infuse' + if mod then + if mod == sorcery.data.metals.gold.parts.powder then + restrict.mod = 'sorcery_draught' + elseif mod == sorcery.data.metals.cobalt.parts.powder then + restrict.mod = 'sorcery_philter' + elseif mod == sorcery.data.metals.lithium.parts.powder then + restrict.mod = 'sorcery_elixirs' + else return false end + end + elseif ink1 == 'blue' and ink2 == 'violet' then kind = 'enchant' + if mod then + if mod == sorcery.data.metals.cobalt.parts.powder then + restrict.aff = 'praxic' + elseif mod == sorcery.data.metals.tungsten.parts.powder then + restrict.aff = 'counterpraxic' + elseif mod == sorcery.data.metals.aluminum.parts.powder then + restrict.aff = 'syncretic' + elseif mod == sorcery.data.metals.lithium.parts.powder then + -- restrict.aff = 'mandatic' -- no enchants yet, will cause infinite loop + elseif mod == sorcery.data.metals.iridium.parts.powder then + restrict.aff = 'entropic' + elseif mod == sorcery.data.metals.gold.parts.powder then + restrict.aff = 'cognic' + elseif mod == sorcery.data.metals.silver.parts.powder then + -- restrict.aff = 'occlutic' + elseif mod == sorcery.data.metals.electrum.parts.powder then + -- restrict.aff = 'imperic' + else return false end + end + elseif ink1 == 'red' and ink2 == 'yellow' then kind = 'cook'; + -- elseif ink1 == 'red' and ink2 == 'orange' then kind = 'smelt'; + end + print('result',kind,dump(restrict)) + if kind then + print('found kind') + local rec = ItemStack('sorcery:recipe') + local m = rec:get_meta() + if ctx.base.gem == 'diamond' then + -- make recipe for thing in slot 1 + else + sorcery.cookbook.setrecipe(rec,kind,nil,restrict) + end + inv:set_stack('item',1,rec) + for i=1,inv:get_size('foci') do + local f = inv:get_stack('foci',i) + f:take_item(1) + inv:set_stack('foci',i,f) + end + enchantment_sparkle(ctx,sorcery.lib.color(97,97,255)) + return + end + end + end + return false + end; }; luminate = { name = 'lumination'; desc = 'Banish darkness all about you for a few moments'; uses = 40; ADDED disassembly.lua Index: disassembly.lua ================================================================== --- disassembly.lua +++ disassembly.lua @@ -0,0 +1,114 @@ +local update_disassembler = function(pos) + local m = minetest.get_meta(pos) + local i = m:get_inventory() + local paper = i:get_stack('paper',1) + local item = i:get_stack('item',1) + + local ink_count + for j=1,i:get_size('ink') do + local ink = i:get_stack('ink',j) + local c = ink:get_count() + if ink_count then + if c < ink_count then ink_count = c end + else ink_count = c end + end + + ink_count = ink_count or 0 + local maxrecs = math.min(ink_count, paper:get_count(), item:get_count()) + + if maxrecs > 0 and sorcery.cookbook.classes.craft.find(item:get_name()) then + local rec = ItemStack{name = 'sorcery:recipe', count = maxrecs} + sorcery.cookbook.setrecipe(rec, 'craft', item:get_name()) + i:set_stack('output',1,rec) + else + i:set_stack('output',1,ItemStack()) + end +end +minetest.register_node('sorcery:disassembler', { + description = 'Disassembly Kit'; + drawtype = 'mesh'; + mesh = 'sorcery-disassembler.obj'; + paramtype = 'light', sunlight_propagates = true; + paramtype2 = 'facedir'; + groups = { cracky = 2, sorcery_tech = 1 }; + tiles = { + 'default_copper_block.png'; + 'default_wood.png'; + 'default_steel_block.png'; + 'default_stone.png'; + 'default_gold_block.png'; + 'default_coal_block.png'; + }; + after_dig_node = sorcery.lib.node.purge_container; + on_construct = function(pos) + local m = minetest.get_meta(pos) + local i = m:get_inventory() + i:set_size('item',1) + i:set_size('paper',1) + i:set_size('ink',3) + i:set_size('output',1) + m:set_string('infotext','Disassembly Kit') + m:set_string('formspec', [[ + formspec_version[3] + size[10.25,7] real_coordinates[true] + list[current_player;main;0.25,2;8,4] + + list[context;item;0.25,0.5;1,1;] + list[context;paper;2.25,0.5;1,1;] + list[context;ink;4.25,0.5;3,1;] + list[context;output;9,0.5;1,1;] + + listring[current_player;main] listring[context;item] + listring[current_player;main] listring[context;paper] + listring[current_player;main] listring[context;ink] + ]]) + end; + on_metadata_inventory_put = update_disassembler; + on_metadata_inventory_take = function(pos,list,idx,stack,user) + local m = minetest.get_meta(pos) + local i = m:get_inventory() + local paper = i:get_stack('paper',1) + local item = i:get_stack('item',1) + + if list == 'output' then + local count = stack:get_count() + item:take_item(count) + i:set_stack('item',1,item) + for j=1,i:get_size('ink') do + local ink = i:get_stack('ink',j) + ink:take_item(count) + i:set_stack('ink',j,ink) + end + end + + update_disassembler(pos) + end; + allow_metadata_inventory_put = function(pos,list,idx,stack,user) + local name = stack:get_name() + if list == 'paper' then + if name == 'default:paper' then return stack:get_count() end + elseif list == 'ink' then + if minetest.get_item_group(name,'dye') > 0 then return stack:get_count() end + elseif list == 'item' then + return stack:get_count() + elseif list == 'output' then + return 0 + end + return 0 + end; + allow_metadata_inventory_move = function(pos, fl, fi, tl, ti, count) + if fl == 'ink' and tl == 'ink' + then return count + else return 0 + end + end; +}) + +minetest.register_craft { + output = 'sorcery:disassembler'; + recipe = { + {'group:wood','default:gold_ingot','dye:black'}; + {'sorcery:vice','screwdriver:screwdriver','xdecor:hammer'}; + {'stairs:slab_stone', 'stairs:slab_stone', 'stairs:slab_stone'}; + }; +} Index: enchanter.lua ================================================================== --- enchanter.lua +++ enchanter.lua @@ -203,11 +203,11 @@ desc = e.desc; color = sorcery.lib.color(e.tone); } local inf = mat.data.slots[s.slot].interference if inf then for k,v in pairs(inf) do - interference[k] = interference[k] + v + interference[k] = (interference[k] or 0) + v end end ::skip::end if #interference > 0 then if interference.speed then stack = sorcery.data.enchants.pierce.apply(stack,-interference.speed,basecaps) end if interference.durability then stack = sorcery.data.enchants.endure.apply(stack,-interference.durability,basecaps) end @@ -229,11 +229,11 @@ description = 'Enchanter'; drawtype = 'mesh'; mesh = 'sorcery-enchanter.obj'; paramtype = 'light'; paramtype2 = 'facedir'; - groups = { cracky = 2, oddly_breakable_by_hand = 2 }; + groups = { cracky = 2, oddly_breakable_by_hand = 2, sorcery_magitech = 1 }; sunlight_propagates = true; selection_box = hitbox; collision_box = hitbox; after_dig_node = sorcery.lib.node.purge_container; tiles = { ADDED farcaster.lua Index: farcaster.lua ================================================================== --- farcaster.lua +++ farcaster.lua @@ -0,0 +1,138 @@ +local constants = { + farcaster_nonlocal_cost = 0.1; + -- the amount of power it takes to cast 50 nodes away +} +minetest.register_node('sorcery:raycaster', { + description = 'Raycaster'; + groups = { cracky = 2; sorcery_ley_device = 1; sorcery_magitech = 1; }; + paramtype2 = 'facedir'; + tiles = { + 'sorcery_farcaster_linear_top.png'; + 'sorcery_farcaster_linear_bottom.png'; + 'sorcery_farcaster_linear_side.png'; + }; + _sorcery = { + ley = { + mode = 'consume', affinity = {'mandatic'}; + power = function(pos,delta) + local tune = sorcery.attunement.verify(pos) + if tune then return 0.3 else return 0 end + end + }; + attune = { + class = 'sorcery:raycaster', accepts = 'sorcery:raycaster'; + source = true, target = true, reciprocal = true; + }; + farcaster = { + partner = function(pos) + local tune = sorcery.attunement.verify(pos) + print(' *!* verifying farcaster tuning',tune) + if not tune then return nil end + minetest.load_area(tune.partner) + local vis = false + local ignored + repeat + ignored = false + for _,p in pairs(sorcery.lib.node.offsets.neighbors) do + local sum = vector.add(pos,p) + local _, stop = minetest.line_of_sight(sum,tune.partner) + if vector.equals(stop, tune.partner) then + vis = true + break + else + if minetest.get_node(stop).name == 'ignore' then + minetest.load_area(stop) + ignored = true + end + end + end + until ignored == false + if vis == true + then return tune.partner + else return nil + end + end; + }; + }; +}) + +minetest.register_node('sorcery:farcaster', { + description = 'Farcaster'; + paramtype2 = 'facedir'; + groups = { cracky = 2; sorcery_ley_device = 1; sorcery_magitech = 1; }; + tiles = { + 'sorcery_farcaster_nonlocal_top.png'; + 'sorcery_farcaster_nonlocal_top.png'; + 'sorcery_farcaster_nonlocal_side.png'; + 'sorcery_farcaster_nonlocal_side.png'; + 'sorcery_farcaster_nonlocal_back.png'; + 'sorcery_farcaster_nonlocal_front.png'; + }; + _sorcery = { + ley = { mode = 'consume'; affinity = {'mandatic'}; + power = function(pos,delta) + local tune = sorcery.attunement.verify(pos) + if not tune then + return 0 + else + return (vector.distance(pos,tune.partner) / 50) * constants.farcaster_nonlocal_cost + end + end; + }; + attune = { + class = 'sorcery:farcaster', accepts = 'sorcery:farcaster'; + source = true, target = true, reciprocal = true; + }; + farcaster = { + partner = function(pos) + local tune = sorcery.attunement.verify(pos) + if not tune then return nil end + + return tune.partner + end; + } + }; +}) + +sorcery.farcaster = {} +sorcery.farcaster.junction = function(start,minconduct) + local stack = {{pos = start, hops = 0, route = {}}} + local checked, network = {},{} + local checkedp = function(pos) + for _,v in pairs(checked) do + if vector.equals(pos,v) then return true end + end + return false + end + local i = 1 repeat + local caps = sorcery.ley.netcaps(stack[i].pos,1,nil,minconduct) + network[#network+1] = { + caps = caps; + hops = stack[i].hops; + route = stack[i].route; + } + for _,d in pairs(caps.net.devices.consume) do + if not checkedp(d.pos) then + checked[#checked+1] = d.pos + local def = minetest.registered_nodes[d.id] + if def and def._sorcery and def._sorcery.farcaster then + local fc = def._sorcery.farcaster + local p = fc.partner(d.pos) + if p ~= nil and d.powerdraw >= d.minpower and not checkedp(p) then + local nr = table.copy(stack[i].route) + checked[#checked+1] = p + nr[#nr+1] = d.pos + stack[#stack+1] = { + pos = p; + route = nr; + hops = stack[i].hops + 1; + } + else + end + end + end + end + i = i + 1 until i > #stack + + return network +end Index: forcefield.lua ================================================================== --- forcefield.lua +++ forcefield.lua @@ -41,17 +41,20 @@ targets = tgts; } end for i=1,10 do minetest.register_node('sorcery:air_barrier_' .. tostring(i), { - drawtype = 'airlike'; + drawtype = 'glasslike'; walkable = true; pointable = false; sunlight_propagates = true; paramtype = 'light'; light_source = i; + tiles = {'sorcery_transparent.png'}; groups = { + air = 1; + sorcery_air = 1; sorcery_force_barrier = i; }; -- _proto = { -- strength = i; -- }; @@ -104,10 +107,11 @@ description = "Barrier Screen Emitter"; paramtype2 = 'facedir'; groups = { cracky = 2; sorcery_ley_device = 1; + sorcery_magitech = 1; }; tiles = { 'sorcery_emitter_barrier_top.png'; 'sorcery_emitter_barrier_bottom.png'; 'sorcery_emitter_barrier_front.png^[transformR270'; Index: gems.lua ================================================================== --- gems.lua +++ gems.lua @@ -76,11 +76,11 @@ minetest.register_tool(id, { inventory_image = sorcery.lib.image('sorcery_lens_overlay_gold.png'): blit(sorcery.lib.image('sorcery_lens_' .. kind .. '.png'): multiply(sorcery.lib.color(gem.tone):brighten(1.1))): render(); - description = sorcery.lib.str.capitalize(name) .. ' ' .. kind .. ' lens'; + description = sorcery.lib.str.capitalize(name) .. ' ' .. sorcery.lib.str.capitalize(kind) .. ' Lens'; groups = { sorcery_enchanting_lens = 1 }; _proto = { gem = name; kind = kind; }; @@ -177,36 +177,10 @@ -- referring to registered_nodes anyway, but i don't want -- to chance it; god knows what's going on under the hood end end -if minetest.get_modpath('xdecor') then - local og = minetest.registered_tools['xdecor:hammer'].groups - og.crafttool = 1 - minetest.override_item('xdecor:hammer', {groups = og}) -end - -minetest.register_on_craft(function(stack,crafter,recipe,grid) - local ctoolclass = { - [1] = 200; - [2] = 100; - [3] = 50; - [4] = 10; - [5] = 5; - } - for i=1,grid:get_size('craft') do - local s = grid:get_stack('craft',i) - local v = minetest.get_item_group(s:get_name(),'crafttool') - if v ~= 0 then - local dmg = 65536 / ctoolclass[v] - local tool = recipe[i] - tool:add_wear(dmg) - grid:set_stack('craft',i,tool) - end - end - return nil -end) for g,v in pairs(sorcery.data.gems) do sorcery.register_gem(g,v) end sorcery.gem = { getdrops = function(fac) items = {} Index: harvester.lua ================================================================== --- harvester.lua +++ harvester.lua @@ -18,11 +18,11 @@ drawtype = 'mesh'; paramtype = 'light'; paramtype2 = 'facedir'; mesh = 'sorcery-harvester.obj'; after_dig_node = sorcery.lib.node.purge_container; - groups = { cracky = 2; oddly_breakable_by_hand = 1; }; + groups = { cracky = 2; oddly_breakable_by_hand = 1; sorcery_magitech = 1; }; sunlight_propagates = true; selection_box = hitbox; collision_box = hitbox; tiles = { amethyst:render(); Index: infuser.lua ================================================================== --- infuser.lua +++ infuser.lua @@ -205,11 +205,14 @@ "default_steel_block.png", "default_bronze_block.png", "default_tin_block.png", }; paramtype2 = 'facedir'; - groups = {cracky = 2, oddly_breakable_by_hand = 1, heavy = 1}; + groups = { + cracky = 2, oddly_breakable_by_hand = 1, heavy = 1; + sorcery_alchemy = 1, sorcery_magitech = 1; + }; selection_box = { type = 'fixed'; fixed = { -0.37, -0.5, -0.37, 0.37, 0.5, 0.37 Index: init.lua ================================================================== --- init.lua +++ init.lua @@ -27,17 +27,19 @@ -- careful about the order they're loaded in sorcery.unit('data') {'ui'} sorcery.unit('lib') { -- convenience - 'str', 'node'; + 'str'; -- serialization 'marshal', 'json'; -- data structures 'tbl', 'class'; -- wrappers 'color', 'image', 'ui'; + -- game + 'node'; } sorcery.unit() { 'compat', 'matreg' } sorcery.unit('data') { 'compat'; @@ -49,12 +51,13 @@ 'philters', 'extracts'; 'register'; } for _,u in pairs { - 'ores'; 'gems'; 'leylines'; + 'attunement'; 'ores'; 'gems'; 'leylines'; 'potions'; 'infuser'; 'altar'; 'wands'; - 'tools'; 'enchanter'; 'harvester'; + 'tools'; 'crafttools'; 'enchanter'; 'harvester'; 'metallurgy-hot', 'metallurgy-cold'; 'entities'; 'recipes'; 'coins'; 'interop'; 'tnodes'; 'forcefield'; + 'farcaster'; 'portal'; 'cookbook'; 'disassembly'; } do sorcery.load(u) end Index: leylines.lua ================================================================== --- leylines.lua +++ leylines.lua @@ -160,11 +160,10 @@ paramtype2 = 'facedir'; groups = { cracky = 2; choppy = 1; sorcery_ley_device = 1; - sorcery_ley_conduit = 1; }; _sorcery = { ley = { mode = 'signal'; power = 5; } }; tiles = tiles; @@ -209,10 +208,11 @@ sorcery_ley_device = 1; snappy = 3; attached = 1; sorcery_ley_cable = 1; }; _sorcery = { ley = { mode = 'signal', power = metal.conduct }; + recipe = { note = 'Conducts up to ' .. metal.conduct .. ' thaum/sec'; }; }; sunlight_propagates = true; node_box = { type = 'connected'; disconnected = { -0.05, -0.35, -0.40; 0.05, -0.25, 0.40 }; @@ -307,10 +307,11 @@ emerald:render(); }; groups = { cracky = 2; sorcery_ley_device = 1; + sorcery_magitech = 1; }; on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_string('infotext','Condenser') end; @@ -376,10 +377,11 @@ checked[#checked + 1] = sum local nodename = minetest.get_node(sum).name if nodename == 'ignore' then minetest.load_area(sum) nodename = minetest.get_node(sum).name + print('**** ignorenode, loaded',nodename) end if minetest.get_item_group(nodename,'sorcery_ley_device') ~= 0 or sorcery.data.compat.ley[nodename] then local d = sorcery.ley.sample(pos,1,nodename,{query={mode=true}}) assert(d.mode == 'signal' @@ -487,10 +489,11 @@ sorcery.ley.sample = function(pos,timespan,name,flags) -- returns how much ley-force can be transmitted by a -- device over timespan local ret = {} + minetest.load_area(pos) name = name or minetest.get_node(pos).name flags = flags or {} flags.query = flags.query or { mode = true; power = true; affinity = true; minpower = true; maxpower = true; @@ -563,12 +566,12 @@ if flags.query.maxpower and not ret.maxpower then ret.maxpower = power end end return ret end -sorcery.ley.netcaps = function(pos,timespan,exclude) - local net = sorcery.ley.mapnet(pos) +sorcery.ley.netcaps = function(pos,timespan,exclude,minconduct) + local net = sorcery.ley.mapnet(pos,minconduct) local maxpower = 0 local freepower = 0 local affs,usedaffs = {},{} local flexpowerdevs = {} local devself Index: lib/node.lua ================================================================== --- lib/node.lua +++ lib/node.lua @@ -1,6 +1,48 @@ +local ofs = { + neighbors = { + {x = 1, y = 0, z = 0}; + {x = -1, y = 0, z = 0}; + {x = 0, y = 1, z = 0}; + {x = 0, y = -1, z = 0}; + {x = 0, y = 0, z = 1}; + {x = 0, y = 0, z = -1}; + }; + planecorners = { + {x = 1, y = 0, z = 1}; + {x = -1, y = 0, z = 1}; + {x = -1, y = 0, z = -1}; + {x = 1, y = 0, z = -1}; + + {x = 1, y = 1, z = 0}; + {x = -1, y = 1, z = 0}; + {x = -1, y = -1, z = 0}; + {x = 1, y = -1, z = 0}; + }; + cubecorners = { + {x = 1, y = 1, z = 1}; + {x = -1, y = 1, z = 1}; + {x = -1, y = -1, z = 1}; + {x = -1, y = -1, z = -1}; + {x = 1, y = -1, z = -1}; + {x = 1, y = 1, z = -1}; + {x = 1, y = -1, z = 1}; + {x = -1, y = 1, z = -1}; + }; + nextto = { + {x = 1, y = 0, z = 0}; + {x = -1, y = 0, z = 0}; + {x = 0, y = 0, z = 1}; + {x = 0, y = 0, z = -1}; + }; +} + +ofs.adjoining = sorcery.lib.tbl.append(sorcery.lib.tbl.append( + ofs.neighbors,ofs.planecorners),ofs.cubecorners) + return { + offsets = ofs; purge_container = function(pos,node,meta,user) local offset = function(pos,range) local r = function(min,max) return (math.random() * (max - min)) + min end @@ -16,6 +58,38 @@ minetest.add_item(offset(pos,0.4), item) end end end end; + + amass = function(startpoint,names,directions) + if not directions then directions = ofs.neighbors end + local nodes, positions, checked = {},{},{} + local checkedp = function(pos) + for _,v in pairs(checked) do + if vector.equals(pos,v) then return true end + end + return false + end + local i,stack = 1,{startpoint} repeat + local pos = stack[i] + local n = minetest.get_node(pos).name + if sorcery.lib.tbl.has(names, n) then -- match found + -- record the find + nodes[pos] = n + if positions[n] then positions[n][#positions[n]] = pos + else positions[n] = {pos} end + + -- check selected neighbors to see if any need scanning + for _,d in pairs(directions) do + local sum = vector.add(pos, d) + if not checkedp(sum) then + stack[#stack + 1] = sum + end + end + end + checked[#checked+1] = pos + i = i + 1 + until i > #stack + return nodes, positions + end; } Index: lib/tbl.lua ================================================================== --- lib/tbl.lua +++ lib/tbl.lua @@ -1,6 +1,19 @@ local fn = {} + +fn.shuffle = function(list) + for i = #list, 2, -1 do + local j = math.random(i) + list[i], list[j] = list[j], list[i] + end +end + +fn.scramble = function(list) + local new = table.copy(list) + fn.shuffle(new) + return new +end fn.copy = function(t) local new = {} for i,v in pairs(t) do new[i] = v end setmetatable(new,getmetatable(t)) Index: metallurgy-cold.lua ================================================================== --- metallurgy-cold.lua +++ metallurgy-cold.lua @@ -109,11 +109,10 @@ end local mp = item:get_definition()._matprop or sorcery.data.compat.grindables[item:get_name()] or {} - again = true if metal then mp = { hardness = mp.hardness or metal.data.hardness; grindvalue = ((mp.grindvalue or metal.value) or (metal and constants.metal_grindvalue)); powder = mp.powder or metal.data.parts.powder; grindcost = mp.grindcost or constants.metal_grindcost; -- invariant for metal @@ -138,10 +137,11 @@ minetest.register_node('sorcery:mill',{ description = 'Mill'; groups = { cracky = 2; sorcery_ley_device = 1; + sorcery_metallurgy = 1; }; paramtype2 = 'facedir'; after_dig_node = sorcery.lib.node.purge_container; on_construct = function(pos) local meta = minetest.get_meta(pos) @@ -335,11 +335,11 @@ local i,f = metal.parts.ingot, metal.parts.fragment local id = 'sorcery:mill_grindhead_' .. name minetest.register_tool(id,{ description = sorcery.lib.str.capitalize(name) .. ' Grinding Head'; inventory_image = sorcery.lib.image('sorcery_mill_grindhead.png'):multiply(sorcery.lib.color(metal.tone)):render(); - groups = { sorcery_mill_grindhead = 1 }; + groups = { sorcery_mill_grindhead = 1, sorcery_metallurgy = 1 }; _proto = { metal = name; }; }); minetest.register_craft { Index: metallurgy-hot.lua ================================================================== --- metallurgy-hot.lua +++ metallurgy-hot.lua @@ -24,16 +24,18 @@ for _, c in pairs { 'clay', 'aluminum', 'platinum', 'duranium' } do minetest.register_craftitem('sorcery:crucible_' .. c, { description = sorcery.lib.str.capitalize(c .. ' crucible'); inventory_image = 'sorcery_crucible_' .. c .. '.png'; + groups = { sorcery_metallurgy = 1; } }) end minetest.register_craftitem('sorcery:crucible_clay_molding', { description = sorcery.lib.str.capitalize('Crucible molding'); inventory_image = 'sorcery_crucible_clay_molding.png'; + groups = { sorcery_metallurgy = 1; } }) minetest.register_craft { recipe = { { 'default:clay_lump', '', 'default:clay_lump'}; @@ -301,10 +303,11 @@ after_dig_node = sorcery.lib.node.purge_container; mesh = 'sorcery-kiln-' .. state .. '.obj'; drop = id; groups = { cracky = (state == 'open' and 2) or nil; + sorcery_metallurgy = 1; }; sunlight_propagates = true; paramtype1 = 'light'; paramtype2 = 'facedir'; selection_box = box[state]; @@ -382,10 +385,11 @@ description = desc; drop = id; after_dig_node = sorcery.lib.node.purge_container; groups = { cracky = (active and 2) or nil; + sorcery_metallurgy = 1; }; paramtype2 = 'facedir'; light_source = (active and 9) or 0; on_construct = function(pos) local meta = minetest.get_meta(pos) ADDED models/sorcery-disassembler.obj Index: models/sorcery-disassembler.obj ================================================================== --- models/sorcery-disassembler.obj +++ models/sorcery-disassembler.obj @@ -0,0 +1,1569 @@ +# Blender v2.82 (sub 7) OBJ File: 'disassembler.blend' +# www.blender.org +mtllib sorcery-disassembler.mtl +o screwdriver.001_Cube.009 +v 0.043647 -0.410865 0.263791 +v -0.235855 -0.208462 0.264985 +v 0.042206 -0.413038 0.294867 +v -0.237295 -0.210634 0.296060 +v 0.032923 -0.425665 0.262260 +v -0.246578 -0.223261 0.263453 +v 0.031483 -0.427837 0.293335 +v -0.248019 -0.225433 0.294529 +v -0.069214 -0.329136 0.264273 +v -0.070654 -0.331309 0.295349 +v -0.081378 -0.346108 0.293817 +v -0.079937 -0.343936 0.262742 +v 0.303506 -0.237945 -0.358781 +v 0.303506 -0.207010 -0.358781 +v 0.379922 -0.237945 -0.125462 +v 0.379922 -0.207010 -0.125462 +v 0.274108 -0.237945 -0.349152 +v 0.274108 -0.207010 -0.349152 +v 0.350524 -0.237945 -0.115833 +v 0.350524 -0.207010 -0.115833 +v 0.370843 -0.237945 -0.153184 +v 0.312586 -0.237945 -0.331059 +v 0.312586 -0.207010 -0.331059 +v 0.370843 -0.207010 -0.153184 +v 0.283187 -0.237945 -0.321430 +v 0.341444 -0.237945 -0.143555 +v 0.341444 -0.207010 -0.143555 +v 0.283187 -0.207010 -0.321430 +v 0.339948 -0.266738 -0.340020 +v 0.330869 -0.266738 -0.367742 +v 0.330869 -0.178217 -0.367742 +v 0.398205 -0.178217 -0.162145 +v 0.407285 -0.178217 -0.134424 +v 0.407285 -0.266738 -0.134424 +v 0.323161 -0.266738 -0.106872 +v 0.323161 -0.178217 -0.106872 +v 0.314081 -0.266738 -0.134594 +v 0.255825 -0.178217 -0.312469 +v 0.246745 -0.178217 -0.340191 +v 0.246745 -0.266738 -0.340191 +v 0.398205 -0.266738 -0.162146 +v 0.339948 -0.178217 -0.340020 +v 0.255825 -0.266738 -0.312469 +v 0.314081 -0.178217 -0.134594 +v 0.297486 -0.237945 -0.377162 +v 0.297486 -0.207010 -0.377162 +v 0.385942 -0.207010 -0.107080 +v 0.385942 -0.237945 -0.107080 +v 0.356544 -0.237945 -0.097452 +v 0.356544 -0.207010 -0.097452 +v 0.268088 -0.207010 -0.367534 +v 0.268088 -0.237945 -0.367534 +v 0.288658 -0.237945 -0.404117 +v 0.288658 -0.207010 -0.404117 +v 0.259260 -0.207010 -0.394488 +v 0.259260 -0.237945 -0.394488 +v 0.288658 -0.316916 -0.404117 +v 0.297486 -0.316916 -0.377162 +v 0.259260 -0.316916 -0.394488 +v 0.268088 -0.316916 -0.367534 +v 0.251861 -0.207010 -0.417080 +v 0.281259 -0.207010 -0.426708 +v 0.281259 -0.237945 -0.426708 +v 0.251861 -0.237945 -0.417080 +v 0.379922 -0.237945 -0.125462 +v 0.379922 -0.207010 -0.125462 +v 0.303506 -0.237945 -0.358781 +v 0.303506 -0.207010 -0.358781 +v 0.350523 -0.237945 -0.115833 +v 0.350523 -0.207010 -0.115833 +v 0.274108 -0.237945 -0.349152 +v 0.274108 -0.207010 -0.349152 +v 0.312586 -0.237945 -0.331059 +v 0.370843 -0.237945 -0.153184 +v 0.370843 -0.207010 -0.153184 +v 0.312586 -0.207010 -0.331059 +v 0.341444 -0.237945 -0.143555 +v 0.283187 -0.237945 -0.321430 +v 0.283187 -0.207010 -0.321430 +v 0.341444 -0.207010 -0.143555 +v 0.398205 -0.266738 -0.162146 +v 0.407285 -0.266738 -0.134424 +v 0.407285 -0.178217 -0.134424 +v 0.339948 -0.178217 -0.340020 +v 0.330869 -0.178217 -0.367742 +v 0.330869 -0.266738 -0.367742 +v 0.246745 -0.266738 -0.340191 +v 0.246745 -0.178217 -0.340191 +v 0.255825 -0.266738 -0.312469 +v 0.314081 -0.178217 -0.134594 +v 0.323161 -0.178217 -0.106872 +v 0.323161 -0.266738 -0.106872 +v 0.339948 -0.266738 -0.340020 +v 0.398205 -0.178217 -0.162146 +v 0.314081 -0.266738 -0.134594 +v 0.255825 -0.178217 -0.312469 +v 0.385942 -0.237945 -0.107080 +v 0.385942 -0.207010 -0.107080 +v 0.297486 -0.207010 -0.377162 +v 0.297486 -0.237945 -0.377162 +v 0.268088 -0.237945 -0.367534 +v 0.268088 -0.207010 -0.367534 +v 0.356544 -0.207010 -0.097452 +v 0.356544 -0.237945 -0.097452 +v 0.341714 -0.237945 -0.242121 +v 0.341714 -0.207010 -0.242121 +v 0.312316 -0.237945 -0.232493 +v 0.312316 -0.207010 -0.232493 +v 0.394770 -0.237945 -0.080126 +v 0.394770 -0.207010 -0.080126 +v 0.365372 -0.207010 -0.070497 +v 0.365372 -0.237945 -0.070497 +v 0.394770 -0.316916 -0.080126 +v 0.385942 -0.316916 -0.107080 +v 0.365372 -0.316916 -0.070497 +v 0.356544 -0.316916 -0.097452 +v 0.372771 -0.207010 -0.047906 +v 0.402169 -0.207010 -0.057534 +v 0.402169 -0.237945 -0.057534 +v 0.372771 -0.237945 -0.047906 +vt 0.424217 -0.000000 +vt 0.424217 1.000000 +vt 0.575783 1.000000 +vt 0.575783 -0.000000 +vt 0.455431 -0.000000 +vt 0.455431 1.000000 +vt 0.544569 1.000000 +vt 0.544569 -0.000000 +vt 0.575783 -0.000000 +vt 0.575783 1.000000 +vt 0.424217 1.000000 +vt 0.424217 -0.000000 +vt 0.544569 -0.000000 +vt 0.544569 1.000000 +vt 0.455431 1.000000 +vt 0.455431 -0.000000 +vt 0.125000 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.750000 +vt 0.125000 0.750000 +vt 12.373487 1.325346 +vt 12.594831 1.037083 +vt 13.358246 1.748821 +vt 13.136902 2.037083 +vt 0.420366 0.453243 +vt 0.420366 0.612510 +vt 0.272130 0.760747 +vt 0.272130 0.305006 +vt 0.420366 0.453243 +vt 0.579633 0.453243 +vt 0.727871 0.305006 +vt 0.272130 0.305006 +vt 0.271175 0.453243 +vt 0.417201 0.453243 +vt 0.417201 0.046672 +vt 0.271175 0.046672 +vt 0.579633 0.612510 +vt 0.420366 0.612510 +vt 0.272130 0.760747 +vt 0.727871 0.760747 +vt 0.579633 1.148786 +vt 0.420366 1.148786 +vt 0.420366 0.666967 +vt 0.579633 0.666967 +vt 0.417201 0.453243 +vt 0.271175 0.453243 +vt 0.271175 0.046672 +vt 0.417201 0.046672 +vt 0.420366 1.148786 +vt 0.579633 1.148786 +vt 0.579633 0.666967 +vt 0.420366 0.666967 +vt 1.148786 0.453243 +vt 1.148786 0.612510 +vt 0.666967 0.612510 +vt 0.666967 0.453243 +vt 0.420366 0.453243 +vt 0.579633 0.453243 +vt 0.579633 0.046672 +vt 0.420366 0.046672 +vt 0.417201 0.612510 +vt 0.271175 0.612510 +vt 0.666967 0.305006 +vt 0.666967 0.760747 +vt 0.516783 0.760747 +vt 0.516783 0.305006 +vt 0.272130 0.666967 +vt 0.727871 0.666967 +vt 0.727871 0.516783 +vt 0.272130 0.516783 +vt 0.727871 0.666967 +vt 0.272130 0.666967 +vt 0.272130 0.516783 +vt 0.727871 0.516783 +vt 0.579633 0.453243 +vt 0.420366 0.453243 +vt 0.420366 0.046672 +vt 0.579633 0.046672 +vt 0.417201 0.612510 +vt 0.271175 0.612510 +vt 0.516783 0.305006 +vt 0.516783 0.760747 +vt 0.666967 0.760747 +vt 0.666967 0.305006 +vt 0.579633 0.612510 +vt 0.579633 0.453243 +vt 0.727871 0.305006 +vt 0.727871 0.760747 +vt 0.420366 0.271175 +vt 0.579633 0.271175 +vt 0.579633 0.148786 +vt 0.420366 0.148786 +vt 0.579633 0.417201 +vt 0.420366 0.417201 +vt 0.420366 0.271175 +vt 0.579633 0.271175 +vt 0.579633 0.516783 +vt 0.420366 0.516783 +vt 0.516783 0.453243 +vt 0.516783 0.612510 +vt 0.516783 0.612510 +vt 0.516783 0.453243 +vt 0.420366 0.516783 +vt 0.579633 0.516783 +vt 0.579633 0.417201 +vt 0.420366 0.417201 +vt 0.666967 0.453243 +vt 0.666967 0.612510 +vt 1.148786 0.612510 +vt 1.148786 0.453243 +vt 0.579633 0.453243 +vt 0.579633 0.612510 +vt 0.420366 0.612510 +vt 0.420366 0.453243 +vt 0.148786 0.453243 +vt 0.148786 0.612510 +vt 0.148786 0.612510 +vt 0.148786 0.453243 +vt 0.420366 0.148786 +vt 0.579633 0.148786 +vt 0.420366 0.453243 +vt 0.272130 0.305006 +vt 0.272130 0.760747 +vt 0.420366 0.612510 +vt 0.420366 0.453243 +vt 0.272130 0.305006 +vt 0.727871 0.305006 +vt 0.579633 0.453243 +vt 0.271175 0.453243 +vt 0.271175 0.046672 +vt 0.417201 0.046672 +vt 0.417201 0.453243 +vt 0.579633 0.612510 +vt 0.727871 0.760747 +vt 0.272130 0.760747 +vt 0.420366 0.612510 +vt 0.579633 0.666967 +vt 0.420366 0.666967 +vt 0.417201 0.453243 +vt 0.417201 0.046672 +vt 0.271175 0.046672 +vt 0.271175 0.453243 +vt 0.420366 0.666967 +vt 0.579633 0.666967 +vt 0.666967 0.453243 +vt 0.666967 0.612510 +vt 0.420366 0.453243 +vt 0.420366 0.046672 +vt 0.579633 0.046672 +vt 0.579633 0.453243 +vt 0.417201 0.612510 +vt 0.271175 0.612510 +vt 0.666967 0.305006 +vt 0.516783 0.305006 +vt 0.516783 0.760747 +vt 0.666967 0.760747 +vt 0.272130 0.666967 +vt 0.272130 0.516783 +vt 0.727871 0.516783 +vt 0.727871 0.666967 +vt 0.727871 0.666967 +vt 0.727871 0.516783 +vt 0.272130 0.516783 +vt 0.272130 0.666967 +vt 0.579633 0.453243 +vt 0.579633 0.046672 +vt 0.420366 0.046672 +vt 0.420366 0.453243 +vt 0.271175 0.612510 +vt 0.417201 0.612510 +vt 0.516783 0.305006 +vt 0.666967 0.305006 +vt 0.666967 0.760747 +vt 0.516783 0.760747 +vt 0.579633 0.612510 +vt 0.727871 0.760747 +vt 0.727871 0.305006 +vt 0.579633 0.453243 +vt 0.420366 0.271175 +vt 0.420366 0.148786 +vt 0.579633 0.148786 +vt 0.579633 0.271175 +vt 0.579633 0.417201 +vt 0.579633 0.271175 +vt 0.420366 0.271175 +vt 0.420366 0.417201 +vt 0.579633 0.516783 +vt 0.420366 0.516783 +vt 0.516783 0.453243 +vt 0.516783 0.612510 +vt 0.516783 0.612510 +vt 0.516783 0.453243 +vt 0.420366 0.516783 +vt 0.420366 0.417201 +vt 0.579633 0.417201 +vt 0.579633 0.516783 +vt 0.666967 0.453243 +vt 0.666967 0.612510 +vt 0.579633 0.453243 +vt 0.420366 0.453243 +vt 0.420366 0.612510 +vt 0.579633 0.612510 +vt 0.148786 0.612510 +vt 0.148786 0.453243 +vt 0.148786 0.453243 +vt 0.148786 0.612510 +vt 0.579633 0.148786 +vt 0.420366 0.148786 +vt -3.590328 3.610900 +vt -3.901390 2.979239 +vt -4.590328 3.318507 +vt -4.279266 3.950168 +vt -7.329282 -3.981636 +vt -8.018219 -3.642368 +vt -7.707157 -3.010707 +vt -7.018219 -3.349975 +vn 0.5847 0.8069 0.0835 +vn -0.0462 -0.0697 0.9965 +vn -0.5847 -0.8069 -0.0835 +vn 0.0462 0.0697 -0.9965 +vn 0.8099 -0.5865 -0.0035 +vn -0.8099 0.5865 0.0035 +vn -0.3112 0.0000 -0.9503 +vn 0.3112 0.0000 0.9503 +vn 0.9503 0.0000 -0.3112 +vn 0.0000 1.0000 0.0000 +vn -0.9503 0.0000 0.3112 +vn 0.0000 -1.0000 -0.0000 +g screwdriver.001_Cube.009_copper +usemtl copper +s off +f 9/1/1 2/2/1 4/3/1 10/4/1 +f 10/5/2 4/6/2 8/7/2 11/8/2 +f 11/9/3 8/10/3 6/11/3 12/12/3 +f 12/13/4 6/14/4 2/15/4 9/16/4 +f 3/17/5 7/18/5 5/19/5 1/20/5 +f 2/21/6 6/22/6 8/23/6 4/24/6 +f 13/25/7 14/26/7 31/27/7 30/28/7 +f 22/29/8 25/30/8 43/31/8 29/32/8 +f 53/33/9 45/34/9 58/35/9 57/36/9 +f 28/37/8 23/38/8 42/39/8 38/40/8 +f 108/41/10 106/42/10 23/43/10 28/44/10 +f 52/45/11 56/46/11 59/47/11 60/48/11 +f 105/49/12 107/50/12 25/51/12 22/52/12 +f 107/53/11 108/54/11 28/55/11 25/56/11 +f 45/57/8 52/58/8 60/59/8 58/60/8 +f 46/61/9 45/34/9 53/33/9 54/62/9 +f 43/63/11 38/64/11 39/65/11 40/66/11 +f 29/67/12 43/68/12 40/69/12 30/70/12 +f 38/71/10 42/72/10 31/73/10 39/74/10 +f 56/75/7 53/76/7 57/77/7 59/78/7 +f 52/45/11 51/79/11 55/80/11 56/46/11 +f 30/81/9 31/82/9 42/83/9 29/84/9 +f 18/85/7 17/86/7 40/87/7 39/88/7 +f 17/86/7 13/25/7 30/28/7 40/87/7 +f 25/30/8 28/37/8 38/40/8 43/31/8 +f 14/26/7 18/85/7 39/88/7 31/27/7 +f 23/38/8 22/29/8 29/32/8 42/39/8 +f 53/89/12 56/90/12 64/91/12 63/92/12 +f 51/93/10 46/94/10 54/95/10 55/96/10 +f 18/97/10 14/98/10 46/94/10 51/93/10 +f 17/99/11 18/100/11 51/79/11 52/45/11 +f 14/101/9 13/102/9 45/34/9 46/61/9 +f 13/103/12 17/104/12 52/105/12 45/106/12 +f 22/107/9 23/108/9 106/109/9 105/110/9 +f 64/111/7 61/112/7 62/113/7 63/114/7 +f 54/62/9 53/33/9 63/115/9 62/116/9 +f 56/46/11 55/80/11 61/117/11 64/118/11 +f 55/96/10 54/95/10 62/119/10 61/120/10 +f 65/121/8 82/122/8 83/123/8 66/124/8 +f 74/125/7 81/126/7 95/127/7 77/128/7 +f 109/129/9 113/130/9 114/131/9 97/132/9 +f 80/133/7 90/134/7 94/135/7 75/136/7 +f 108/41/10 80/137/10 75/138/10 106/42/10 +f 104/139/11 116/140/11 115/141/11 112/142/11 +f 105/49/12 74/143/12 77/144/12 107/50/12 +f 107/53/11 77/145/11 80/146/11 108/54/11 +f 97/147/7 114/148/7 116/149/7 104/150/7 +f 98/151/9 110/152/9 109/129/9 97/132/9 +f 95/153/11 92/154/11 91/155/11 90/156/11 +f 81/157/12 82/158/12 92/159/12 95/160/12 +f 90/161/10 91/162/10 83/163/10 94/164/10 +f 112/165/8 115/166/8 113/167/8 109/168/8 +f 104/139/11 112/142/11 111/169/11 103/170/11 +f 82/171/9 81/172/9 94/173/9 83/174/9 +f 70/175/8 91/176/8 92/177/8 69/178/8 +f 69/178/8 92/177/8 82/122/8 65/121/8 +f 77/128/7 95/127/7 90/134/7 80/133/7 +f 66/124/8 83/123/8 91/176/8 70/175/8 +f 75/136/7 94/135/7 81/126/7 74/125/7 +f 109/179/12 119/180/12 120/181/12 112/182/12 +f 103/183/10 111/184/10 110/185/10 98/186/10 +f 70/187/10 103/183/10 98/186/10 66/188/10 +f 69/189/11 104/139/11 103/170/11 70/190/11 +f 66/191/9 98/151/9 97/132/9 65/192/9 +f 65/193/12 97/194/12 104/195/12 69/196/12 +f 74/197/9 105/110/9 106/109/9 75/198/9 +f 120/199/8 119/200/8 118/201/8 117/202/8 +f 110/152/9 118/203/9 119/204/9 109/129/9 +f 112/142/11 120/205/11 117/206/11 111/169/11 +f 111/184/10 117/207/10 118/208/10 110/185/10 +f 12/12/5 9/1/5 10/5/5 11/9/5 +f 115/209/12 116/210/12 114/211/12 113/212/12 +f 59/213/12 57/214/12 58/215/12 60/216/12 +o screwdriver.002_Cube.014 +v 0.001121 -0.421942 -0.279823 +v 0.001121 -0.376060 -0.279823 +v 0.163420 -0.421942 -0.113813 +v 0.163420 -0.376060 -0.113813 +v -0.031688 -0.421942 -0.247749 +v -0.031688 -0.376060 -0.247749 +v 0.130612 -0.421942 -0.081738 +v 0.130612 -0.376060 -0.081738 +v 0.500000 -0.426985 0.500000 +v 0.074306 -0.426985 0.500000 +v 0.500000 -0.426985 0.103149 +v 0.074306 -0.426985 0.103149 +v 0.500000 -0.225107 0.103149 +v 0.500000 -0.225107 0.500000 +v 0.074306 -0.225107 0.500000 +v 0.074306 -0.225107 0.103149 +v 0.500000 -0.225107 0.301574 +v 0.074306 -0.225107 0.301574 +v 0.500000 -0.077495 0.301574 +v 0.500000 -0.077495 0.500000 +v 0.074306 -0.077495 0.500000 +v 0.074306 -0.077495 0.301574 +v 0.099049 -0.225107 0.276863 +v 0.099049 -0.225107 0.127860 +v 0.475257 -0.225107 0.127860 +v 0.475257 -0.225107 0.276863 +v 0.099049 -0.403485 0.276863 +v 0.099049 -0.403485 0.127860 +v 0.475257 -0.403485 0.127860 +v 0.475257 -0.403485 0.276863 +v 0.474281 -0.077495 0.327183 +v 0.474281 -0.077495 0.474391 +v 0.100026 -0.077495 0.474391 +v 0.100025 -0.077495 0.327183 +v 0.474281 -0.403355 0.327183 +v 0.474281 -0.403355 0.474391 +v 0.100026 -0.403355 0.474391 +v 0.100025 -0.403355 0.327183 +v -0.347737 -0.288676 -0.035482 +v -0.347737 -0.343523 -0.021635 +v -0.283226 -0.343523 -0.021635 +v -0.283226 -0.288676 -0.035482 +v -0.347737 -0.371696 -0.364314 +v -0.347737 -0.426543 -0.350466 +v -0.283226 -0.426543 -0.350466 +v -0.283226 -0.371696 -0.364314 +v 0.042940 -0.412040 0.297443 +v 0.044608 -0.409524 0.261457 +v -0.069920 -0.330311 0.297925 +v 0.030522 -0.429178 0.295669 +v -0.082339 -0.347449 0.296151 +v 0.032190 -0.426662 0.259683 +v -0.080671 -0.344933 0.260165 +v -0.068252 -0.327795 0.261939 +vt 0.000000 0.401186 +vt 0.000000 0.598814 +vt 1.000000 0.598814 +vt 1.000000 0.401186 +vt 1.000000 0.401186 +vt 1.000000 0.598814 +vt 0.000000 0.598814 +vt 0.000000 0.401186 +vt 0.401186 1.000000 +vt 0.598814 1.000000 +vt 0.598814 0.000000 +vt 0.401186 0.000000 +vt 0.598814 1.000000 +vt 0.401186 1.000000 +vt 0.401186 0.000000 +vt 0.598814 0.000000 +vt -0.603816 -2.866437 +vt -0.603816 -1.866437 +vt 0.396184 -1.866437 +vt 0.396184 -2.866437 +vt -3.780913 -8.696232 +vt -2.780914 -8.696232 +vt -2.780914 -7.696233 +vt -3.780913 -7.696233 +vt 0.069733 0.070792 +vt 1.001979 0.070792 +vt 1.001979 0.545024 +vt 0.535856 0.545024 +vt 0.069733 0.545024 +vt 0.535856 0.545024 +vt 0.069733 0.545024 +vt 0.069733 0.891781 +vt 0.535856 0.891781 +vt 0.000000 0.070792 +vt 1.000000 0.070792 +vt 1.000000 0.545024 +vt 0.000000 0.545024 +vt 1.000000 0.070792 +vt 0.000000 0.070792 +vt 0.000000 0.545024 +vt 1.000000 0.545024 +vt 1.001979 0.070792 +vt 0.069733 0.070792 +vt 1.001979 0.545024 +vt 1.001979 0.000000 +vt 1.001979 1.000000 +vt 0.943929 0.941876 +vt 0.943929 0.058124 +vt 0.535856 0.000000 +vt 0.535856 1.000000 +vt 0.475698 0.939583 +vt 0.475698 0.060417 +vt 0.000000 0.891781 +vt 1.000000 0.891781 +vt 0.000000 0.545024 +vt 1.000000 0.545024 +vt 1.000000 0.891781 +vt 0.000000 0.891781 +vt 0.535856 0.891781 +vt 0.069733 0.891781 +vt 0.058124 0.545024 +vt 0.941876 0.545024 +vt 0.941876 0.125995 +vt 0.058124 0.125995 +vt 0.535856 1.000000 +vt 0.535856 0.000000 +vt 0.593906 0.058124 +vt 0.593906 0.941876 +vt 0.943929 0.941876 +vt 0.593906 0.941876 +vt 0.593906 0.058124 +vt 0.943929 0.058124 +vt 0.593906 0.545024 +vt 0.943929 0.545024 +vt 0.943929 0.125995 +vt 0.593906 0.125995 +vt 0.943929 0.545024 +vt 0.593906 0.545024 +vt 0.593906 0.125995 +vt 0.943929 0.125995 +vt 0.941876 0.545024 +vt 0.058124 0.545024 +vt 0.058124 0.125995 +vt 0.941876 0.125995 +vt 0.060417 0.891781 +vt 0.939583 0.891781 +vt 0.939583 -0.066303 +vt 0.060417 -0.066303 +vt 0.069733 1.000000 +vt 0.069733 0.000000 +vt 0.129891 0.060417 +vt 0.129891 0.939583 +vt 0.475698 0.939583 +vt 0.129891 0.939583 +vt 0.129891 0.060417 +vt 0.475698 0.060417 +vt 0.939583 0.891781 +vt 0.060417 0.891781 +vt 0.060417 -0.066303 +vt 0.939583 -0.066303 +vt 0.475698 0.891781 +vt 0.129891 0.891781 +vt 0.129891 -0.066303 +vt 0.475698 -0.066303 +vt 0.129891 0.891781 +vt 0.475698 0.891781 +vt 0.475698 -0.066303 +vt 0.129891 -0.066303 +vt -0.100000 0.595107 +vt -0.100000 0.404893 +vt 0.900000 0.404893 +vt 0.900000 0.595107 +vt 0.595107 0.416603 +vt 0.595107 0.583397 +vt 0.404893 0.583397 +vt 0.404893 0.416603 +vt -0.100000 0.416603 +vt -0.100000 0.583397 +vt 0.900000 0.583397 +vt 0.900000 0.416603 +vt -0.100000 0.583397 +vt -0.100000 0.416603 +vt 0.900000 0.416603 +vt 0.900000 0.583397 +vt -0.100000 0.404893 +vt -0.100000 0.595107 +vt 0.900000 0.595107 +vt 0.900000 0.404893 +vt 0.576208 0.000000 +vt 0.576208 1.000000 +vt 0.423792 1.000000 +vt 0.423792 0.000000 +vt 0.629579 0.000000 +vt 0.629579 1.000000 +vt 0.370421 1.000000 +vt 0.370421 0.000000 +vt 0.423792 0.000000 +vt 0.423792 1.000000 +vt 0.576208 1.000000 +vt 0.576208 0.000000 +vt 0.370421 0.000000 +vt 0.370421 1.000000 +vt 0.629579 1.000000 +vt 0.629579 0.000000 +vt 1.000000 -0.000000 +vt 1.000000 1.000000 +vt 0.000077 0.999923 +vt 0.000077 0.000077 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 4.684376 -5.655330 +vt 3.857829 -5.655330 +vt 3.684376 -4.672564 +vt 4.510924 -4.672564 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vn 0.7151 0.0000 -0.6991 +vn -0.7151 0.0000 0.6991 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 -0.0000 +vn 0.6991 0.0000 0.7151 +vn -0.6991 0.0000 -0.7151 +vn 1.0000 0.0000 -0.0000 +vn -1.0000 0.0000 0.0000 +vn -0.0000 0.0000 -1.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.9696 -0.2448 +vn -0.0000 -0.2448 -0.9696 +vn 0.0000 -0.9696 0.2448 +vn 0.0462 0.0697 -0.9965 +vn -0.5847 -0.8069 -0.0835 +vn -0.0462 -0.0697 0.9965 +vn 0.5847 0.8069 0.0835 +vn -0.8099 0.5865 0.0035 +vn 0.8099 -0.5865 -0.0035 +vn 0.0000 0.2448 0.9696 +g screwdriver.002_Cube.014_wood +usemtl wood +s off +f 121/217/13 122/218/13 124/219/13 123/220/13 +f 127/221/14 128/222/14 126/223/14 125/224/14 +f 123/225/15 127/226/15 125/227/15 121/228/15 +f 128/229/16 124/230/16 122/231/16 126/232/16 +f 123/233/17 124/234/17 128/235/17 127/236/17 +f 121/237/18 125/238/18 126/239/18 122/240/18 +f 129/241/19 131/242/19 133/243/19 137/244/19 134/245/19 +f 138/246/20 135/247/20 141/248/20 142/249/20 +f 131/250/21 132/251/21 136/252/21 133/253/21 +f 130/254/22 129/255/22 134/256/22 135/257/22 +f 132/258/20 130/259/20 135/247/20 138/246/20 136/260/20 +f 133/261/16 136/262/16 144/263/16 145/264/16 +f 139/265/16 142/266/16 154/267/16 151/268/16 +f 135/257/22 134/256/22 140/269/22 141/270/22 +f 137/271/21 138/272/21 142/273/21 139/274/21 +f 134/245/19 137/244/19 139/275/19 140/276/19 +f 145/277/22 144/278/22 148/279/22 149/280/22 +f 138/281/16 137/282/16 146/283/16 143/284/16 +f 137/282/16 133/261/16 145/264/16 146/283/16 +f 136/262/16 138/281/16 143/284/16 144/263/16 +f 148/285/16 147/286/16 150/287/16 149/288/16 +f 146/289/20 145/290/20 149/291/20 150/292/20 +f 144/293/19 143/294/19 147/295/19 148/296/19 +f 143/297/21 146/298/21 150/299/21 147/300/21 +f 151/301/22 154/302/22 158/303/22 155/304/22 +f 141/305/16 140/306/16 152/307/16 153/308/16 +f 142/266/16 141/305/16 153/308/16 154/267/16 +f 140/306/16 139/265/16 151/268/16 152/307/16 +f 158/309/16 157/310/16 156/311/16 155/312/16 +f 153/313/21 152/314/21 156/315/21 157/316/21 +f 154/317/19 153/318/19 157/319/19 158/320/19 +f 152/321/20 151/322/20 155/323/20 156/324/20 +f 159/325/23 162/326/23 166/327/23 163/328/23 +f 164/329/24 163/330/24 166/331/24 165/332/24 +f 160/333/20 159/334/20 163/335/20 164/336/20 +f 162/337/19 161/338/19 165/339/19 166/340/19 +f 161/341/25 160/342/25 164/343/25 165/344/25 +f 172/345/26 173/346/26 174/347/26 168/348/26 +f 170/349/27 171/350/27 173/351/27 172/352/27 +f 167/353/28 169/354/28 171/355/28 170/356/28 +f 168/357/29 174/358/29 169/359/29 167/360/29 +f 173/361/30 171/362/30 169/363/30 174/364/30 +f 167/365/31 170/366/31 172/367/31 168/368/31 +f 160/369/32 161/370/32 162/371/32 159/372/32 +f 131/373/15 129/374/15 130/375/15 132/376/15 +o screwdriver.003_Cube.015 +v 0.158085 -0.383521 -0.108598 +v 0.158085 -0.414482 -0.108598 +v 0.135946 -0.414482 -0.086954 +v 0.135946 -0.383521 -0.086954 +v 0.296978 -0.383521 0.033471 +v 0.296978 -0.414482 0.033471 +v 0.274839 -0.414482 0.055115 +v 0.274839 -0.383521 0.055115 +v 0.296978 -0.393841 0.033471 +v 0.296978 -0.404161 0.033471 +v 0.274839 -0.393841 0.055115 +v 0.274839 -0.404161 0.055115 +v 0.312696 -0.393841 0.049548 +v 0.312696 -0.404161 0.049548 +v 0.290557 -0.393841 0.071192 +v 0.290557 -0.404161 0.071192 +v 0.300570 -0.393841 0.029960 +v 0.300570 -0.404161 0.029960 +v 0.271248 -0.393841 0.058626 +v 0.271248 -0.404161 0.058626 +v 0.316288 -0.393841 0.046037 +v 0.316288 -0.404161 0.046037 +v 0.286966 -0.393841 0.074704 +v 0.286966 -0.404161 0.074704 +v -0.002015 -0.417557 -0.276758 +v -0.002015 -0.380446 -0.276758 +v -0.028552 -0.380446 -0.250814 +v -0.028552 -0.417557 -0.250814 +v -0.007652 -0.417557 -0.282523 +v -0.007652 -0.380446 -0.282523 +v -0.034188 -0.380446 -0.256579 +v -0.034188 -0.417557 -0.256579 +v -0.251199 -0.388445 0.143113 +v -0.251199 -0.170935 0.088198 +v -0.379763 -0.388445 0.143113 +v -0.379763 -0.170935 0.088198 +v -0.251199 -0.424855 -0.001101 +v -0.251199 -0.207344 -0.056016 +v -0.379763 -0.424855 -0.001101 +v -0.379763 -0.207344 -0.056016 +v -0.237672 -0.210997 0.269398 +v -0.238682 -0.212520 0.291190 +v -0.246202 -0.222898 0.290116 +v -0.245192 -0.221375 0.268324 +v -0.254752 -0.198628 0.269471 +v -0.255762 -0.200151 0.291263 +v -0.263282 -0.210529 0.290188 +v -0.262272 -0.209006 0.268397 +v -0.256924 -0.201625 0.269161 +v -0.257934 -0.203149 0.290952 +v -0.261110 -0.207532 0.290499 +v -0.260100 -0.206008 0.268707 +v -0.274942 -0.188814 0.271518 +v -0.275740 -0.190018 0.288748 +v -0.278916 -0.194401 0.288294 +v -0.278118 -0.193197 0.271065 +v 0.377330 -0.285952 -0.349122 +v 0.377330 -0.070448 -0.349122 +v 0.392567 -0.285952 -0.302599 +v 0.392567 -0.070448 -0.302599 +v 0.220302 -0.285952 -0.297693 +v 0.220302 -0.070448 -0.297693 +v 0.235539 -0.285952 -0.251169 +v 0.235539 -0.070448 -0.251169 +v 0.377330 -0.255225 -0.349122 +v 0.377330 -0.172742 -0.349122 +v 0.392567 -0.172742 -0.302599 +v 0.392567 -0.255226 -0.302599 +v 0.235539 -0.172742 -0.251169 +v 0.235539 -0.255226 -0.251169 +v 0.220302 -0.172742 -0.297693 +v 0.220302 -0.255226 -0.297693 +v 0.396207 -0.070448 -0.291484 +v 0.239179 -0.070448 -0.240055 +v 0.396207 -0.172742 -0.291484 +v 0.239179 -0.172742 -0.240055 +v 0.395886 -0.255226 -0.292463 +v 0.395886 -0.285952 -0.292463 +v 0.238858 -0.285952 -0.241034 +v 0.238858 -0.255226 -0.241034 +v 0.296629 -0.240812 -0.271177 +v 0.281392 -0.240812 -0.317701 +v 0.296629 -0.220446 -0.271177 +v 0.281392 -0.204143 -0.317701 +v 0.281392 -0.207521 -0.317701 +v 0.296629 -0.204143 -0.271177 +v 0.331477 -0.207521 -0.282591 +v 0.316240 -0.204143 -0.329114 +v 0.331477 -0.204143 -0.282591 +v 0.331477 -0.240812 -0.282591 +v 0.316240 -0.240812 -0.329114 +v 0.433728 -0.285952 -0.176921 +v 0.433728 -0.070448 -0.176921 +v 0.418491 -0.285952 -0.223445 +v 0.418491 -0.070448 -0.223445 +v 0.276700 -0.285952 -0.125492 +v 0.276700 -0.070448 -0.125492 +v 0.261463 -0.285952 -0.172016 +v 0.261463 -0.070448 -0.172016 +v 0.433728 -0.255225 -0.176921 +v 0.433728 -0.172742 -0.176921 +v 0.418491 -0.172742 -0.223445 +v 0.418491 -0.255226 -0.223445 +v 0.261463 -0.172742 -0.172016 +v 0.261463 -0.255226 -0.172016 +v 0.276700 -0.172742 -0.125492 +v 0.276700 -0.255226 -0.125492 +v 0.414851 -0.070448 -0.234559 +v 0.257823 -0.070448 -0.183130 +v 0.414851 -0.172742 -0.234559 +v 0.257823 -0.172742 -0.183130 +v 0.415171 -0.255226 -0.233580 +v 0.415171 -0.285952 -0.233580 +v 0.258143 -0.285952 -0.182151 +v 0.258143 -0.255226 -0.182151 +v 0.322553 -0.240812 -0.192024 +v 0.337790 -0.240812 -0.145500 +v 0.322553 -0.220446 -0.192024 +v 0.337790 -0.204143 -0.145500 +v 0.337790 -0.207521 -0.145500 +v 0.322553 -0.204143 -0.192024 +v 0.357401 -0.207521 -0.203437 +v 0.372638 -0.204143 -0.156913 +v 0.357401 -0.204143 -0.203437 +v 0.357401 -0.240812 -0.203437 +v 0.372638 -0.240812 -0.156913 +v 0.380855 -0.429536 -0.404467 +v 0.372027 -0.429536 -0.431422 +v 0.184718 -0.429536 -0.340229 +v 0.175890 -0.429536 -0.367184 +v 0.368023 -0.316916 -0.443648 +v 0.368023 -0.429536 -0.443648 +v 0.171886 -0.316916 -0.379410 +v 0.171886 -0.429536 -0.379410 +v 0.394770 -0.429536 -0.080126 +v 0.365372 -0.429536 -0.070497 +v 0.385942 -0.429536 -0.107080 +v 0.356544 -0.429536 -0.097452 +v 0.341714 -0.429536 -0.242121 +v 0.312316 -0.429536 -0.232493 +v 0.469312 -0.429536 -0.134385 +v 0.478140 -0.429536 -0.107431 +v 0.273174 -0.429536 -0.070147 +v 0.282002 -0.429536 -0.043193 +v 0.425083 -0.429536 -0.269426 +v 0.228946 -0.429536 -0.205188 +v 0.398775 -0.429536 -0.067900 +v 0.369376 -0.429536 -0.058271 +v 0.482144 -0.316916 -0.095204 +v 0.482144 -0.429536 -0.095204 +v 0.286007 -0.316916 -0.030966 +v 0.286007 -0.429536 -0.030966 +vt 0.466448 0.281802 +vt 0.533552 0.281802 +vt 0.533552 0.712415 +vt 0.466448 0.712415 +vt 0.466448 0.511184 +vt 0.466448 0.533552 +vt 0.533552 0.533552 +vt 0.533552 0.511184 +vt 0.281802 0.466448 +vt 0.281802 0.533552 +vt 0.712415 0.533552 +vt 0.712415 0.511184 +vt 0.712415 0.488816 +vt 0.712415 0.466448 +vt 0.281802 0.533552 +vt 0.281802 0.466448 +vt 0.712415 0.466448 +vt 0.712415 0.488816 +vt 0.712415 0.511184 +vt 0.712415 0.533552 +vt 0.533552 0.281802 +vt 0.466448 0.281802 +vt 0.466448 0.712415 +vt 0.533552 0.712415 +vt 0.466448 0.466448 +vt 0.466448 0.488816 +vt 0.533552 0.488816 +vt 0.533552 0.466448 +vt 0.466448 0.712415 +vt 0.466448 0.761147 +vt 0.455562 0.761147 +vt 0.455562 0.712415 +vt 0.466448 0.488816 +vt 0.466448 0.511184 +vt 0.533552 0.511184 +vt 0.533552 0.488816 +vt 0.544438 0.488816 +vt 0.544438 0.511184 +vt 0.533552 0.712415 +vt 0.466448 0.712415 +vt 0.466448 0.761147 +vt 0.533552 0.761147 +vt 0.533552 0.712415 +vt 0.533552 0.761147 +vt 0.712415 0.511184 +vt 0.712415 0.488816 +vt 0.761147 0.488816 +vt 0.761147 0.511184 +vt 0.712415 0.488816 +vt 0.712415 0.511184 +vt 0.761147 0.511184 +vt 0.761147 0.488816 +vt 0.455562 0.511184 +vt 0.455562 0.488816 +vt 0.544438 0.761147 +vt 0.544438 0.712415 +vt 0.455562 0.488816 +vt 0.455562 0.511184 +vt 0.455562 0.712415 +vt 0.455562 0.761147 +vt 0.544438 0.712415 +vt 0.544438 0.761147 +vt 0.544438 0.511184 +vt 0.544438 0.488816 +vt 0.540216 -0.221379 +vt 0.459784 -0.221379 +vt 0.459784 -0.238854 +vt 0.540216 -0.238854 +vt 0.540216 0.459784 +vt 0.540216 0.540216 +vt 0.459784 0.540216 +vt 0.459784 0.459784 +vt -0.221379 0.459784 +vt -0.221379 0.540216 +vt -0.238854 0.540216 +vt -0.238854 0.459784 +vt 0.459784 -0.221379 +vt 0.540216 -0.221379 +vt 0.540216 -0.238854 +vt 0.459784 -0.238854 +vt -0.221379 0.540216 +vt -0.221379 0.459784 +vt -0.238854 0.459784 +vt -0.238854 0.540216 +vt 0.213456 0.000000 +vt 0.213456 1.000000 +vt 0.786544 1.000000 +vt 0.786544 0.000000 +vt 0.057985 0.000000 +vt 0.057985 1.000000 +vt 0.721007 1.000000 +vt 0.721007 0.000000 +vt 0.573077 0.000076 +vt 0.573077 0.999924 +vt 0.000076 0.999924 +vt 0.000076 0.000076 +vt 0.721007 0.000000 +vt 0.721007 1.000000 +vt 0.057985 1.000000 +vt 0.057985 0.000000 +vt 0.057985 0.786544 +vt 0.721007 0.786544 +vt 0.721007 0.213456 +vt 0.057985 0.213456 +vt 0.721007 0.786544 +vt 0.057985 0.786544 +vt 0.057985 0.213456 +vt 0.721007 0.213456 +vt -4.674511 -10.751538 +vt -4.674511 -9.751538 +vt -3.674511 -9.751538 +vt -3.674511 -10.751538 +vt 0.753081 -0.031154 +vt 0.246919 -0.031154 +vt 0.246919 0.456970 +vt 0.753081 0.456970 +vt 0.351158 0.246919 +vt 0.648842 0.246919 +vt 0.562862 0.246919 +vt 0.437138 0.246919 +vt 0.351158 -0.031154 +vt 0.648842 -0.031154 +vt 0.648842 0.456970 +vt 0.351158 0.456970 +vt 0.648842 -0.031154 +vt 0.351158 -0.031154 +vt 0.351158 0.456970 +vt 0.648842 0.456970 +vt 0.246919 -0.031154 +vt 0.753081 -0.031154 +vt 0.753081 0.456970 +vt 0.246919 0.456970 +vt 0.246919 0.456970 +vt 0.753081 0.456970 +vt 0.700094 0.968846 +vt 0.299906 0.968846 +vt 0.648842 0.753081 +vt 0.351158 0.753081 +vt 0.437138 0.753081 +vt 0.562862 0.753081 +vt 0.562862 0.700094 +vt 0.437138 0.700094 +vt 0.437138 0.299906 +vt 0.562862 0.299906 +vt 0.753081 0.456970 +vt 0.246919 0.456970 +vt 0.299906 0.968846 +vt 0.700094 0.968846 +vt 0.437138 0.456970 +vt 0.562862 0.456970 +vt 0.562862 0.968846 +vt 0.437138 0.968846 +vt 0.562862 0.456970 +vt 0.437138 0.456970 +vt 0.437138 0.968846 +vt 0.562862 0.968846 +vt 0.330609 0.624954 +vt 0.330609 1.099628 +vt 0.557773 1.099628 +vt 0.557773 0.624954 +vt 0.875000 0.500000 +vt 0.625000 0.500000 +vt 0.625000 0.500000 +vt 0.875000 0.500000 +vt 0.557773 0.624954 +vt 0.557773 1.099628 +vt 0.330609 1.099628 +vt 0.330609 0.624954 +vt 0.541667 0.750000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.541667 1.000000 +vt 0.125000 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.750000 +vt 0.125000 0.750000 +vt 0.875000 0.750000 +vt 0.458333 0.750000 +vt 0.458333 1.000000 +vt 0.375000 1.000000 +vt 0.506529 0.855413 +vt 0.472895 0.855413 +vt 0.472895 0.894587 +vt 0.557773 0.099628 +vt 0.557773 0.242209 +vt 0.330609 0.242209 +vt 0.330609 0.099628 +vt 0.458333 0.250000 +vt 0.458333 0.500000 +vt 0.458333 0.500000 +vt 0.458333 0.250000 +vt 0.541667 0.250000 +vt 0.506529 0.355413 +vt 0.472895 0.355413 +vt 0.472895 0.394587 +vt 0.493471 0.394587 +vt 0.330609 0.099628 +vt 0.330609 0.242209 +vt 0.557773 0.242209 +vt 0.557773 0.099628 +vt 0.541667 0.250000 +vt 0.625000 0.250000 +vt 0.541667 0.500000 +vt 0.612042 0.624954 +vt 0.612042 1.099628 +vt 0.612042 1.099628 +vt 0.612042 0.624954 +vt 0.541667 0.500000 +vt 0.375000 0.250000 +vt 0.375000 0.500000 +vt 0.607264 0.242209 +vt 0.607264 0.099628 +vt 0.607264 0.099628 +vt 0.607264 0.242209 +vt 0.125000 0.500000 +vt 0.375000 0.667406 +vt 0.375000 0.717256 +vt 0.601970 0.717256 +vt 0.625000 0.717256 +vt 0.625000 0.667407 +vt 0.513850 0.667407 +vt 0.375000 0.032744 +vt 0.375000 0.082593 +vt 0.601970 0.082593 +vt 0.625000 0.082593 +vt 0.625000 0.032744 +vt 0.125000 0.667407 +vt 0.125000 0.717256 +vt 0.875000 0.717256 +vt 0.875000 0.667406 +vt 0.509942 0.394587 +vt 0.509942 0.355413 +vt 0.509942 0.894588 +vt 0.509942 0.855413 +vt 0.330609 0.624954 +vt 0.557773 0.624954 +vt 0.557773 1.099628 +vt 0.330609 1.099628 +vt 0.875000 0.500000 +vt 0.875000 0.500000 +vt 0.625000 0.500000 +vt 0.625000 0.500000 +vt 0.557773 0.624954 +vt 0.330609 0.624954 +vt 0.330609 1.099628 +vt 0.557773 1.099628 +vt 0.541667 0.750000 +vt 0.541667 1.000000 +vt 0.625000 1.000000 +vt 0.625000 0.750000 +vt 0.125000 0.500000 +vt 0.125000 0.750000 +vt 0.375000 0.750000 +vt 0.375000 0.500000 +vt 0.875000 0.750000 +vt 0.375000 1.000000 +vt 0.458333 1.000000 +vt 0.458333 0.750000 +vt 0.472895 0.894587 +vt 0.472895 0.855413 +vt 0.506529 0.855413 +vt 0.557773 0.099628 +vt 0.330609 0.099628 +vt 0.330609 0.242209 +vt 0.557773 0.242209 +vt 0.458333 0.250000 +vt 0.458333 0.250000 +vt 0.458333 0.500000 +vt 0.458333 0.500000 +vt 0.493471 0.394587 +vt 0.472895 0.394587 +vt 0.472895 0.355413 +vt 0.506529 0.355413 +vt 0.541667 0.250000 +vt 0.330609 0.099628 +vt 0.557773 0.099628 +vt 0.557773 0.242209 +vt 0.330609 0.242209 +vt 0.541667 0.250000 +vt 0.541667 0.500000 +vt 0.625000 0.250000 +vt 0.612042 1.099628 +vt 0.612042 0.624954 +vt 0.612042 0.624954 +vt 0.612042 1.099628 +vt 0.541667 0.500000 +vt 0.375000 0.250000 +vt 0.375000 0.500000 +vt 0.607264 0.099628 +vt 0.607264 0.242209 +vt 0.607264 0.242209 +vt 0.607264 0.099628 +vt 0.125000 0.500000 +vt 0.375000 0.667406 +vt 0.513850 0.667407 +vt 0.625000 0.667407 +vt 0.625000 0.717256 +vt 0.601970 0.717256 +vt 0.375000 0.717256 +vt 0.375000 0.032744 +vt 0.625000 0.032744 +vt 0.625000 0.082593 +vt 0.601970 0.082593 +vt 0.375000 0.082593 +vt 0.125000 0.667407 +vt 0.125000 0.717256 +vt 0.875000 0.667406 +vt 0.875000 0.717256 +vt 0.509942 0.355413 +vt 0.509942 0.394587 +vt 0.509942 0.855413 +vt 0.509942 0.894588 +vt 0.000000 -0.000000 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 0.781448 0.659162 +vt 0.218553 0.659162 +vt 0.218553 0.352007 +vt 0.781448 0.352007 +vt 0.218553 0.112445 +vt 0.218553 0.500000 +vt 0.457814 0.500000 +vt 0.542185 0.500000 +vt 0.781448 0.500000 +vt 0.781448 0.112445 +vt 0.218553 0.035088 +vt 0.781448 0.035088 +vt 0.781448 0.000000 +vt 0.218553 0.000000 +vt 0.542185 0.964912 +vt 0.542185 1.000000 +vt 0.781448 1.000000 +vt 0.781448 0.964912 +vt 0.457814 0.964912 +vt 0.457814 1.000000 +vt 0.457814 0.887555 +vt 0.542185 0.887555 +vt 0.218553 0.887555 +vt 0.781448 0.887555 +vt 0.218553 0.964912 +vt 0.457814 0.352007 +vt 0.218553 0.352007 +vt 0.218553 0.659162 +vt 0.781448 0.659162 +vt 0.781448 0.352007 +vt 0.542185 0.352007 +vt 1.000000 0.659162 +vt 0.000000 0.659162 +vt 0.000000 0.352007 +vt 0.035088 0.352007 +vt 0.112445 0.352007 +vt 0.500000 0.352007 +vt 0.887555 0.352007 +vt 0.964912 0.352007 +vt 1.000000 0.352007 +vt 0.887555 0.352007 +vt 0.500000 0.352007 +vt 0.112445 0.352007 +vt 0.035088 0.352007 +vt 0.000000 0.352007 +vt 0.000000 0.659162 +vt 1.000000 0.659162 +vt 1.000000 0.352007 +vt 0.964912 0.352007 +vt 0.218553 1.000000 +vn 0.0000 1.0000 0.0000 +vn 0.6991 0.0000 0.7151 +vn 0.7151 0.0000 -0.6991 +vn -0.7151 0.0000 0.6991 +vn 0.0000 -1.0000 -0.0000 +vn -0.6991 0.0000 -0.7151 +vn 0.0000 0.2448 0.9696 +vn -1.0000 -0.0000 0.0000 +vn -0.0000 -0.2448 -0.9696 +vn 1.0000 -0.0000 -0.0000 +vn 0.0000 -0.9696 0.2448 +vn -0.0000 0.9696 -0.2448 +vn 0.5847 0.8069 0.0835 +vn 0.5857 -0.3478 -0.7321 +vn 0.0462 0.0697 -0.9965 +vn -0.0462 -0.0697 0.9965 +vn -0.5847 -0.8069 -0.0835 +vn 0.8360 -0.5487 0.0000 +vn -0.8099 0.5865 0.0035 +vn -0.0374 0.1297 -0.9908 +vn -0.1293 -0.0089 0.9916 +vn 0.9503 0.0000 -0.3112 +vn -0.9503 0.0000 0.3112 +vn -0.3112 0.0000 -0.9503 +vn 0.3112 0.0000 0.9503 +vn 0.9503 0.0000 -0.3113 +vn 0.8099 -0.5865 -0.0035 +g screwdriver.003_Cube.015_steel +usemtl steel +s off +f 175/377/33 178/378/33 182/379/33 179/380/33 +f 183/381/34 179/382/34 182/383/34 185/384/34 +f 176/385/35 175/386/35 179/387/35 183/388/35 184/389/35 180/390/35 +f 178/391/36 177/392/36 181/393/36 186/394/36 185/395/36 182/396/36 +f 177/397/37 176/398/37 180/399/37 181/400/37 +f 180/401/34 184/402/34 186/403/34 181/404/34 +f 183/405/33 187/406/33 195/407/33 191/408/33 +f 188/409/34 187/410/34 189/411/34 190/412/34 +f 185/384/38 186/403/38 194/413/38 193/414/38 +f 186/415/37 184/416/37 188/417/37 190/418/37 +f 183/405/33 185/419/33 189/420/33 187/406/33 +f 193/421/36 194/422/36 198/423/36 197/424/36 +f 192/425/35 191/426/35 195/427/35 196/428/35 +f 184/402/38 183/381/38 191/429/38 192/430/38 +f 186/415/37 190/418/37 198/431/37 194/432/37 +f 187/410/34 188/409/34 196/433/34 195/434/34 +f 188/417/37 184/416/37 192/435/37 196/436/37 +f 189/420/33 185/419/33 193/437/33 197/438/33 +f 190/412/34 189/411/34 197/439/34 198/440/34 +f 201/441/33 200/442/33 204/443/33 205/444/33 +f 206/445/38 205/446/38 204/447/38 203/448/38 +f 202/449/36 201/450/36 205/451/36 206/452/36 +f 199/453/37 202/454/37 206/455/37 203/456/37 +f 200/457/35 199/458/35 203/459/35 204/460/35 +f 207/461/39 208/462/39 210/463/39 209/464/39 +f 209/465/40 210/466/40 214/467/40 213/468/40 +f 213/469/41 214/470/41 212/471/41 211/472/41 +f 211/473/42 212/474/42 208/475/42 207/476/42 +f 209/477/43 213/478/43 211/479/43 207/480/43 +f 214/481/44 210/482/44 208/483/44 212/484/44 +f 176/398/38 177/397/38 178/391/38 175/377/38 +f 199/485/34 200/486/34 201/487/34 202/488/34 +f 216/489/45 215/490/45 219/491/45 220/492/45 +f 219/493/46 222/494/46 226/495/46 223/496/46 +f 215/497/47 218/498/47 222/499/47 219/500/47 +f 217/501/48 216/502/48 220/503/48 221/504/48 +f 218/505/49 217/506/49 221/507/49 222/508/49 +f 226/509/49 225/510/49 229/511/49 230/512/49 +f 221/513/50 220/514/50 224/515/50 225/516/50 +f 222/494/51 221/513/51 225/516/51 226/495/51 +f 220/514/51 219/493/51 223/496/51 224/515/51 +f 229/517/51 228/518/51 227/519/51 230/520/51 +f 224/521/45 223/522/45 227/523/45 228/524/45 +f 223/525/52 226/526/52 230/527/52 227/528/52 +f 225/529/53 224/530/53 228/531/53 229/532/53 +f 240/533/54 232/534/54 234/535/54 241/536/54 +f 234/537/33 238/538/33 248/539/33 247/540/33 +f 243/541/55 238/542/55 236/543/55 245/544/55 +f 245/545/56 236/546/56 232/547/56 240/548/56 +f 233/549/37 237/550/37 235/551/37 231/552/37 +f 238/538/33 234/537/33 232/553/33 236/546/33 +f 235/551/56 246/554/56 239/555/56 231/556/56 +f 246/554/56 245/545/56 259/557/56 256/558/56 265/559/56 239/555/56 +f 237/560/55 244/561/55 246/562/55 235/563/55 +f 244/561/55 243/541/55 245/544/55 246/562/55 +f 242/564/33 244/565/33 254/566/33 251/567/33 +f 242/564/57 241/568/57 261/569/57 264/570/57 255/571/57 257/572/57 244/565/57 +f 231/573/54 239/574/54 242/575/54 233/576/54 +f 239/574/54 240/533/54 241/536/54 242/575/54 +f 249/577/57 247/578/57 248/539/57 250/579/57 +f 238/542/55 243/541/55 250/580/55 248/581/55 +f 241/536/58 234/535/58 247/582/58 249/583/58 +f 243/584/37 241/568/37 249/577/37 250/579/37 +f 252/585/57 251/567/57 254/566/57 253/586/57 +f 233/576/54 242/575/54 251/587/54 252/588/54 +f 244/561/55 237/560/55 253/589/55 254/590/55 +f 237/550/37 233/549/37 252/591/37 253/586/37 +f 255/592/54 256/593/54 259/594/54 258/595/54 260/596/54 257/597/54 +f 265/598/55 264/599/55 261/600/55 263/601/55 262/602/55 +f 264/603/33 265/604/33 256/593/33 255/592/33 +f 260/596/37 258/595/37 262/605/37 263/606/37 +f 244/565/57 257/572/57 260/607/57 263/608/57 261/569/57 241/568/57 243/584/57 +f 239/555/56 265/559/56 262/609/56 258/610/56 259/557/56 245/545/56 240/548/56 +f 275/611/54 276/612/54 269/613/54 267/614/54 +f 269/615/33 282/616/33 283/617/33 273/618/33 +f 278/619/55 280/620/55 271/621/55 273/622/55 +f 280/623/57 275/624/57 267/625/57 271/626/57 +f 268/627/37 266/628/37 270/629/37 272/630/37 +f 273/618/33 271/626/33 267/631/33 269/615/33 +f 270/629/57 266/632/57 274/633/57 281/634/57 +f 281/634/57 274/633/57 300/635/57 291/636/57 294/637/57 280/623/57 +f 272/638/55 270/639/55 281/640/55 279/641/55 +f 279/641/55 281/640/55 280/620/55 278/619/55 +f 277/642/33 286/643/33 289/644/33 279/645/33 +f 277/642/56 279/645/56 292/646/56 290/647/56 299/648/56 296/649/56 276/650/56 +f 266/651/54 268/652/54 277/653/54 274/654/54 +f 274/654/54 277/653/54 276/612/54 275/611/54 +f 284/655/56 285/656/56 283/617/56 282/657/56 +f 273/622/55 283/658/55 285/659/55 278/619/55 +f 276/612/54 284/660/54 282/661/54 269/613/54 +f 278/662/37 285/656/37 284/655/37 276/650/37 +f 287/663/56 288/664/56 289/644/56 286/643/56 +f 268/652/54 287/665/54 286/666/54 277/653/54 +f 279/641/55 289/667/55 288/668/55 272/638/55 +f 272/630/37 288/664/37 287/669/37 268/627/37 +f 290/670/54 292/671/54 295/672/54 293/673/54 294/674/54 291/675/54 +f 300/676/55 297/677/55 298/678/55 296/679/55 299/680/55 +f 299/681/33 290/670/33 291/675/33 300/682/33 +f 295/672/37 298/683/37 297/684/37 293/673/37 +f 279/645/56 278/662/56 276/650/56 296/649/56 298/685/56 295/686/56 292/646/56 +f 274/633/57 275/624/57 280/623/57 294/637/57 293/687/57 297/688/57 300/635/57 +f 305/689/33 307/690/33 325/691/33 323/692/33 +f 307/693/56 305/694/56 306/695/56 308/696/56 +f 301/697/37 319/698/37 313/699/37 314/700/37 320/701/37 303/702/37 +f 302/703/37 304/704/37 308/705/37 306/706/37 +f 304/704/37 302/703/37 301/697/37 303/702/37 +f 310/707/37 322/708/37 326/709/37 318/710/37 +f 309/711/37 321/712/37 322/708/37 310/707/37 +f 311/713/37 309/711/37 310/707/37 312/714/37 +f 312/714/37 314/700/37 313/699/37 311/713/37 +f 313/699/37 319/698/37 315/715/37 311/713/37 +f 312/714/37 317/716/37 320/701/37 314/700/37 +f 311/713/37 315/715/37 316/717/37 309/711/37 +f 310/707/37 318/710/37 317/716/37 312/714/37 +f 321/718/57 324/719/57 323/720/57 325/721/57 326/722/57 322/723/57 +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 +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 +f 316/717/37 324/742/37 321/712/37 309/711/37 +f 215/497/59 216/502/59 217/506/59 218/498/59 +o screwdriver.004_Cube.016 +v -0.500000 -0.426985 -0.500000 +v -0.500000 -0.500000 -0.500000 +v 0.500000 -0.426985 -0.500000 +v 0.500000 -0.500000 -0.500000 +v -0.500000 -0.426985 0.500000 +v -0.500000 -0.500000 0.500000 +v 0.500000 -0.426985 0.500000 +v 0.500000 -0.500000 0.500000 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt -0.000000 1.000000 +vt 0.000000 0.000000 +vt 0.021155 0.465926 +vt 0.021155 0.538941 +vt 1.021155 0.538941 +vt 1.021155 0.465926 +vt 1.021155 0.465926 +vt 1.021155 0.538941 +vt 0.021155 0.538941 +vt 0.021155 0.465926 +vt 0.021155 1.010579 +vt 1.021155 1.010579 +vt 1.021155 0.010579 +vt 0.021155 0.010579 +vt 0.010579 0.465926 +vt 0.010579 0.538941 +vt 1.010579 0.538941 +vt 1.010579 0.465926 +vt 1.010579 0.465926 +vt 1.010579 0.538941 +vt 0.010579 0.538941 +vt 0.010579 0.465926 +vn 0.0000 1.0000 0.0000 +vn -1.0000 0.0000 0.0000 +vn 1.0000 0.0000 -0.0000 +vn 0.0000 -1.0000 -0.0000 +vn 0.0000 0.0000 1.0000 +vn -0.0000 0.0000 -1.0000 +g screwdriver.004_Cube.016_stone +usemtl stone +s off +f 327/743/60 331/744/60 333/745/60 329/746/60 +f 332/747/61 331/748/61 327/749/61 328/750/61 +f 330/751/62 329/752/62 333/753/62 334/754/62 +f 332/755/63 328/756/63 330/757/63 334/758/63 +f 334/759/64 333/760/64 331/761/64 332/762/64 +f 328/763/65 327/764/65 329/765/65 330/766/65 +o screwdriver.005_Cube.017 +v -0.180198 -0.430345 0.353438 +v -0.180198 -0.273910 0.353438 +v -0.336633 -0.430345 0.353438 +v -0.336633 -0.273910 0.353438 +v -0.180198 -0.430345 0.197003 +v -0.180198 -0.273910 0.197003 +v -0.336633 -0.430345 0.197003 +v -0.336633 -0.273910 0.197003 +v -0.214051 -0.273910 0.319585 +v -0.302780 -0.273910 0.319585 +v -0.302780 -0.273910 0.230856 +v -0.214051 -0.273910 0.230856 +v -0.214051 -0.247453 0.319585 +v -0.302780 -0.247453 0.319585 +v -0.302780 -0.247453 0.230856 +v -0.214051 -0.247453 0.230856 +v -0.233435 -0.247453 0.300201 +v -0.283396 -0.247453 0.300201 +v -0.283396 -0.247453 0.250240 +v -0.233435 -0.247453 0.250240 +v -0.233435 -0.284338 0.300201 +v -0.283396 -0.284338 0.300201 +v -0.283396 -0.284338 0.250240 +v -0.233435 -0.284338 0.250240 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 1.000000 +vt 0.000000 0.000000 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 0.072331 0.927669 +vt 0.927669 0.927669 +vt 0.927669 0.072331 +vt 0.072331 0.072331 +vt 0.000000 0.000000 +vt 0.216403 0.216403 +vt 0.216403 0.783597 +vt 0.000000 0.350907 +vt 1.000000 0.350907 +vt 1.000000 0.649093 +vt 0.000000 0.649093 +vt 1.000000 0.000000 +vt 0.783597 0.216403 +vt 0.783597 0.783597 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 0.781535 0.781535 +vt 0.781535 0.218465 +vt 1.000000 0.350907 +vt 0.000000 0.350907 +vt 0.000000 0.649093 +vt 1.000000 0.649093 +vt 0.000000 0.350907 +vt 0.000000 0.649093 +vt 1.000000 0.350907 +vt 1.000000 0.649093 +vt 1.000000 0.658562 +vt 0.000000 0.658562 +vt 0.000000 0.341438 +vt 1.000000 0.341438 +vt 0.000000 1.000000 +vt 0.000000 0.000000 +vt 0.218465 0.218465 +vt 0.218465 0.781535 +vt 1.000000 0.658562 +vt 1.000000 0.341438 +vt 1.000000 0.658562 +vt 0.000000 0.658562 +vt 0.000000 0.341438 +vt 1.000000 0.341438 +vt 0.000000 0.658562 +vt 0.000000 0.341438 +vn 0.0000 0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +vn -0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 -0.0000 +vn 0.0000 -1.0000 -0.0000 +vn 0.0000 1.0000 -0.0000 +g screwdriver.005_Cube.017_gold +usemtl gold +s off +f 335/767/66 336/768/66 338/769/66 337/770/66 +f 337/771/67 338/772/67 342/773/67 341/774/67 +f 341/774/68 342/773/68 340/775/68 339/776/68 +f 339/777/69 340/778/69 336/768/69 335/767/69 +f 337/779/70 341/780/70 339/781/70 335/782/70 +f 338/772/71 336/783/71 343/784/71 344/785/71 +f 343/786/69 346/787/69 350/788/69 347/789/69 +f 336/783/71 340/790/71 346/791/71 343/784/71 +f 342/773/71 338/772/71 344/785/71 345/792/71 +f 340/790/71 342/773/71 345/792/71 346/791/71 +f 350/793/71 349/794/71 353/795/71 354/796/71 +f 345/797/67 344/798/67 348/799/67 349/800/67 +f 346/801/68 345/797/68 349/800/68 350/802/68 +f 344/803/66 343/786/66 347/789/66 348/804/66 +f 352/805/68 351/806/68 355/807/68 356/808/68 +f 348/809/71 347/810/71 351/811/71 352/812/71 +f 347/810/71 350/793/71 354/796/71 351/811/71 +f 349/794/71 348/809/71 352/812/71 353/795/71 +f 351/806/67 354/813/67 358/814/67 355/807/67 +f 353/815/69 352/816/69 356/817/69 357/818/69 +f 354/819/66 353/815/66 357/818/66 358/820/66 +f 355/807/71 358/814/71 357/818/71 356/817/71 +o screwdriver.006_Cube.018 +v -0.233435 -0.263296 0.300201 +v -0.283396 -0.263296 0.300201 +v -0.283396 -0.263296 0.250240 +v -0.233435 -0.263296 0.250240 +v -0.233435 -0.270554 0.300201 +v -0.283396 -0.270554 0.300201 +v -0.283396 -0.270554 0.250240 +v -0.233435 -0.270554 0.250240 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 0.000000 0.000000 +vt 1.000000 0.000000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn -1.0000 0.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.0000 -1.0000 +g screwdriver.006_Cube.018_ink +usemtl ink +s off +f 361/821/72 362/822/72 359/823/72 360/824/72 +f 365/825/73 364/826/73 363/827/73 366/828/73 +f 359/823/74 362/822/74 366/828/74 363/827/74 +f 361/821/75 360/824/75 364/826/75 365/825/75 +f 362/822/76 361/821/76 365/825/76 366/828/76 +f 360/824/77 359/823/77 363/827/77 364/826/77 Index: ores.lua ================================================================== --- ores.lua +++ ores.lua @@ -105,15 +105,18 @@ }; }; end -- TODO: replace crafting recipe with kiln recipe minetest.register_craft { - output = screw.. ' 4'; + output = screw.. ' 8'; recipe = { - {fragment,fragment,fragment}; - {'', fragment,''}; - {'', fragment,''}; + {'', 'xdecor:hammer',''}; + { fragment,fragment,fragment}; + {'', fragment,''}; + }; + replacements = { + {'xdecor:hammer','xdecor:hammer'}; }; } if not sorcery.compat.defp(ingot) then -- TODO: remove instant_ores dependency instant_ores.register_metal { @@ -142,17 +145,17 @@ description = sorcery.lib.str.capitalize(name) .. ' Fragment'; }) minetest.register_craft { type = 'cooking'; recipe = powder; - cooktime = (metal.cooktime or 4) * 1.5; + cooktime = (metal.cooktime or 4) * 0.25; output = fragment; } minetest.register_craft { type = 'cooking'; recipe = ingot; - cooktime = (metal.cooktime or 4) / 2; + cooktime = (metal.cooktime or 4) * 0.5; output = fragment .. ' ' .. tostring(fragments_per_ingot); } do local rec = {} for i=1,fragments_per_ingot do rec[#rec+1]=fragment @@ -179,12 +182,14 @@ if metal.sinter then local powders = {} for _,m in pairs(metal.sinter) do powders[#powders+1] = 'sorcery:powder_' .. m end + if metal.sinter_catalyst then for _,m in pairs(metal.sinter_catalyst) + do powders[#powders+1] = m end end minetest.register_craft { type = 'shapeless'; output = powder .. ' ' .. tostring(#powders); recipe = powders; }; end end ADDED portal.lua Index: portal.lua ================================================================== --- portal.lua +++ portal.lua @@ -0,0 +1,467 @@ +local constants = { + portal_max_height = 5; + -- maximum y-distance between a portal pad and its + -- corresponding reflector + portal_min_height = 1; + -- minimum y-distance. should probably be 2 but maybe + -- half-size portals will be useful for transporting + -- items or something + portal_jump_time = 8; + -- number of seconds until teleportation occurs + portal_jump_cost_local = 1; + -- energy required to make a jump from one portal + -- to another on the local circuit + portal_jump_cost_per_farcaster = 2; + -- energy cost required to power each farcaster along + -- the route to the final destination (remote only) + portal_node_power = 0.1; + -- amount of power needed for each portal node to operate + -- and be reachable +} +minetest.register_node('sorcery:portal_pad', { + description = 'Portal Pad'; + groups = { + cracky = 2; sorcery_portal_node = 1; + sorcery_magitech = 1; + }; + tiles = { + 'sorcery_portal_pad_top.png'; + 'sorcery_portal_pad_bottom.png'; + 'sorcery_portal_pad_side.png'; + 'sorcery_portal_pad_side.png'; + 'sorcery_portal_pad_front.png^[transformFX'; + 'sorcery_portal_pad_front.png'; + }; +}) + +minetest.register_node('sorcery:portal_reflector', { + description = 'Portal Reflector'; + groups = { + cracky = 2; sorcery_portal_node = 1; + sorcery_magitech = 1; + }; + tiles = { + 'sorcery_portal_pad_bottom.png'; + 'sorcery_portal_pad_top.png'; + 'sorcery_portal_pad_side.png^[transformFY'; + 'sorcery_portal_pad_side.png^[transformFY'; + 'sorcery_portal_pad_front.png^[transformFY^[transformFX'; + 'sorcery_portal_pad_front.png^[transformFY'; + }; +}) + + + +local portal_composition = function(pos) + -- make sure a reasonable amount of the block is loaded + -- so we have a shot at finding a working portal + minetest.load_area( + vector.add(pos, {x = 5, y = 1 + constants.portal_max_height, z = 5}), + vector.add(pos, {x = -5, y = -1 - constants.portal_max_height, z = -5}) + ) + -- starting at a portal node, search connected blocks + -- recursively to locate portal pads and their paired + -- partners. return a table characterizing the portal + -- return false if no portal found + + -- first search immediate neighbors. the portal node + -- can be connected to either reflectors or pads + local startpoint, startwithpads + for _, d in pairs(sorcery.lib.node.offsets.neighbors) do + local sum = vector.add(pos,d) + local name = minetest.get_node(sum).name + if name == 'sorcery:portal_pad' then + startwithpads = true + elseif name == 'sorcery:portal_reflector' then + startwithpads = false + else goto skip end + startpoint = sum + do break end + ::skip::end + + -- if startpoint is not set, a valid portal was not found + if not startpoint then return nil end + local search, partner + if startwithpads then search = 'sorcery:portal_pad' + partner = 'sorcery:portal_reflector' + else search = 'sorcery:portal_reflector' + partner = 'sorcery:portal_pad' end + + local firsthalf = sorcery.lib.node.amass(startpoint,{search},sorcery.lib.node.offsets.nextto) + local min,max,maxheight = nil, nil, 0 + local telepairs = {} + for pos in pairs(firsthalf) do + local found = false + for i=constants.portal_min_height,constants.portal_max_height do + local p = vector.add(pos, {y=(startwithpads and i or 0-i),x=0,z=0}) + local n = minetest.get_node(p).name + if n == partner then + found = true + maxheight = math.max(maxheight, i) + telepairs[#telepairs + 1] = { + pad = startwithpads and pos or p; + reflector = startwithpads and p or pos; + height = i; + } + elseif n ~= 'air' and minetest.get_item_group(n,'air') == 0 then + goto skippad + end + end + if found then + if min then min = { + x = math.min(min.x, pos.x); + y = math.min(min.y, pos.y); + z = math.min(min.z, pos.z); + } else min = pos end + if max then max = { + x = math.max(max.x, pos.x); + y = math.max(max.y, pos.y); + z = math.max(max.z, pos.z); + } else max = pos end + end + ::skippad::end + + if #telepairs == 0 then return nil end + + return { + nodes = telepairs; + dimensions = { + padmin = min; + padmax = max; + height = maxheight; + }; + } +end + +local caster_farnet = function(pos) + local tune = sorcery.attunement.verify(pos) + if not tune then return nil end + + local partner = minetest.get_node(tune.partner) + if partner.name ~= 'sorcery:farcaster' then return nil end + + local ptune = sorcery.attunement.verify(tune.partner) + if ptune.code == tune.code and vector.equals(ptune.partner, pos) then + return tune.partner + end + return nil +end + +local portal_context = { + users = {} +} + +local portal_circuit = function(start) + local circuit = {} + local network = sorcery.farcaster.junction(start,constants.portal_jump_cost_local) -- get the ley of the land. GEDDIT) + for _, n in pairs(network) do + for _, d in pairs(n.caps.net.devices.consume) do + if d.id == 'sorcery:portal_node' and portal_composition(d.pos) then + circuit[#circuit+1] = { + pos = d.pos; + hops = n.hops; + route = n.route; + } + print(' ! found portal node',d.pos) + else + print(' -- skipping node',d.pos,d.id) + end + end + end + return circuit +end + +local portal_disposition = function(dev) + local dim = vector.subtract(dev.dimensions.padmax, dev.dimensions.padmin) + local radius = math.max(dim.x, dim.z, dev.dimensions.height) + local center = vector.add(vector.divide(dim,2), dev.dimensions.padmin) + local objs = minetest.get_objects_inside_radius(center, radius) + local users = {} + local occupads = {} + for _,obj in pairs(objs) do + if minetest.is_player(obj) then + local pos = obj:get_pos() + for _,n in pairs(dev.nodes) do + -- is the player between a pad and reflector pair? + if math.abs(pos.x - n.pad.x) < 0.5 and + math.abs(pos.z - n.pad.z) < 0.5 and + pos.y >= n.pad.y and pos.y <= n.reflector.y then + users[#users+1] = { + object = obj; + slot = n; + } + occupads[n] = true + goto skip + end + end + end + ::skip::end + + local freepads = {} + for _,n in pairs(dev.nodes) do + if not occupads[n] then + freepads[#freepads+1] = n + end + end + + return { + users = users; + freepads = freepads; + radius = radius; + center = center; + bounds = dim; + } +end + +local portal_destination_evaluate = function(circuit,pos) + -- evaluation of the local network occurs before this function + -- is ever even called, so we only need to worry about the + -- farcaster-related transmission costs + for i,c in pairs(circuit) do + if vector.equals(c.pos,pos) then + print('found destination in circuit table',i,dump(c)) + -- the destination is listed in the circuit table + for j,r in pairs(c.route) do + local nc = sorcery.ley.netcaps(pos,1) + print('checking route for sufficient energy to power farcasters', j, nc.freepower) + if nc.freepower < constants.portal_jump_cost_per_farcaster then + return false -- only one route to any given portal node + -- will be listed in the circuit table, so bail early + -- maybe in the future farcasters should charge up, + -- and power should be deducted when they are used? + end + end + -- we've tested every leg of the route, sufficient power is + -- available + return true + end + end + return false +end + +local portal_pick_destination = function(dev,circuit,partner) + if partner then + print('paired: evaluating partner') + if portal_destination_evaluate(circuit,partner) + then return partner end + print('partner failed eval') + end + + local scrambled = sorcery.lib.tbl.scramble(circuit) + for i=1,#scrambled do + print('evaluating destination',i,dump(scrambled[i])) + if portal_destination_evaluate(circuit,scrambled[i].pos) + then return scrambled[i].pos end + print('eval failed') + end + print('no viable destinations in net') +end + +-- minetest.register_lbm { +-- name = 'sorcery:activate_portals'; +-- label = 'activate portals'; +-- run_at_every_load = true; +-- nodenames = { 'sorcery:portal_node' }; +-- action = function(pos,node) +-- minetest.get_node_timer(pos).start(2) +-- end; +-- } + +minetest.register_node('sorcery:portal_node', { + description = 'Portal Node'; + groups = { + cracky = 2; sorcery_portal_node = 2; + sorcery_ley_device = 1; + sorcery_magitech = 1; + }; + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string('infotext','Portal Node') + minetest.get_node_timer(pos):start(1) + end; + on_timer = function(pos,delta) + local dev = portal_composition(pos) + if not dev then return false end + local dsp = portal_disposition(dev) + local crc = portal_circuit(pos) + local cap = sorcery.ley.netcaps(pos,delta) + local tune = sorcery.attunement.verify(pos) + local partner -- raw position of partner node, if any + if tune and tune.partner then + minetest.load_area(tune.partner) + -- we are attuned to a partner, but is it in the circuit? + for _,v in pairs(crc) do + if vector.equals(v.pos,tune.partner) then + print('found partner in circuit') + partner = tune.partner + break + end + end + end + + print("power reqs",cap.self.minpower,cap.self.powerdraw) + if cap.self.minpower ~= cap.self.powerdraw then + print("not enough power") + return true + end + + -- clean out user table + for name,user in pairs(portal_context.users) do + if user and vector.equals(user.portal, pos) then + local found = false + for _,u in pairs(dsp.users) do + if u.object:get_player_name() == name then + found = true + end + end + if not found then + portal_context.users[name] = nil + end + end + end + + -- one user per pad only! + for _,n in pairs(dev.nodes) do + for _,u in pairs(dsp.users) do + if u.slot == n then + local pname = u.object:get_player_name() + if not portal_context.users[pname] then + portal_context.users[pname] = { time = 0, portal = pos } end + local user = portal_context.users[pname] + if not vector.equals(pos,user.portal) then + user.time = 0 + user.portal = pos + end + local cap = sorcery.ley.netcaps(pos,delta) + local jc = (constants.portal_jump_cost_local*delta) + print('free power',cap.freepower,jc) + if not user.dest and cap.freepower >= jc then + user.dest = portal_pick_destination(dev,crc,partner) + else + print('powerdraw',cap.self.powerdraw) + end + if not user.dest then goto skippad else + minetest.load_area(user.dest) + end + local fac = (user.time / constants.portal_jump_time); + minetest.add_particlespawner { + time = 1, amount = 100 + (fac * 200); + minsize = 0.2 + fac*0.7, maxsize = 0.4 + fac*0.9; + minvel = {y = 0.2, x=0,z=0}, maxvel = {y = 0.5, x=0,z=0}; + minacc = {y = 0.0, x=0,z=0}, maxacc = {y = 0.3, x=0,z=0}; + minpos = vector.add(n.pad,{x = -0.5, y = 0.5, z = -0.5}); + maxpos = vector.add(n.pad,{x = 0.5, y = 0.5, z = 0.5}); + texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(255,119,255)):render(); + glow = 14; + minexptime = 1, maxexptime = 1.3; + animation = { + type = 'vertical_frames'; + aspect_w = 16, aspect_h = 16; + }; + } + if user.time >= (constants.portal_jump_time * 0.5) then + minetest.add_particlespawner { + time = 2; + amount = 500 * fac; + minpos = { x = -0.3, y = 0, z = -0.3 }; + maxpos = { x = 0.3, y = 1.5, z = 0.3 }; + minvel = { x = -0.3, y = 0.4, z = -0.3 }; + maxvel = { x = 0.3, y = 0.6, z = 0.3 }; + maxacc = { x = 0, y = 0.5, z = 0 }; + texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(255,144,226)):render(); + minexptime = 1.5; + maxexptime = 2; + minsize = 0.4; + maxsize = 1.6 * fac; + glow = 14; + attached = u.object; + animation = { + type = 'vertical_frames', length = 2.1; + aspect_w = 16, aspect_h = 16; + }; + } + end + if user.time >= constants.portal_jump_time then + local dd = portal_disposition(portal_composition(user.dest)) + if #dd.freepads > 0 then + local destpad = dd.freepads[math.random(#dd.freepads)].pad + local rng = function(min,max) + return (math.random() * (max - min)) + min + end + local oldpos = u.object:get_pos() + local colors = { + {255,95,201}; {199,95,255}; + {142,95,255}; {255,95,154}; + } + for i = 1,128 do + local vel = { + x = rng(-0.6,1.2), y = rng(-0.6,1.2), z = rng(-0.6,1.2) + } + local life = rng(0.5,5) + minetest.add_particle { + pos = vector.add(oldpos, {x = rng(-0.3,0.3), y = rng(0,1.5), z = rng(-0.3,0.3)}); + velocity = vel; + expirationtime = life; + acceleration = vector.multiply(vel, -0.1); + texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(colors[math.random(#colors)]):brighten(rng(1.0,1.4))):render(); + glow = 14; + animation = { + type = 'vertical_frames', length = life + 0.1; + aspect_w = 16, aspect_h = 16; + }; + } + end + u.object:set_pos(vector.add(destpad, {y=0.5,z=0,x=0})) + user.dest = nil + portal_context[pname] = nil + end + else + user.time = user.time + delta + end + + break + end + end + ::skippad::end + return true + end; + tiles = { + 'sorcery_portal_top.png'; + 'sorcery_portal_top.png'; + 'sorcery_portal_side.png'; + 'sorcery_portal_side.png'; + 'sorcery_portal_front.png'; + 'sorcery_portal_front.png'; + }; + _sorcery = { + attune = { + class = 'sorcery:portal'; + accepts = 'sorcery:portal'; + source = true, target = true; + reciprocal = false; + }; + ley = { + mode = 'consume', affinity = {'mandatic'}; + power = function(pos,delta) + -- return power use if device is currently in process + -- of teleporting a player; otherwise, return 0 + local cost = constants.portal_node_power + for _,u in pairs(portal_context.users) do + if u.dest and vector.equals(u.portal, pos) then + print('user is on pad',dump(pos)) + cost = cost + constants.portal_jump_cost_local + end + end + return cost * delta + end; + }; + + on_leychange = function(pos) minetest.get_node_timer(pos):start(1) end; + }; +}) + +sorcery.portal = { + composition = portal_composition; + disposition = portal_disposition; + circuit = portal_circuit; +} Index: potions.lua ================================================================== --- potions.lua +++ potions.lua @@ -56,16 +56,17 @@ sorcery.register_potion('blood', 'Blood', 'A bottle of sacrificial blood, imbued\nwith stolen life force', u.color(219,19,14)) sorcery.register_potion('potion_water', 'Water Bottle', 'A bottle of plain water', u.color(43,90,162)) sorcery.register_potion('holy_water', 'Holy Water','A bottle of consecrated water',u.color(94,138,206),'sparkle',6) -local create_infusion_recipe = function(id,potion,default_basis) +local create_infusion_recipe = function(id,potion,default_basis,proto) if potion.infusion then sorcery.data.register.infusion { infuse = potion.infusion; into = potion.basis or default_basis; output = 'sorcery:' .. id; + _proto = proto; } end end for n,v in pairs(sorcery.data.potions) do @@ -75,18 +76,19 @@ local id = 'potion_' .. string.lower(n) local desc = 'A ' .. ((glow and 'glowing ') or '') .. 'bottle of ' .. string.lower(n) .. ((kind == 'sparkle' and ', fiercely bubbling') or '') .. ' liquid' - sorcery.register_potion(id, n .. ' Potion', desc, color, kind, glow, { + local fullname = n .. ' Potion' + sorcery.register_potion(id, fullname, desc, color, kind, glow, { _proto = v; groups = { sorcery_potion = 1; sorcery_magical = 1; }; }) - create_infusion_recipe(id,v,'sorcery:potion_serene') + create_infusion_recipe(id,v,'sorcery:potion_serene',{data=v,name=fullname}) end for n,potion in pairs(sorcery.data.draughts) do local name = 'draught_' .. n local behavior = { @@ -131,30 +133,32 @@ end end return stack end } - sorcery.register_potion(name, potion.name .. ' Draught', + local fullname = potion.name .. ' Draught' + sorcery.register_potion(name, fullname, potion.desc, u.color(potion.color), potion.style or 'dull', potion.glow or 0, behavior) - create_infusion_recipe(name,potion,'sorcery:potion_luminous') + create_infusion_recipe(name,potion,'sorcery:potion_luminous',{data=potion,name=fullname}) end for n,elixir in pairs(sorcery.data.elixirs) do local color = u.color(elixir.color) local id = 'elixir_' .. string.lower(n) - sorcery.register_potion(id, 'Elixir of ' .. n, nil, color, 'dull', false, { + local fullname = 'Elixir of ' .. n + sorcery.register_potion(id, fullname, nil, color, 'dull', false, { _proto = elixir; groups = { sorcery_elixir = 1; sorcery_magical = 1; }; }) - create_infusion_recipe(id,elixir,'sorcery:potion_misty') + create_infusion_recipe(id,elixir,'sorcery:potion_misty',{data=elixir,name=fullname}) end for n,v in pairs(sorcery.data.oils) do local color = u.color(v.color) local kind = v.style @@ -167,34 +171,39 @@ for n,v in pairs(sorcery.data.greases) do local color = u.color(v.color) local kind = v.style sorcery.register_oil('grease_' .. n, u.str.capitalize(n) .. ' Grease', nil, color, kind, { - groups = { sorcery_grease = 2 } + groups = { sorcery_grease = 1 } }) end for n,v in pairs(sorcery.data.philters) do local color = u.color(v.color) local id = 'philter_' .. n local name = v.name or u.str.capitalize(n) - sorcery.register_potion(id, name .. ' Philter', v.desc, color, 'sparkle',v.glow or 4, { + local fullname = name .. ' Philter' + sorcery.register_potion(id, fullname, v.desc, color, 'sparkle',v.glow or 4, { _proto = v; _protoname = n; groups = { sorcery_magical = 1; sorcery_philter = 1; }; }) - create_infusion_recipe(id,v,'sorcery:potion_viscous') + create_infusion_recipe(id,v,'sorcery:potion_viscous',{data=v,name=fullname}) end for n,v in pairs(sorcery.data.extracts) do local item = v[1] local color = u.color(v[2]) local name = 'extract_' .. n - sorcery.register_potion(name, u.str.capitalize(n) .. ' Extract', nil, color, 'sparkle', false) + sorcery.register_potion(name, u.str.capitalize(n) .. ' Extract', nil, color, 'sparkle', false, { + groups = { + sorcery_extracts = 1; + }; + }) local add_alcohol = function(booze) minetest.register_craft { type = "shapeless"; recipe = { Index: recipes.lua ================================================================== --- recipes.lua +++ recipes.lua @@ -249,41 +249,155 @@ { 'sorcery:infuser_tube', 'sorcery:infuser_tube', 'sorcery:infuser_tube' }; }; output = "sorcery:infuser"; } +minetest.register_craft { + output = "sorcery:displacer"; + recipe = { + {'sorcery:platinum_ingot','sorcery:leyline_stabilizer','sorcery:platinum_ingot'}; + {'sorcery:inverter_coil','sorcery:core_syncretic','sorcery:inverter_coil'}; + {'sorcery:platinum_ingot','default:chest','sorcery:platinum_ingot'}; + }; +} ----- altar --- candles +minetest.register_craft { + output = "sorcery:displacement_node"; + recipe = { + {'sorcery:platinum_ingot','sorcery:screw_tungsten','sorcery:platinum_ingot'}; + {'basic_materials:copper_wire','sorcery:core_syncretic','doors:trapdoor_steel'}; + {'sorcery:platinum_ingot','sorcery:screw_tungsten','sorcery:platinum_ingot'}; + }; + replacements = { + {'basic_materials:copper_wire','basic_materials:empty_spool'}; + }; +} + +minetest.register_craft { + output = 'sorcery:raycaster'; + recipe = { + {'sorcery:gem_amethyst', 'sorcery:gem_amethyst', 'sorcery:gem_amethyst'}; + {'default:gold_ingot','sorcery:beam_generator','default:gold_ingot'}; + {'sorcery:gem_amethyst', 'sorcery:gem_amethyst', 'sorcery:gem_amethyst'}; + }; +} + +minetest.register_craft { + output = 'sorcery:tuning_disc'; + recipe = { + {'sorcery:inverter_coil','sorcery:silver_ingot',''}; + {'sorcery:leyline_stabilizer','sorcery:silver_ingot','sorcery:gem_emerald'}; + {'sorcery:inverter_coil','sorcery:silver_ingot',''}; + }; +} + +minetest.register_craft { + output = 'sorcery:farcaster'; + recipe = { + {'default:gold_ingot','sorcery:iridium_ingot','default:gold_ingot'}; + {'sorcery:core_mandatic','default:diamondblock','sorcery:tuning_disc'}; + {'default:gold_ingot','sorcery:iridium_ingot','default:gold_ingot'}; + }; +} + +minetest.register_craft { + output = 'sorcery:portal_node'; + recipe = { + {'sorcery:tungsten_ingot','sorcery:core_mandatic','sorcery:tungsten_ingot'}; + {'sorcery:aluminum_ingot','sorcery:platinumblock','sorcery:aluminum_ingot'}; + {'sorcery:tungsten_ingot','sorcery:core_mandatic','sorcery:tungsten_ingot'}; + }; +} + +minetest.register_craft { + output = 'sorcery:portal_reflector'; + recipe = { + {'basic_materials:steel_bar','default:tin_ingot','basic_materials:steel_bar'}; + {'sorcery:gem_amethyst','sorcery:inverter_coil','sorcery:gem_amethyst'}; + {'basic_materials:steel_bar','xpanes:bar_flat','basic_materials:steel_bar'}; + } +} + +minetest.register_craft { + output = 'sorcery:portal_pad'; + recipe = { + {'basic_materials:steel_bar','xpanes:bar_flat','basic_materials:steel_bar'}; + {'sorcery:gem_amethyst','sorcery:beam_generator','sorcery:gem_amethyst'}; + {'basic_materials:steel_bar','default:tin_ingot','basic_materials:steel_bar'}; + } +} + +minetest.register_craftitem('sorcery:tuning_disc',{ + description = 'Tuning Disc'; + inventory_image = 'sorcery_tuning_disc.png'; + groups = { + sorcery_magitech = 1; metal = 1; + }; +}); + minetest.register_craftitem('sorcery:core_counterpraxic',{ description = 'Counterpraxis Core'; inventory_image = 'sorcery_core_counterpraxic.png'; + groups = { + sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1; + }; +}); + +minetest.register_craftitem('sorcery:core_mandatic',{ + description = 'Mandatic Core'; + inventory_image = 'sorcery_core_mandatic.png'; + groups = { + sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1; + }; +}); + +minetest.register_craftitem('sorcery:core_syncretic',{ + description = 'Syncresis Core'; + inventory_image = 'sorcery_core_sycretic.png'; + groups = { + sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1; + }; }); --- + minetest.register_craftitem('sorcery:suppression_matrix',{ description = 'Suppression Matrix'; inventory_image = 'sorcery_suppression_matrix.png'; + groups = { + sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1; + }; }); minetest.register_craftitem('sorcery:inverter_coil',{ description = 'Inverter Coil'; inventory_image = 'sorcery_inverter_coil.png'; + groups = { + sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1; + }; }); minetest.register_craftitem('sorcery:beam_generator',{ description = 'Beam Generator'; inventory_image = 'sorcery_beam_generator.png'; + groups = { + sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1; + }; }); minetest.register_craftitem('sorcery:leyline_stabilizer',{ description = 'Leyline Stabilizer'; inventory_image = 'sorcery_leyline_stabilizer.png'; + groups = { + sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1; + }; }); minetest.register_craftitem('sorcery:field_emitter',{ description = 'Field Emitter'; inventory_image = 'sorcery_field_emitter.png'; + groups = { + sorcery_magitech = 1; metal = 1; sorcery_magitech_core = 1; + }; }) minetest.register_craft { output = 'sorcery:leyline_stabilizer'; recipe = { @@ -325,10 +439,28 @@ {'sorcery:gem_ruby_shard','sorcery:tungsten_ingot','sorcery:gem_ruby_shard'}; {'sorcery:tungsten_ingot','sorcery:gem_emerald','sorcery:tungsten_ingot'}; {'sorcery:gem_ruby_shard','sorcery:tungsten_ingot','sorcery:gem_ruby_shard'}; }; } + +minetest.register_craft { + output = 'sorcery:core_syncretic'; + recipe = { + {'sorcery:gem_sapphire_shard','default:gold_ingot','sorcery:gem_sapphire_shard'}; + {'default:gold_ingot','sorcery:gem_diamond','default:gold_ingot'}; + {'sorcery:gem_sapphire_shard','default:gold_ingot','sorcery:gem_sapphire_shard'}; + }; +} + +minetest.register_craft { + output = 'sorcery:core_mandatic'; + recipe = { + {'sorcery:gem_amethyst_shard','sorcery:silver_ingot','sorcery:gem_amethyst_shard'}; + {'sorcery:silver_ingot','sorcery:gem_sapphire','sorcery:silver_ingot'}; + {'sorcery:gem_amethyst_shard','sorcery:silver_ingot','sorcery:gem_amethyst_shard'}; + }; +} minetest.register_craft { output = 'sorcery:inverter_coil'; recipe = { {'sorcery:screw_platinum','basic_materials:steel_wire','sorcery:screw_platinum'}; @@ -374,10 +506,11 @@ replacements = { {'basic_materials:copper_wire', 'basic_materials:empty_spool'}; }; } +---- altar minetest.register_craftitem('sorcery:candle', { -- TODO make candle node inventory_image = 'sorcery_candle.png'; description = 'Votive Candle'; groups = { Index: textures/sorcery_core_counterpraxic.png ================================================================== --- textures/sorcery_core_counterpraxic.png +++ textures/sorcery_core_counterpraxic.png cannot compute difference between binary files ADDED textures/sorcery_core_mandatic.png Index: textures/sorcery_core_mandatic.png ================================================================== --- textures/sorcery_core_mandatic.png +++ textures/sorcery_core_mandatic.png cannot compute difference between binary files ADDED textures/sorcery_core_syncretic.png Index: textures/sorcery_core_syncretic.png ================================================================== --- textures/sorcery_core_syncretic.png +++ textures/sorcery_core_syncretic.png cannot compute difference between binary files ADDED textures/sorcery_farcaster_linear_bottom.png Index: textures/sorcery_farcaster_linear_bottom.png ================================================================== --- textures/sorcery_farcaster_linear_bottom.png +++ textures/sorcery_farcaster_linear_bottom.png cannot compute difference between binary files ADDED textures/sorcery_farcaster_linear_side.png Index: textures/sorcery_farcaster_linear_side.png ================================================================== --- textures/sorcery_farcaster_linear_side.png +++ textures/sorcery_farcaster_linear_side.png cannot compute difference between binary files ADDED textures/sorcery_farcaster_linear_top.png Index: textures/sorcery_farcaster_linear_top.png ================================================================== --- textures/sorcery_farcaster_linear_top.png +++ textures/sorcery_farcaster_linear_top.png cannot compute difference between binary files ADDED textures/sorcery_farcaster_nonlocal_back.png Index: textures/sorcery_farcaster_nonlocal_back.png ================================================================== --- textures/sorcery_farcaster_nonlocal_back.png +++ textures/sorcery_farcaster_nonlocal_back.png cannot compute difference between binary files ADDED textures/sorcery_farcaster_nonlocal_front.png Index: textures/sorcery_farcaster_nonlocal_front.png ================================================================== --- textures/sorcery_farcaster_nonlocal_front.png +++ textures/sorcery_farcaster_nonlocal_front.png cannot compute difference between binary files ADDED textures/sorcery_farcaster_nonlocal_side.png Index: textures/sorcery_farcaster_nonlocal_side.png ================================================================== --- textures/sorcery_farcaster_nonlocal_side.png +++ textures/sorcery_farcaster_nonlocal_side.png cannot compute difference between binary files ADDED textures/sorcery_farcaster_nonlocal_top.png Index: textures/sorcery_farcaster_nonlocal_top.png ================================================================== --- textures/sorcery_farcaster_nonlocal_top.png +++ textures/sorcery_farcaster_nonlocal_top.png cannot compute difference between binary files Index: textures/sorcery_field_emitter.png ================================================================== --- textures/sorcery_field_emitter.png +++ textures/sorcery_field_emitter.png cannot compute difference between binary files ADDED textures/sorcery_portal_front.png Index: textures/sorcery_portal_front.png ================================================================== --- textures/sorcery_portal_front.png +++ textures/sorcery_portal_front.png cannot compute difference between binary files ADDED textures/sorcery_portal_pad_bottom.png Index: textures/sorcery_portal_pad_bottom.png ================================================================== --- textures/sorcery_portal_pad_bottom.png +++ textures/sorcery_portal_pad_bottom.png cannot compute difference between binary files ADDED textures/sorcery_portal_pad_front.png Index: textures/sorcery_portal_pad_front.png ================================================================== --- textures/sorcery_portal_pad_front.png +++ textures/sorcery_portal_pad_front.png cannot compute difference between binary files ADDED textures/sorcery_portal_pad_side.png Index: textures/sorcery_portal_pad_side.png ================================================================== --- textures/sorcery_portal_pad_side.png +++ textures/sorcery_portal_pad_side.png cannot compute difference between binary files ADDED textures/sorcery_portal_pad_top.png Index: textures/sorcery_portal_pad_top.png ================================================================== --- textures/sorcery_portal_pad_top.png +++ textures/sorcery_portal_pad_top.png cannot compute difference between binary files ADDED textures/sorcery_portal_side.png Index: textures/sorcery_portal_side.png ================================================================== --- textures/sorcery_portal_side.png +++ textures/sorcery_portal_side.png cannot compute difference between binary files ADDED textures/sorcery_portal_top.png Index: textures/sorcery_portal_top.png ================================================================== --- textures/sorcery_portal_top.png +++ textures/sorcery_portal_top.png cannot compute difference between binary files ADDED textures/sorcery_tuning_disc.png Index: textures/sorcery_tuning_disc.png ================================================================== --- textures/sorcery_tuning_disc.png +++ textures/sorcery_tuning_disc.png cannot compute difference between binary files ADDED textures/sorcery_vice.png Index: textures/sorcery_vice.png ================================================================== --- textures/sorcery_vice.png +++ textures/sorcery_vice.png cannot compute difference between binary files ADDED textures/sorcery_vidrium_fragment.png Index: textures/sorcery_vidrium_fragment.png ================================================================== --- textures/sorcery_vidrium_fragment.png +++ textures/sorcery_vidrium_fragment.png cannot compute difference between binary files ADDED textures/sorcery_vidrium_powder.png Index: textures/sorcery_vidrium_powder.png ================================================================== --- textures/sorcery_vidrium_powder.png +++ textures/sorcery_vidrium_powder.png cannot compute difference between binary files Index: tnodes.lua ================================================================== --- tnodes.lua +++ tnodes.lua @@ -5,10 +5,11 @@ sunlight_propagates = true; buildable_to = true; pointable = false; walkable = false; floodable = true; + groups = { air = 1; sorcery_air = 1; }; on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_float('duration',10) meta:set_float('timeleft',10) meta:set_int('power',minetest.LIGHT_MAX) Index: wands.lua ================================================================== --- wands.lua +++ wands.lua @@ -14,12 +14,12 @@ pine = { tex = u.image('default_pine_wood.png'); }; apple = { tex = u.image('default_wood.png'); - tree = 'default:wood'; - plank = 'default:plank'; + tree = 'default:tree'; + plank = 'default:wood'; }; acacia = { tex = u.image('default_acacia_wood.png'); }; aspen = { @@ -32,17 +32,43 @@ }; }; core = { obsidian = { item = 'default:obsidian_shard'; - sturdiness = 1.3; - } + sturdiness = 1.5; + }; + cobalt = { + item = 'sorcery:powder_cobalt'; + power = 1.4; + }; + iridium = { + item = 'sorcery:powder_iridium'; + sturdiness = 1.25; + power = 1.25; + }; + lithium = { + item = 'sorcery:powder_lithium'; + power = 1.7; + reliability = 0.85; + }; + gold = { + item = 'sorcery:powder_gold'; + duration = 1.3; + power = 1.3; + }; + tungsten = { + item = 'sorcery:powder_tungsten'; + duration = 1.7; + sturdiness = 1.25; + }; + -- add one that only lets the first wielder + -- ever use the wand }; wire = { gold = { -- gold limits the amount of wear-and-tear on - -- the wand, but causes the effect to weaken as + -- the wand, but causes the power to weaken as -- it empties tone = u.color(255,255,59); tex = u.image('default_gold_block.png'); }; copper = {