sorcery  keg.lua at [a27bfa0fa7]

File keg.lua artifact f0cb8863c3 part of check-in a27bfa0fa7


local constants = {
	keg_volume = sorcery.liquid.constants.glasses_per_bottle * 600
}

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.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
		return {
			title = string.format('%s Keg', sorcery.lib.str.capitalize(liq.name));
			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')
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; sorcery_tech = 1; 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
				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

				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()

					-- 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 = 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()
						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
				end
			end
		end;
	})
end

minetest.register_craft {
	output = "sorcery:keg";
	recipe = {
		{'','screwdriver:screwdriver',''};
		{'sorcery:screw_bronze', 'sorcery:tap', 'sorcery:screw_bronze'};
		{'sorcery:screw_bronze', 'xdecor:barrel', 'sorcery:screw_bronze'};
	};
	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'};
	};
}