@@ -1,12 +1,42 @@ +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 = { @@ -235,41 +265,17 @@ 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; }; @@ -311,8 +317,62 @@ 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; @@ -367,8 +427,120 @@ 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';