Index: cookbook.lua ================================================================== --- cookbook.lua +++ cookbook.lua @@ -31,10 +31,11 @@ vessel = { caption = 'Any Bottle', cnitem = 'vessels:glass_bottle' }; flower = { caption = 'Any Flower', cnitem = 'flowers:rose' }; mushroom = { caption = 'Any Mushroom', cnitem = 'flowers:mushroom_brown' }; water_bucket = { caption = 'Water Bucket', cnitem = 'bucket:bucket_water' }; sorcery_ley_cable = { caption = 'Cable', cnitem = 'sorcery:cable_vidrium' }; + scissors = { caption = 'Scissors', cnitem = 'sorcery:scissors_steel' }; }; } sorcery.cookbook.constants = constants local slot3x3 = { @@ -154,19 +155,21 @@ return desc end; local bookadjs = { -- sets are in reverse order! {'Celestial', 'Divine', 'Inspired', 'Heavenly'; - 'Mystic', 'Diabolic', 'Luminous', 'Forsaken'}; + 'Mystic', 'Diabolic', 'Luminous', 'Forsaken', + 'Ethereal'}; {'Dark', 'Perfected', 'Flawless', 'Unthinkable'; - 'Impossible', 'Worrisome', 'Unimpeachable'}; + 'Impossible', 'Worrisome', 'Unimpeachable', 'Fulsome', + 'Wise'}; {'Splendid', 'Magnificent', 'Sublime', 'Grand'; 'Beneficent', 'Mysterious', 'Peculiar', 'Eerie'; 'Fulsome', 'Fearsome', 'Curious', 'Fascinating'; - 'Notorious', 'Infamous'}; + 'Notorious', 'Infamous', 'Wondrous'}; } local cache = { populate_grindables = function(cache) if not cache.grindables then @@ -314,28 +317,55 @@ 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 + elseif e.item then + rec[i] = e.item + end + if e.consume or (e.item and not e.dmg) then + rec[i] = rec[i] .. ' ' .. tostring(e.consume or 1) -- :/ end end return rec end; props = function(name) - return sorcery.data.enchants[name].info or {} + local ench = sorcery.data.enchants[name] + local p = ench.info + local desc = '' + if ench.cost ~= 0 then + desc = string.format('%s %i thaum-second%s of charge when tool is used', + ench.cost > 0 and 'Consumes' or 'Generates', + math.abs(ench.cost), + ench.cost ~= 1 and 's' or '' + ) + end + + if p == nil then return {note = desc} end + if p.note then return p end + return sorcery.lib.tbl.proto({note = desc},p) 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] + local cap = sorcery.lib.str.capitalize + local aff = sorcery.data.affinities[e.affinity] return sorcery.lib.ui.tooltip { title = e.name; - desc = sorcery.lib.str.capitalize(e.desc); - color = sorcery.lib.color(e.tone):readable(); + desc = cap(e.desc); + color = sorcery.lib.color(e.tone); + props = { + { + title = string.format('%s affinity', cap(e.affinity)); + desc = aff.desc; + color = sorcery.lib.color(aff.color); + }; + }; } end; }; -- spells = { -- booksuf = 'Spellbook'; @@ -400,15 +430,16 @@ end local img, ot if props.note then local nx, ny, nw, nh if notes_right then - nx = 5.25 ny = 0 - nw = 4 nh = 3 + nx = 5.25 - (3 - k.w) -- :/ + ny = 0 + nw = 4 nh = k.h else nx = 0 ny = 3 - nw = 4 nh = 1 + nw = 4 nh = k,h end t = t .. string.format([[ hypertext[%f,%f;%f,%f;note;%s] ]], nx,ny,nw,nh, minetest.formspec_escape(props.note)) end @@ -415,16 +446,16 @@ 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]] .. [[ + box[%f,%f;1.1,1.1;#1a001650] %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, + k.w+1.05, k.h/2 - 0.55, 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; Index: data/enchants.lua ================================================================== --- data/enchants.lua +++ data/enchants.lua @@ -18,11 +18,11 @@ desc = 'tools last longer before wearing out'; affinity = 'counterpraxic'; groups = allgroups; recipe = { {lens = 'convex', gem = 'amethyst', dmg = 2}; - {lens = 'rectifier', gem = 'emerald', dmg = 4}; + {item = 'default:obsidian_shard'}; {lens = 'convex', gem = 'emerald', dmg = 2}; }; apply = function(stack,power,base) local caps = table.copy(stack:get_definition().tool_capabilities) for g,v in pairs(caps.groupcaps) do @@ -44,11 +44,11 @@ cost = 1; tone = {255,235,195}; desc = 'Leave a trail of light hanging in the air as you dig'; recipe = { {lens = 'convex', gem = 'sapphire', dmg = 2}; - {lens = 'concave', gem = 'ruby', dmg = 1}; + {item = 'sorcery:gem_luxite_shard'}; {lens = 'concave', gem = 'sapphire', dmg = 1}; }; on_dig = function(ctx) local chance = 10 -- make dependent on power somehow? if math.random(chance) == 1 then @@ -71,15 +71,18 @@ affinity = 'syncretic'; groups = { 'pick'; 'pickaxe'; 'sword'; }; recipe = { - {lens = 'amplifier', gem = 'ruby', dmg = 5}; - {lens = 'concave', gem = 'mese', dmg = 1}; - {lens = 'concave', gem = 'sapphire', dmg = 1}; + {lens = 'amplifier', gem = 'ruby', dmg = 5}; + {item = 'sorcery:powder_tungsten'}; + {item = 'sorcery:extract_rye'}; }; desc = 'some damage is repaired when used to mine ore or kill an attacker'; + info = { + note = 'Consumes 3 thaum-seconds of charge when repair takes place'; + }; on_dig = function(ctx) local orepfx = "stone_with_" -- }:< -- local oredrop = ' lump' local barename = string.sub(ctx.node.name, string.find(ctx.node.name, ':') + 1) if sorcery.itemclass.get(ctx.node.name,'ore') then @@ -94,11 +97,11 @@ cost = 0; desc = 'enchantments last longer before running out of power to sustain them'; groups = allgroups; affinity = 'syncretic'; recipe = { - {lens = 'rectifier', gem = 'mese', dmg = 7}; + {item = 'default:mese_crystal_fragment'}; {lens = 'rectifier', gem = 'sapphire', dmg = 2}; {lens = 'rectifier', gem = 'amethyst', dmg = 2}; }; -- implemented in sorcery/enchanter.lua:register_on_dig }; @@ -108,11 +111,11 @@ cost = 1; desc = 'strike colored sparks when used to dig near valuable ore.'; groups = {'pick','pickaxe'}; affinity = 'cognic'; recipe = { - {lens = 'concave', gem = 'ruby', dmg = 3}; + {item = 'sorcery:gem_luxite'}; {lens = 'concave', gem = 'emerald', dmg = 3}; {lens = 'concave', gem = 'sapphire', dmg = 3}; }; on_dig = function(ctx) local range = 4*sorcery.enchant.strength(ctx.tool,'dowse') @@ -152,28 +155,25 @@ tone = {255,50,60}; desc = 'dramatically improve your chances of finding gems while mining veins'; groups = {'pick','pickaxe'}; affinity = 'entropic'; recipe = { + {item = 'sorcery:oil_luck'}; {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}; groups = digtools; - { - 'pick';'pickaxe';'axe';'shovel';'sickle'; - }; desc = 'rip through solid stone or wood like a hot knife through butter'; recipe = { {lens = 'amplifier', gem = 'diamond', dmg = 4}; {lens = 'amplifier', gem = 'ruby', dmg = 4}; - {lens = 'rectifier', gem = 'diamond', dmg = 2}; + {item = 'default:flint'}; }; affinity = 'praxic'; apply = function(stack,power,base) local caps = table.copy(stack:get_definition().tool_capabilities) for g,v in pairs(caps.groupcaps) do @@ -190,13 +190,13 @@ name = 'Rend'; affinity = 'praxic'; tone = {251,203,113}; groups = {'sword';'pick';'pickaxe';}; recipe = { - {lens = 'convex', gem = 'mese', dmg = 3}; {lens = 'amplifier', gem = 'emerald', dmg = 7}; - {lens = 'amplifier', gem = 'diamond', dmg = 7}; + {item = 'flowers:flower_rose'}; + {item = 'sorcery:powder_silver'}; }; cost = 5; desc = 'cleave through sturdy ores and tear mortal flesh with fearsome ease'; apply = function(stack,power,base) local caps = table.copy(stack:get_definition().tool_capabilities) @@ -219,11 +219,11 @@ groups = {'sorcery_sanctify'}; affinity = 'entropic'; tone = {255,255,255}; cost = 7; recipe = { - {lens = 'amplifier', gem = 'ruby', dmg = 13}; + {item = 'sorcery:holy_water'}; {lens = 'amplifier', gem = 'ruby', dmg = 15}; {lens = 'amplifier', gem = 'ruby', dmg = 18}; }; }; } Index: data/metals.lua ================================================================== --- data/metals.lua +++ data/metals.lua @@ -394,11 +394,11 @@ cooktime = 120; hardness = 8; maxconduct = 15; sharpness = 5; level = 2; - speed = 1.7; + speed = 2.5; maxenergy = 2200; durability = 1500; slots = { {affinity={'praxic'},confluence=3}; {affinity={'syncretic'},confluence=2}; Index: data/oils.lua ================================================================== --- data/oils.lua +++ data/oils.lua @@ -107,7 +107,19 @@ 'sorcery:extract_grape'; 'farming:cocoa_beans'; 'farming:sugar'; 'farming:sugar'; }; + }; + luck = { + color = {156,54,255}; + style = 'sparkle'; + mix = { + 'sorcery:extract_marram'; + 'farming:hemp_leaf'; + 'farming:hemp_oil'; + 'xdecor:honey'; + 'farming:salt'; + 'farming:salt'; + }; }; } Index: data/runes.lua ================================================================== --- data/runes.lua +++ data/runes.lua @@ -142,10 +142,15 @@ if not target then return false end local subjects if ctx.amulet.frame == 'cobalt' then if ctx.target.type ~= 'object' then return false end subjects = {{ref=ctx.target.ref}} + elseif ctx.amulet.frame == 'iridium' then + subjects = {} + for _,o in pairs(minetest.get_objects_inside_radius(ctx.caster:get_pos(), ctx.stats.power)) do + subjects[#subjects+1] = {player = o} + end else subjects = {{ref=ctx.caster}} end local delay = math.max(5,11 - ctx.stats.power) + 2.3*(math.random()*2-1) local color = sorcery.lib.color(117,38,237) teleport(ctx,subjects,delay,target:get_pos(),color) @@ -866,11 +871,11 @@ desc = 'Bring an exact twin of any object or item into existence, no matter how common or rare it might be'; cast = function(ctx) local color = sorcery.lib.color(255,61,205) local dup, sndpos, anchor, sbj, ty if ctx.target.type == 'object' and ctx.target.ref:get_luaentity().name == '__builtin:item' then - -- sorcery.vfx.imbue(color, ctx.target.ref) -- causes graphics card problems??? + sorcery.vfx.imbue(color, ctx.target.ref) -- causes graphics card problems??? sndpos = 'subjects' sbj = {{player = ctx.target.ref}} local item = ItemStack(ctx.target.ref:get_luaentity().itemstring) local r = function() return math.random() * 2 - 1 end local putpos = vector.offset(ctx.target.ref:get_pos(), r(), 1, r()) Index: data/spells.lua ================================================================== --- data/spells.lua +++ data/spells.lua @@ -29,11 +29,11 @@ end local anchorwand = function(aff,uses,recipe) local affcolor = sorcery.lib.color(sorcery.data.affinities[aff].color) return { name = aff .. ' anchor'; - desc = 'With an enchanter, anchor ' .. aff .. ' spells into an object to enable it to produce preternatural effects'; + desc = 'Destroy items on an enchanter and channel their essence with enchanting lenses to anchor ' .. aff .. ' spells into an object, enabling it to produce preternatural effects'; uses = uses; affinity = recipe; color = affcolor; sound = 'xdecor_enchanting'; -- FIXME make own cast = function(ctx) @@ -114,10 +114,12 @@ then return false end elseif spec.item then default_mode = 'consume' if stack:get_name() ~= spec.item then return false end + if spec.consume and stack:get_count() < spec.consume then + return false end else return false end local mode @@ -127,11 +129,20 @@ if mode == 'dmg' then stack:add_wear((spec.dmg or 1) * 1000) return stack elseif mode == 'consume' then + local r = sorcery.register.residue.db[stack:get_name()] stack:take_item(spec.consume or 1) + if r then + local rs = ItemStack(r) + rs:set_count(rs:get_count() * (spec.consume or 1)) + if stack:is_empty() + then stack = rs + else minetest.add_item(ctx.target.above, rs) + end + end return stack end end for ench,data in pairs(sorcery.data.enchants) do if data.affinity ~= aff or data.recipe == nil then goto skip end @@ -193,11 +204,11 @@ end; }; seal = { name = 'sealing'; color = {255,238,16}; - uses = 32; + uses = 128; desc = 'Bind an object to your spirit such that it will be rendered impregnable to others, or break a sealing created with this same wand'; leytype = 'imperic'; affinity = {'pine','dark'}; cast = function(ctx) if ctx.target == nil or ctx.target.type ~= 'node' then return false end @@ -254,15 +265,15 @@ 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 strength = ley.force + local strength = ley.force * 4 * ley.force if color then strength = strength / #ley.aff for _,a in pairs(ley.aff) do - cast_sparkle(ctx,sorcery.lib.color(sorcery.data.affinities[a].color):brighten(1.3), strength, duration * strength) + cast_sparkle(ctx,sorcery.lib.color(sorcery.data.affinities[a].color):brighten(1.3), strength, duration * (strength*0.5)) end else cast_sparkle(ctx,sorcery.lib.color(250,255,185), strength, duration*strength) end @@ -585,10 +596,11 @@ sorcery.ley.setcharge(rechargee,charge + newenergy) e:set_stack('item',1,rechargee) enchantment_sparkle(ctx, sorcery.lib.color(212,6,63)) + sorcery.enchant.update_enchanter(ctx.target.under) end; }; transfer = { name = 'transfer'; uses = 65; @@ -626,10 +638,11 @@ else table.remove(e.spells, math.random(#e.spells)) end end sorcery.enchant.set(item,e) ei:set_stack('item',1,item) + sorcery.enchant.update_enchanter(ctx.target.under) enchantment_sparkle(ctx,sorcery.lib.color(255,154,44)) enchantment_sparkle(ctx,sorcery.lib.color(226,44,255)) end; }; divine = { Index: entities.lua ================================================================== --- entities.lua +++ entities.lua @@ -5,11 +5,11 @@ } minetest.register_entity('sorcery:spell_projectile_flamebolt',{ initial_properties = { visual = "sprite"; - use_texture_alpha = true; + use_texture_alpha = 'blend'; textures = {'sorcery_fireball.png'}; visual_size = { x = 2, y = 2, z = 2 }; physical = true; collide_with_objects = true; pointable = false; DELETED hotmetallurgy.lua Index: hotmetallurgy.lua ================================================================== --- hotmetallurgy.lua +++ hotmetallurgy.lua @@ -1,446 +0,0 @@ --- alloying furnace --- --- there are several kinds of alloy furnace, with varying --- capabilities. the simplest can alloy two simple metals; --- the most complex can alloy four high-grade metals such --- as titanium, platinum, iridium, or levitanium. --- --- furnace recipes follow a pattern: the number of crucibles --- determines the input slots, the type of crucible determines --- how hot the furnace can get, and various other components --- (like a coolant circulator) can be added to allow the --- creation of exotic metals. --- --- alloy furnaces produce ingots that can later be melted down --- again and cast into a mold to produce items of particular --- shapes. - --- there are five kinds of crucibles: clay, aluminum, platinum, --- duridium, and impervium. clay crucibles are made by molding --- clay into the proper shape and then firing it in a furnace. --- others are made by casting. - -local fragments_per_ingot = 4 - -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'; - }) -end - -minetest.register_craftitem('sorcery:crucible_clay_molding', { - description = sorcery.lib.str.capitalize('Crucible molding'); - inventory_image = 'sorcery_crucible_clay_molding.png'; -}) - -minetest.register_craft { - recipe = { - { 'default:clay_lump', '', 'default:clay_lump'}; - { 'default:clay_lump', '', 'default:clay_lump'}; - { 'default:clay_lump', 'default:clay_lump', 'default:clay_lump'}; - }; - output = 'sorcery:crucible_clay_molding'; -} -minetest.register_craft { - type = 'shapeless'; - recipe = { 'sorcery:crucible_clay_molding' }; - output = 'default:clay_lump 7'; -} -minetest.register_craft { - type = 'cooking'; - recipe = 'sorcery:crucible_clay_molding'; - cooktime = 40; - output = 'sorcery:crucible_clay'; -} - -local burn_layout = function(v) - local layouts = { - [1] = {w = 1, h = 1}; [2] = {w = 2, h = 1}; [3] = {w = 3, h = 1}; - [4] = {w = 2, h = 2}; [5] = {w = 3, h = 2}; [6] = {w = 3, h = 2}; - [7] = {w = 4, h = 2}; [8] = {w = 4, h = 2}; [9] = {w = 3, h = 3}; - } - local inpos = { x = 2.8, y = 1 } - local insize = layouts[v.in] - local outpos = { x = 5.2, y = 2.4 } - local outsize = layouts[v.out] - local fuelpos = { x = 2.8, y = 3.4 } - local fuelsize = layouts[v.fuel] - return string.format([[ - list[context;input;%f,%f;%f,%f;] - list[context;output;%f,%f;%f,%f;] - list[context;fuel;%f,%f;%f,%f;] - - image[2.3,1.9;1,1;default_furnace_fire_bg.png^[lowpart:%u%%:default_furnace_fire_fg.png] - image[3.2,1.9;1,1;gui_furnace_arrow_bg.png^[lowpart:%u%%:gui_furnace_arrow_fg.png^[transformR270] - - listring[context;output] listring[current_player;main] - listring[context;input] listring[current_player;main] - listring[context;fuel] listring[current_player;main] - ]], - - --input - inpos.x - insize.w/2, -- pos - inpos.y - insize.h/2, - insize.w, insize.h, -- size - --output - outpos.x - outsize.w/2, -- pos - outpos.y - outsize.h/2, - outsize.w, outsize.h, -- size - --fuel - fuelpos.x - fuelsize.w/2, -- pos - fuelpos.y - fuelsize.h/2, - fuelsize.w, fuelsize.h, -- size - - v.burn, v.prog - ) -end - -local kiln_formspec = function(kind, fuel_progress, cook_progress) - return [[ - size[8,8] - list[current_player;main;0,4.2;8,4] - list[context;wax;0,2;1,1] - ]] .. burn_layout{ - in = kind.size^2; - out = kind.outsize; - fuel = kind.fuelsize; - burn = fuel_progress; - prog = cook_progress; - } -end - -local smelter_formspec = function(kind, fuel_progress, smelt_progress) - return [[ - size[8,8] - list[current_player;main;0,4.2;8,4] - ]] .. burn_layout { - in = kind.size; - out = kind.outsize; - fuel = kind.fuelsize; - burn = fuel_progress; - prog = smelt_progress; - } -end - -local find_recipe = function(inv) - local mix = {} - local count = 0 - for i=1,inv:get_size('input') do - local m = inv:get_stack('input',i) - if m:is_empty() then goto skip end - local l = sorcery.data.metallookup[m:get_name()] - if not l then return false end - mix[l.id] = (mix[l.id] or 0) + l.value - count = count + l.value - ::skip::end - -- everything is metal, we've finished summing it up. - -- let's see if the assembled items match the ratio - -- specified in any of the smelting recipes. - local matches = 0 - for _,rec in pairs(sorcery.data.alloys) do - local fac = nil - local meltpoint = 1 - if rec.metals == nil then goto skip_recipe end - for metal, ratio in pairs(rec.metals) do - if mix[metal] and mix[metal] % ratio == 0 then - if fac then - if mix[metal] / ratio ~= fac then goto skip_recipe end - else fac = math.floor(mix[metal] / ratio) end - local m = sorcery.data.metals[metal] - if m.meltpoint then - meltpoint = math.max(meltpoint, m.meltpoint) end - else goto skip_recipe end - end - do return rec, count, fac, meltpoint end - ::skip_recipe::end - return false -end - -local update_smelter = function(pos) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - local proto = minetest.registered_nodes[minetest.get_node(pos).name]._proto - local recipe, count, factor, meltpoint = find_recipe(inv) - if recipe --[[and proto.temp >= meltpoint]] then - minetest.get_node_timer(pos):start(1) - else - meta:set_float('burntime',0) - end -end - -local smelter_step = function(kind,active,pos,delta) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - local recipe, count, factor = find_recipe(inv) - local cooktime - local elapsed = meta:get_float('burntime') + delta - meta:set_float('burnleft',meta:get_float('burnleft') - delta) - if (not active) and (not recipe) then return false end - if meta:get_float('burnleft') <= 0 or not active then - if recipe then - local burn, frep = minetest.get_craft_result { - method = 'fuel', width = 1; - items = { inv:get_stack('fuel',1) }; - } - if burn.time == 0 then goto nofuel end - inv:set_stack('fuel', 1, frep.items[1]) - meta:set_float('burnleft',burn.time) - meta:set_float('burnmax',burn.time) - if not active then - minetest.swap_node(pos, - sorcery.lib.tbl.merge(minetest.get_node(pos), { - name = kind.id .. '_active' - })) - active = true - end - else goto nofuel end - end - - if not recipe then goto update end - - cooktime = ((recipe.cooktime / fragments_per_ingot) * count) / factor - if elapsed >= cooktime then - elapsed = 0 - -- remove used items - for i=1,inv:get_size('input') do - local s = inv:get_stack('input',i) - if s:is_empty() then goto skip end - s:take_item(1) inv:set_stack('input',i,s) - ::skip::end - - local outstack - if count % fragments_per_ingot == 0 then - outstack = ItemStack { - name = sorcery.data.metals[recipe.output].ingot or 'sorcery:' .. recipe.output .. '_ingot'; - count = count / fragments_per_ingot; - } - else - outstack = ItemStack { - name = 'sorcery:fragment_' .. recipe.output; - count = count; - } - end - - local leftover = inv:add_item('output',outstack) - if not leftover:is_empty() then - minetest.add_item(pos, leftover) - end - end - - ::update:: - meta:set_float('burntime',elapsed) - meta:set_string('formspec', smelter_formspec(kind, - math.min(1, meta:get_float('burnleft') / - meta:get_float('burnmax') - ) * 100, -- fuel - (cooktime and math.min(1, elapsed / cooktime) * 100) or 0 -- smelt - )) - do return active end - - ::nofuel:: - if active then - minetest.swap_node(pos, - sorcery.lib.tbl.merge(minetest.get_node(pos), { name = kind.id })) - end - meta:set_float('burnleft',0) -- just in case - ::noburn:: - meta:set_float('burntime',0) -- just in case - meta:set_string('formspec', smelter_formspec(kind, 0, 0)) - return false -end -local register_kiln = function(kind) - local box = { - open = { - type = 'fixed'; - fixed = { - -0.5,-0.5,-0.5, - 0.5, 1.6, 0.5 - }; - }; - closed = { - type = 'fixed'; - fixed = { - -0.5,-0.5,-0.5, - 0.5, 0.7, 0.5 - }; - }; - } - local id = 'sorcery:kiln_' .. kind.material - local metal = sorcery.data.metals[kind.material] - -- use some iffy heuristics to guess the texture - local metaltex - if kind.material == 'clay' then - metaltex = 'default_brick.png'; - else - metaltex = (metal.img and metal.img.block) or - (metal.ingot and 'default_' .. kind.material .. '_block.png') or - sorcery.lib.image('default_steel_block.png'):multiply(sorcery.lib.color(metal.tone)):render(); - end - local tex = { - open = { - 'default_furnace_front.png'; - metaltex; - 'default_copper_block.png'; - 'default_stone.png'; - }; - closed = { - 'default_furnace_front_active.png'; - 'default_copper_block.png'; - metaltex; - 'default_stone.png'; - }; - }; - for _,state in pairs{'open','closed'} do - local id_closed = id .. '_closed' - local id_current = (state == 'closed' and id_closed) or id - local desc = sorcery.lib.str.capitalize(kind.temp_name) .. ' kiln'; - minetest.register_node(id_current, { - _active = (state == 'closed'); - _proto = kind; - description = desc; - drawtype = "mesh"; - mesh = 'sorcery-kiln-' .. state .. '.obj'; - drop = id; - groups = { cracky = 2; sorcery_device_kiln = (state == 'closed') and 1 or 2; } - sunlight_propagates = true; - paramtype1 = 'light'; - paramtype2 = 'facedir'; - selection_box = box[state]; - collision_box = box[state]; - tiles = tex[state]; - light_source = (state == 'closed' and 7) or 0; - on_construct = function(pos) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - inv:set_size('input', kind.size^2) - inv:set_size('output', kind.outsize) - inv:set_size('fuel', kind.fuelsize) - inv:set_size('wax', 1) - - meta:set_float('burnleft',0) - meta:set_float('burnmax',0) - meta:set_float('burntime',0) - - meta:set_string('infotext',desc) - meta:set_string('formspec',kiln_formspec(kind,0,0)) - end; - on_timer = function(pos,delta) - end; - - on_metadata_inventory_put = function(pos) - minetest.get_node_timer(pos):start(1) end; - on_metadata_inventory_move = function(pos) - minetest.get_node_timer(pos):start(1) end; - on_metadata_inventory_take = function(pos) - minetest.get_node_timer(pos):start(1) end; - }) - end - local ingot - if kind.material == 'clay' then - ingot = 'default:clay_brick'; - else - ingot = metal.ingot or 'sorcery:' .. kind.material .. '_ingot' - end - minetest.register_craft = { - output = id_open; - recipe = { - {'default:copper_ingot', 'default:copper_ingot', 'default:copper_ingot'}; - {ingot,'',ingot}; - {ingot,'default:furnace',ingot}; - }; - } -end - -local register_smelter = function(kind) - local recipe = {{},{}; - {'default:stone','default:furnace','default:stone'}; - } do - local on = kind.crucible - local ti = 'default:tin_ingot' - local cu = 'default:copper_ingot' - local crucmap = { - [2] = { {cu,cu,cu}, {on,ti,on} }; - [3] = { {cu,on,cu}, {on,ti,on} }; - [4] = { {on,cu,on}, {on,ti,on} }; - [5] = { {on,cu,on}, {on,on,on} }; - [6] = { {on,on,on}, {on,on,on} }; - }; - for y=1,2 do recipe[y] = crucmap[kind.size][y] end - end - - local desc = 'smelter'; - if kind.temp_name then desc = kind.temp_name .. ' ' .. desc end - if kind.size_name then desc = kind.size_name .. ' ' .. desc end - desc = sorcery.lib.str.capitalize(desc); - local id = 'sorcery:smelter_' .. kind.material .. kind.size_name - kind.id = id - for _, active in pairs {false, true} do - minetest.register_node((active and id .. '_active') or id, { - _proto = kind; - description = desc; - drop = id; - groups = { - cracky = 2; - sorcery_device_smelter = active and 1 or 2; - }; - paramtype2 = 'facedir'; - light_source = (active and 9) or 0; - on_construct = function(pos) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - inv:set_size('input',kind.size) - inv:set_size('output',kind.outsize) - inv:set_size('fuel',kind.fuelsize) - meta:set_string('infotext', desc) - meta:set_string('formspec', smelter_formspec(kind, 0, 0)) - meta:set_float('burnleft',0) - meta:set_float('burnmax',0) - meta:set_float('burntime',0) - end; - on_metadata_inventory_put = update_smelter; - on_metadata_inventory_move = update_smelter; - on_metadata_inventory_take = update_smelter; - on_timer = function(pos,delta) return smelter_step(kind, active, pos, delta) end; - -- allow_metadata_inventory_put = function(pos, listname, index, stack, player) - -- end; - tiles = { - 'sorcery_smelter_top_' .. tostring(kind.size) .. '.png'; - 'sorcery_smelter_bottom.png'; - 'sorcery_smelter_side.png'; - 'sorcery_smelter_side.png'; - 'sorcery_smelter_side.png'; - 'sorcery_smelter_front' .. ((active and '_hot') or '') .. '.png'; - }; - }) - end - minetest.register_craft { - recipe = recipe; - output = id; - } -end - -for _, t in pairs { - {1, nil, 'clay'}; - -- {2, 'hot','aluminum'}; - -- {3, 'volcanic','platinum'}; - -- {4, 'stellar','duridium'}; - -- {5, 'nova','impervium'}; -} do register_kiln { - temp = t[1], temp_name = t[2]; - material = t[3]; - size = 3, outsize = 4, fuelsize = 1; -- future-proofing - } - - for _, s in pairs { - {2, 'small'}; - {3, 'large'}; - {4, 'grand'}; - } do register_smelter { - size = s[1], size_name = s[2]; - temp = t[1], temp_name = t[2]; - material = t[3]; - crucible = 'sorcery:crucible_' .. t[3]; - outsize = 4, fuelsize = 1; -- future-proofing - } end -end Index: init.lua ================================================================== --- init.lua +++ init.lua @@ -101,12 +101,12 @@ data { 'compat'; 'affinities'; 'gods'; 'calendar', 'signs'; 'resonance'; - 'enchants', 'spells', 'runes'; 'gems', 'metals'; + 'enchants', 'spells', 'runes'; 'potions', 'oils', 'greases', 'draughts', 'elixirs', 'philters', 'extracts'; } end Index: leylines.lua ================================================================== --- leylines.lua +++ leylines.lua @@ -378,11 +378,11 @@ neighbors = {'group:sorcery_ley_device'}; interval = 5.6, chance = 1, catch_up = false; action = function(pos) local force = sorcery.ley.estimate(pos).force minetest.sound_play('sorcery_condenser_bg', { - pos = pos, max_hear_distance = 5 + 8*force, gain = force*0.3; + pos = pos, max_hear_distance = 5 + 4*force, gain = force*0.3; }) end; } end Index: lib/color.lua ================================================================== --- lib/color.lua +++ lib/color.lua @@ -162,13 +162,20 @@ -- print("back is r"..temp.red.."g"..temp.green.."b"..temp.blue) return { hue = hue, saturation = saturation, luminosity = luminosity } end; readable = function(self, target) - target = target or 0.5 + target = target or 0.6 local hsl = self:to_hsl() hsl.luminosity = target + local worstHue = 230 + local nearness = math.abs(worstHue - hsl.hue) + if nearness <= 70 then + local boost = 1.0 - (nearness / 70) + hsl.luminosity = math.min(1, hsl.luminosity * (1 + (boost*0.4))) + end + return from_hsl(hsl, self.alpha) end; bg = function(self, text) return text .. minetest.get_background_escape_sequence(self:hex()) @@ -183,11 +190,12 @@ -- To HSL local hsl = self:to_hsl() -- Do the calculation, clamp to 0-1 instead of the clamp fn hsl.luminosity = math.min(math.max(hsl.luminosity * fac, 0), 1) -- Turn back into RGB color - local t = from_hsl(hsl, self.alpha) + -- local t = from_hsl(hsl, self.alpha) + -- print("darker is r"..hsl.red.."g"..hsl.green.."b"..hsl.blue) -- print("brighten is r"..t.red.."g"..t.green.."b"..t.blue) return from_hsl(hsl, self.alpha) end; darken = warp(function(new, fac) ADDED lib/hud.lua Index: lib/hud.lua ================================================================== --- lib/hud.lua +++ lib/hud.lua @@ -0,0 +1,28 @@ +-- the HUD library provides an easy-to-use interface for create custom +-- item UIs. the idea is that an item will define one or more UI layouts +-- in its _sorcery.hud property, then call lib.hud.open(id, layout, player, ...) +-- when it wishes to open , usually from its on_use handler. the library +-- will then iterate through the elements in its definition, transmit them to +-- the user, and store the resulting handles in a user context. it will also +-- register any timer callbacks needed to ensure a timely update of the item. +-- if the item is removed from the hotbar, any UI associated with it will be +-- closed. +-- +-- each UI element can have a function that is called to set its value. if +-- this is present, it will be called at initialization and at update. +-- +-- example: +-- _sorcery = { +-- hud = { +-- powerlevel = { +-- period = 0.1; +-- elements = { +-- {kind = 'text', +-- text = function(ctx) +-- return ctx.stack:get_meta():get_int("power") +-- end; +-- }; +-- }; +-- }; +-- }; +-- }; Index: lib/tbl.lua ================================================================== --- lib/tbl.lua +++ lib/tbl.lua @@ -53,10 +53,18 @@ new[k] = v end end return new end + +fn.append = function(r1, r2) + local new = fn.copy(r1) + for i=1,#r2 do + new[#new + 1] = r2[i] + end + return new +end fn.merge = function(base,override) local new = fn.copy(base) for k,v in pairs(override) do new[k] = v @@ -64,11 +72,11 @@ return new end fn.deepmerge = function(base,override,func) local new = {} - local keys = fn.merge(fn.keys(base),fn.keys(override)) + local keys = fn.append(fn.keys(base),fn.keys(override)) for _,k in pairs(keys) do if type(base[k]) == 'table' and type(override[k]) == 'table' then new[k] = fn.deepmerge(base[k], override[k], func) elseif func and override[k] and base[k] then @@ -77,18 +85,10 @@ new[k] = override[k] else new[k] = base[k] end end - return new -end - -fn.append = function(r1, r2) - local new = fn.copy(r1) - for i=1,#r2 do - new[#new + 1] = r2[i] - end return new end fn.has = function(tbl,value,eqfn) for k,v in pairs(tbl) do Index: lib/ui.lua ================================================================== --- lib/ui.lua +++ lib/ui.lua @@ -1,11 +1,11 @@ local l = sorcery.lib local dui = sorcery.data.ui return { tooltip = function(a) - local color = a.color + local color = a.color and a.color:readable() if color == nil then color = l.color(136,158,177) end local str = a.title if a.desc then str = str .. '\n' .. color:fmt(minetest.wrap_text(a.desc,60)) end @@ -12,11 +12,11 @@ if a.props then -- str = str .. '\n' for _,prop in pairs(a.props) do local c if prop.color and l.color.id(prop.color) then - c = prop.color + c = prop.color:readable() elseif dui.colors[prop.affinity] then c = l.color(dui.colors[prop.affinity]) else c = l.color(dui.colors.neutral) end @@ -25,15 +25,15 @@ if prop.title then str = str .. c:brighten(1.3):fmt(prop.title) .. ': ' end - local lines = minetest.wrap_text(prop.desc, 50, true) + local lines = minetest.wrap_text(prop.desc, 55, true) str = str .. c:fmt(lines[1]) for i=2,#lines do str = str .. '\n' .. string.rep(' ',5) .. c:fmt(lines[i]) end end end - return str + return color:darken(0.8):bg(str) end; } Index: metallurgy-cold.lua ================================================================== --- metallurgy-cold.lua +++ metallurgy-cold.lua @@ -131,11 +131,11 @@ mp.grindcost = mp.grindcost or constants.default_grindcost if item:get_wear() ~= 0 then -- prevent cheating by recovering metal from items before they -- are destroyed - local wearfac = (item:get_wear() / 65535) + local wearfac = 1-(item:get_wear() / 65535) mp.grindvalue = math.max(1,math.ceil(mp.grindvalue * wearfac)) mp.hardness = math.max(1,math.ceil(mp.grindcost * wearfac)) mp.torque = math.max(1,math.ceil(mp.torque * wearfac)) end Index: portal.lua ================================================================== --- portal.lua +++ portal.lua @@ -360,11 +360,11 @@ 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(); + texture = sorcery.lib.image('sorcery_sputter.png'):glow(sorcery.lib.color(255,144,226)):render(); minexptime = 1.5; maxexptime = 2; minsize = 0.4; maxsize = 1.6 * fac; glow = 14; Index: potions.lua ================================================================== --- potions.lua +++ potions.lua @@ -10,18 +10,18 @@ '^[multiply:'..tostring(color).. '^vessels_glass_bottle.png' sorcery.register.residue.link('sorcery:' .. name, 'vessels:glass_bottle') local node = { - description = color:darken(0.8):bg( + description = --color:darken(0.8):bg( sorcery.lib.ui.tooltip { title = label; desc = desc; color = color:readable(); - } + }; -- label .. (desc and ("\n" .. color:readable():fmt(desc)) or '') - ); + --); short_description = label; drawtype = "plantlike"; tiles = {image}; inventory_image = image; paramtype = "light"; Index: runeforge.lua ================================================================== --- runeforge.lua +++ runeforge.lua @@ -1,10 +1,11 @@ -- TODO make some kind of disposable "filter" tool that runeforges require -- to generate runes and that wears down over time, to make amulets more -- expensive than they currently are? the existing system is neat but -- i think amulets are a little overpowered for something that just -- passively consumes ley-current +-- -- are phials & rune-wrenches enough for this now? local constants = { rune_mine_interval = 240; -- how often a powered forge rolls for new runes @@ -46,12 +47,13 @@ end sorcery.register.runes.foreach('sorcery:generate',{},function(name,rune) local id = 'sorcery:rune_' .. name rune.image = rune.image or string.format('sorcery_rune_%s.png',name) rune.item = id + local c = sorcery.lib.color(rune.tone) minetest.register_craftitem(id, { - description = sorcery.lib.color(rune.tone):readable():fmt(rune.name .. ' Rune'); + description = c:darken(0.7):bg(c:readable():fmt(rune.name .. ' Rune')); short_description = rune.name .. ' Rune'; inventory_image = rune.image; stack_max = 1; groups = { sorcery_rune = 1; @@ -147,11 +149,11 @@ m:set_string('amulet_rune', rp.id) m:set_int('amulet_rune_grade', rg) local spell = sorcery.amulet.getspell(stack) if not spell then return nil end local name - if spell.minrune then -- indicating quality makes less sense if it's restricted + if spell.mingrade and spell.mingrade > 0 then -- indicating quality makes less sense if it's restricted name = string.format('Amulet of %s', spell.name) else name = string.format('Amulet of %s %s', constants.amulet_grades[rg], spell.name) end m:set_string('description', sorcery.lib.ui.tooltip { @@ -405,11 +407,11 @@ i:set_size('wrench',1) i:set_size('phial',1) i:set_size('refuse',1) i:set_size('amulet',1) i:set_size('active',1) m:set_string('infotext','Rune Forge') runeforge_update(pos) end; - after_dig_node = sorcery.lib.node.purge_only {'amulet'}; + after_dig_node = sorcery.lib.node.purge_only {'amulet','wrench'}; on_timer = runeforge_update; on_metadata_inventory_move = function(pos, fl,fi, tl,ti, count, user) local inv = minetest.get_meta(pos):get_inventory() local wrench if not inv:is_empty('wrench') then wrench = inv:get_stack('wrench',1):get_definition()._proto Index: vfx.lua ================================================================== --- vfx.lua +++ vfx.lua @@ -12,11 +12,12 @@ local height = caster:get_properties().eye_height minetest.add_particlespawner { amount = 70 * strength; time = duration or 1.5; attached = caster; - texture = sorcery.lib.image('sorcery_spark.png'):multiply(color):render(); + -- texture = sorcery.lib.image('sorcery_spark.png'):multiply(color):render(); + texture = sorcery.vfx.glowspark(color):render(); minpos = ofs({ x = 0.0, z = 0.6, y = height*0.7}); maxpos = ofs({ x = 0.4, z = 0.2, y = height*1.1}); 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}; @@ -65,11 +66,11 @@ sorcery.vfx.enchantment_sparkle = function(tgt,color) local minvel, maxvel if minetest.get_node(vector.add(tgt.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(tgt.under,tgt.above) + local dir = vector.subtract(tgt.above,tgt.under) minvel = vector.multiply(dir, 0.3) maxvel = vector.multiply(dir, 1.2) end return minetest.add_particlespawner { amount = 50; Index: wands.lua ================================================================== --- wands.lua +++ wands.lua @@ -161,14 +161,14 @@ end; matprops = function(proto) local matprops = {} for k,v in pairs(proto) do if sorcery.wands.materials[k] then - local mp = sorcery.wands.materials[k].wandprops + local mp = sorcery.wands.materials[k][v].wandprops if mp then matprops = sorcery.lib.tbl.deepmerge(matprops, mp, - function(a,b,k) + function(a,b,key) if key == 'bond' then return a+b else return a*b end end) @@ -274,11 +274,11 @@ }; wearmult = 1; } local result = castfn(context) if result ~= false then - minetest.sound_play(sorcery.data.spells[spell].sound or "default_item_smoke", { --FIXME make own sounds + minetest.sound_play(sorcery.data.spells[spell].sound or "sorcery_chime", { --FIXME make better sound pos = user:get_pos(); gain = 0.8; }) -- minetest.add_particle { -- pos = vector.add(vector.add(user:get_pos(), vector.multiply(user:get_look_dir(),1.1)), {y=1.6,z=0,x=0}); @@ -380,11 +380,11 @@ paramtype2 = 'facedir'; tiles = images; selection_box = hitbox; collision_box = hitbox; after_dig_node = sorcery.lib.node.purge_container; - use_texture_alpha = true; + use_texture_alpha = 'blend'; on_construct = function(pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() inv:set_size('wand', 1) update_stand_info(pos)