Index: altar.lua ================================================================== --- altar.lua +++ altar.lua @@ -1,7 +1,7 @@ local altar_item_offset = { - x = 0, y = -0.3, z = 0 + x = 0, y = -0.3, z = 0.13 } local log = sorcery.logger('altar') local L = sorcery.lib local range = function(min, max) Index: keg.lua ================================================================== --- keg.lua +++ keg.lua @@ -1,16 +1,24 @@ local constants = { keg_volume = sorcery.liquid.constants.glasses_per_bottle * 600 } -local hitbox = { +local hitbox = function(yo) return { + type = 'fixed'; + fixed = { + -0.4, -0.5 + yo, -0.45; + 0.4, 0.2 + yo, 0.5; + }; +} end +local mcbox = { type = 'fixed'; fixed = { - -0.4, -0.5, -0.5; - 0.4, 0.2, 0.5; + -0.5, -0.4, -0.5; + 0.5, 0.3, 0.4; }; } + local kegcaption = function(m) local liqid = m:get_string('liquid') if liqid ~= '' then local liq = sorcery.register.liquid.db[liqid] if not liq then log.err('missing entry for liquid',liqid) return end @@ -19,170 +27,179 @@ color = sorcery.lib.color(liq.color); desc = string.format('%s of %s', liq.measure(m:get_int('charge')), liq.name); }; else return { title = 'Empty Keg', props = {} } end end + local log = sorcery.logger('keg') -minetest.register_node('sorcery:keg', { - description = 'Keg'; - drawtype = 'mesh'; - mesh = 'sorcery-keg.obj'; - sunlight_propagates = true; - paramtype = 'light'; - paramtype2 = 'facedir'; - groups = { choppy = 2; sorcery_container = 2 }; -- 2=liquid - tiles = { - 'default_bronze_block.png'; - 'default_wood.png'; - 'default_steel_block.png'; - }; - selection_box = hitbox; - collision_box = hitbox; - drop = { - -- preserve_metadata will not work without this! - max_items = 1; - items = { - { items = { 'sorcery:keg' } }; +for _, keg in pairs { + { name = 'Keg', id = 'sorcery:keg', model = 'sorcery-keg.obj', atch = 1 }; + { name = 'Mounted Keg', id = 'sorcery:keg_stand', model = 'sorcery-keg-stand.obj', atch = 0, ofs = 0.1, cb = mcbox }; +} do + minetest.register_node(keg.id, { + description = keg.name; + drawtype = 'mesh'; + mesh = keg.model; + sunlight_propagates = true; + paramtype = 'light'; + paramtype2 = 'facedir'; + groups = { choppy = 2; sorcery_container = 2; attached_node = keg.atch }; -- 2=liquid + tiles = { + 'default_bronze_block.png'; + 'default_wood.png'; + 'default_steel_block.png'; + }; + selection_box = hitbox(keg.ofs or 0); + collision_box = keg.cb or hitbox(keg.ofs or 0); + drop = { + -- preserve_metadata will not work without this! + max_items = 1; + items = { + { items = { keg.id } }; + }; }; - }; - preserve_metadata = function(pos,node,meta,drops) - if meta.liquid and meta.liquid ~= '' then - local m = drops[1]:get_meta() - m:from_table({fields = meta}) - local cap = kegcaption(m) - m:set_string('description', sorcery.lib.ui.tooltip(cap)) - m:set_string('short_description', cap.title) - end - end; - after_place_node = function(pos, placer, stack, tgt) - local meta = minetest.get_meta(pos) - local stackmeta = stack:get_meta() - meta:from_table(stackmeta:to_table()) - if not meta:contains('infotext') then - meta:set_string('infotext', 'Empty Keg') - end - end; - on_rightclick = function(pos, node, user, stack) - local m = minetest.get_meta(pos) - local update = function() - local c = kegcaption(m) - local str = c.title - if c.desc then str = str .. '\n(' .. c.desc .. ')' end - if c.props then for _,p in pairs(c.props) do -- future-proofing - str = str .. string.format('\n(%s: %s)', p.title, p.desc) - end end - m:set_string('infotext', str) - end - - if stack:is_empty() then return end - - local ctr = sorcery.itemclass.get(stack, 'container') - if (not ctr) or not ctr.hold == 'liquid' then return end - - local liqid = m:get_string('liquid') - if ctr.has and -- add liquid to keg - (liqid == ctr.has or not m:contains('liquid')) then - if not ctr.empty then log.err(stack:get_name(), 'does not specify its empty counterpart container') return end - - local add = ctr.charge * stack:get_count() - local chg = m:get_int('charge') - if chg + add > constants.keg_volume then - log.act(string.format('%s tried to overfill a %s keg at %s', - user:get_player_name(), - ctr.has, minetest.pos_to_string(pos))) - return + preserve_metadata = function(pos,node,meta,drops) + if meta.liquid and meta.liquid ~= '' then + local m = drops[1]:get_meta() + m:from_table({fields = meta}) + local cap = kegcaption(m) + m:set_string('description', sorcery.lib.ui.tooltip(cap)) + m:set_string('short_description', cap.title) + end + end; + after_place_node = function(pos, placer, stack, tgt) + local meta = minetest.get_meta(pos) + local stackmeta = stack:get_meta() + meta:from_table(stackmeta:to_table()) + if not meta:contains('infotext') then + meta:set_string('infotext', 'Empty Keg') + end + end; + on_rightclick = function(pos, node, user, stack) + local m = minetest.get_meta(pos) + local update = function() + local c = kegcaption(m) + local str = c.title + if c.desc then str = str .. '\n(' .. c.desc .. ')' end + if c.props then for _,p in pairs(c.props) do -- future-proofing + str = str .. string.format('\n(%s: %s)', p.title, p.desc) + end end + m:set_string('infotext', str) end - m:set_int('charge', chg + add) - m:set_string('liquid', ctr.has) - sorcery.liquid.sound_pour(add,chg,pos) + + if stack:is_empty() then return end + + local ctr = sorcery.itemclass.get(stack, 'container') + if (not ctr) or not ctr.hold == 'liquid' then return end + + local liqid = m:get_string('liquid') + if ctr.has and -- add liquid to keg + (liqid == ctr.has or not m:contains('liquid')) then + if not ctr.empty then log.err(stack:get_name(), 'does not specify its empty counterpart container') return end + + local add = ctr.charge * stack:get_count() + local chg = m:get_int('charge') + if chg + add > constants.keg_volume then + log.act(string.format('%s tried to overfill a %s keg at %s', + user:get_player_name(), + ctr.has, minetest.pos_to_string(pos))) + return + end + m:set_int('charge', chg + add) + m:set_string('liquid', ctr.has) + sorcery.liquid.sound_pour(add,chg,pos) - local liq = sorcery.register.liquid.db[ctr.has] - if liq then - update() - log.act(string.format('%s added %u units of %s to a keg at %s', - user:get_player_name(), add, - ctr.has, minetest.pos_to_string(pos))) - else log.err('no liquid entry for',ctr.has) end + local liq = sorcery.register.liquid.db[ctr.has] + if liq then + update() + log.act(string.format('%s added %u units of %s to a keg at %s', + user:get_player_name(), add, + ctr.has, minetest.pos_to_string(pos))) + else log.err('no liquid entry for',ctr.has) end - return ItemStack { - name = ctr.empty; - count = stack:get_count(); - } - elseif not ctr.has and liqid ~= '' then -- take liquid - local liq = sorcery.register.liquid.db[m:get_string('liquid')] - if not liq then log.err('missing definition for liquid', liqid) return end + return ItemStack { + name = ctr.empty; + count = stack:get_count(); + } + elseif not ctr.has and liqid ~= '' then -- take liquid + local liq = sorcery.register.liquid.db[m:get_string('liquid')] + if not liq then log.err('missing definition for liquid', liqid) return end - local basin = m:get_int('charge') - local filled, amtleft = sorcery.liquid.fill_from_basin(stack, liqid, basin) - if filled then - local chg = basin - amtleft - log.act(string.format('%s removed %u units of %s from a keg at %s', - user:get_player_name(), chg, liqid, - minetest.pos_to_string(pos))) - if amtleft == 0 then - m:set_string('liquid','') - m:set_int('charge',0) - else m:set_int('charge', amtleft) end - sorcery.liquid.sound_dip(chg,avail,pos) - update() + local basin = m:get_int('charge') + local filled, amtleft = sorcery.liquid.fill_from_basin(stack, liqid, basin) + if filled then + local chg = basin - amtleft + log.act(string.format('%s removed %u units of %s from a keg at %s', + user:get_player_name(), chg, liqid, + minetest.pos_to_string(pos))) + if amtleft == 0 then + m:set_string('liquid','') + m:set_int('charge',0) + else m:set_int('charge', amtleft) end + sorcery.liquid.sound_dip(chg,avail,pos) + update() - -- fancy visuals - local color = sorcery.lib.color(liq.color or {255,255,255}) - local spritz = sorcery.lib.image('sorcery_droplet.png'):glow(color) - local drop = sorcery.lib.image('sorcery_drop.png'):glow(color) - local facing = minetest.facedir_to_dir(minetest.get_node(pos).param2) - local noz = vector.add(pos, vector.rotate( - vector.new(0.0,0,-0.48), - vector.dir_to_rotation(facing) - )) - local minnoz = vector.offset(noz, -0.03, -0.32, -0.03); - local maxnoz = vector.offset(noz, 0.03, -0.32, 0.03); - minetest.add_particlespawner { - amount = 15 * chg, time = 0.1*chg; - texture = spritz:render(); - minpos = minnoz, maxpos = maxnoz; - minvel = vector.new(0,0,0); - maxvel = vector.new(0,-0.1,0); - minacc = vector.new(0,-0.1,0); - maxacc = vector.new(0,-0.13,0); - minsize = 0.4, maxsize = 1; - glow = 14; -- FIXME liquid glow prop - minexptime = 0.5, maxexptime = 0.5; - animation = { - type = 'sheet_2d'; - frames_w = 14; - frames_h = 1; - frame_length = (0.5/14) + 0.02; - } - } - minetest.after(0.2, function() + -- fancy visuals + local color = sorcery.lib.color(liq.color or {255,255,255}) + local spritz = sorcery.lib.image('sorcery_droplet.png'):glow(color) + local drop = sorcery.lib.image('sorcery_drop.png'):multiply(color) + local facing = minetest.facedir_to_dir(minetest.get_node(pos).param2) + local noz = vector.add( + vector.offset(pos,0,keg.ofs or 0,0), + vector.rotate( + vector.new(0.0,0,-0.48), + vector.dir_to_rotation(facing) + ) + ) + local minnoz = vector.offset(noz, -0.03, -0.32, -0.03); + local maxnoz = vector.offset(noz, 0.03, -0.32, 0.03); minetest.add_particlespawner { - amount = math.random(5,11) * chg, time = 0.13 * chg; - texture = drop:render(); - minpos = minnoz; - maxpos = maxnoz; - minvel = vector.new(0,-0.1,0); - maxvel = vector.new(0,-0.4,0); - minacc = vector.new(0,-0.15,0); - maxacc = vector.new(0,-0.18,0); - minsize = 0.3, maxsize = 0.5; + amount = 15 * chg, time = 0.1*chg; + texture = spritz:render(); + minpos = minnoz, maxpos = maxnoz; + minvel = vector.new(0,0,0); + maxvel = vector.new(0,-0.1,0); + minacc = vector.new(0,-0.1,0); + maxacc = vector.new(0,-0.13,0); + minsize = 0.4, maxsize = 1; glow = 14; -- FIXME liquid glow prop - minexptime = 1, maxexptime = 1.5; + minexptime = 0.5, maxexptime = 0.5; animation = { type = 'sheet_2d'; - frames_w = 10; + frames_w = 14; frames_h = 1; - frame_length = (1.5/10) + 0.02; + frame_length = (0.5/14) + 0.02; } } - end) + minetest.after(0.2, function() + minetest.add_particlespawner { + amount = math.random(5,11) * chg, time = 0.13 * chg; + texture = drop:render(); + minpos = minnoz; + maxpos = maxnoz; + minvel = vector.new(0,-0.1,0); + maxvel = vector.new(0,-0.4,0); + minacc = vector.new(0,-0.15,0); + maxacc = vector.new(0,-0.18,0); + minsize = 0.3, maxsize = 0.5; + glow = 14; -- FIXME liquid glow prop + minexptime = 1, maxexptime = 1.5; + animation = { + type = 'sheet_2d'; + frames_w = 10; + frames_h = 1; + frame_length = (1.5/10) + 0.02; + } + } + end) - return filled + return filled + end end - end - end; -}) + end; + }) +end minetest.register_craft { output = "sorcery:keg"; recipe = { {'','screwdriver:screwdriver',''}; @@ -191,5 +208,25 @@ }; replacements = { {'screwdriver:screwdriver', 'screwdriver:screwdriver'}; }; } + +minetest.register_craft { + output = "sorcery:keg_stand"; + recipe = { + {'','sorcery:keg',''}; + {'sorcery:screw_steel','group:wood','sorcery:screw_steel'}; + {'sorcery:screw_steel','screwdriver:screwdriver','sorcery:screw_steel'}; + }; + replacements = {{'screwdriver:screwdriver', 'screwdriver:screwdriver'}}; +} + +minetest.register_craft { + output = "sorcery:keg"; + type = 'shapeless'; + recipe = { 'sorcery:keg_stand', 'screwdriver:screwdriver' }; + replacements = { + {'screwdriver:screwdriver', 'screwdriver:screwdriver'}; + {'sorcery:keg_stand', 'sorcery:screw_steel 4'}; + }; +}