sorcery  Diff

Differences From Artifact [b24c7d1147]:

To Artifact [4b624880ad]:


     1      1   local constants = {
     2      2   	keg_volume = sorcery.liquid.constants.glasses_per_bottle * 600
     3      3   }
     4      4   
     5         -local hitbox = {
            5  +local hitbox = function(yo) return {
            6  +	type = 'fixed';
            7  +	fixed = {
            8  +		-0.4, -0.5 + yo, -0.45;
            9  +		 0.4,  0.2 + yo,  0.5;
           10  +	};
           11  +} end
           12  +local mcbox = {
     6     13   	type = 'fixed';
     7     14   	fixed = {
     8         -		-0.4, -0.5, -0.5;
     9         -		 0.4,  0.2,  0.5;
           15  +		-0.5, -0.4, -0.5;
           16  +		 0.5,  0.3,  0.4;
    10     17   	};
    11     18   }
           19  +
    12     20   local kegcaption = function(m)
    13     21   	local liqid = m:get_string('liquid')
    14     22   	if liqid ~= '' then
    15     23   		local liq = sorcery.register.liquid.db[liqid]
    16     24   		if not liq then log.err('missing entry for liquid',liqid) return end
    17     25   		return {
    18     26   			title = string.format('%s Keg', sorcery.lib.str.capitalize(liq.name));
    19     27   			color = sorcery.lib.color(liq.color);
    20     28   			desc = string.format('%s of %s', liq.measure(m:get_int('charge')), liq.name);
    21     29   		};
    22     30   	else return { title = 'Empty Keg', props = {} } end
    23     31   end
           32  +
    24     33   local log = sorcery.logger('keg')
    25         -minetest.register_node('sorcery:keg', {
    26         -	description = 'Keg';
    27         -	drawtype = 'mesh';
    28         -	mesh = 'sorcery-keg.obj';
    29         -	sunlight_propagates = true;
    30         -	paramtype = 'light';
    31         -	paramtype2 = 'facedir';
    32         -	groups = { choppy = 2; sorcery_container = 2 }; -- 2=liquid
    33         -	tiles = {
    34         -		'default_bronze_block.png';
    35         -		'default_wood.png';
    36         -		'default_steel_block.png';
    37         -	};
    38         -	selection_box = hitbox;
    39         -	collision_box = hitbox;
    40         -	drop = {
    41         -		-- preserve_metadata will not work without this!
    42         -		max_items = 1;
    43         -		items = {
    44         -			{ items = { 'sorcery:keg' } };
           34  +for _, keg in pairs {
           35  +	{ name = 'Keg', id = 'sorcery:keg', model = 'sorcery-keg.obj', atch = 1 };
           36  +	{ name = 'Mounted Keg', id = 'sorcery:keg_stand', model = 'sorcery-keg-stand.obj', atch = 0, ofs = 0.1, cb = mcbox };
           37  +} do
           38  +	minetest.register_node(keg.id, {
           39  +		description = keg.name;
           40  +		drawtype = 'mesh';
           41  +		mesh = keg.model;
           42  +		sunlight_propagates = true;
           43  +		paramtype = 'light';
           44  +		paramtype2 = 'facedir';
           45  +		groups = { choppy = 2; sorcery_container = 2; attached_node = keg.atch }; -- 2=liquid
           46  +		tiles = {
           47  +			'default_bronze_block.png';
           48  +			'default_wood.png';
           49  +			'default_steel_block.png';
           50  +		};
           51  +		selection_box = hitbox(keg.ofs or 0);
           52  +		collision_box = keg.cb or hitbox(keg.ofs or 0);
           53  +		drop = {
           54  +			-- preserve_metadata will not work without this!
           55  +			max_items = 1;
           56  +			items = {
           57  +				{ items = { keg.id } };
           58  +			};
    45     59   		};
    46         -	};
    47         -	preserve_metadata = function(pos,node,meta,drops)
    48         -		if meta.liquid and meta.liquid ~= '' then
    49         -			local m = drops[1]:get_meta()
    50         -			m:from_table({fields = meta})
    51         -			local cap = kegcaption(m)
    52         -			m:set_string('description', sorcery.lib.ui.tooltip(cap))
    53         -			m:set_string('short_description', cap.title)
    54         -		end
    55         -	end;
    56         -	after_place_node = function(pos, placer, stack, tgt)
    57         -		local meta = minetest.get_meta(pos)
    58         -		local stackmeta = stack:get_meta()
    59         -		meta:from_table(stackmeta:to_table())
    60         -		if not meta:contains('infotext') then
    61         -			meta:set_string('infotext', 'Empty Keg')
    62         -		end
    63         -	end;
    64         -	on_rightclick = function(pos, node, user, stack)
    65         -		local m = minetest.get_meta(pos)
    66         -		local update = function()
    67         -			local c = kegcaption(m)
    68         -			local str = c.title
    69         -			if c.desc then str = str .. '\n(' .. c.desc .. ')' end
    70         -			if c.props then for _,p in pairs(c.props) do -- future-proofing
    71         -				str = str .. string.format('\n(%s: %s)', p.title, p.desc)
    72         -			end end
    73         -			m:set_string('infotext', str)
    74         -		end
    75         -
    76         -		if stack:is_empty() then return end
    77         -
    78         -		local ctr = sorcery.itemclass.get(stack, 'container')
    79         -		if (not ctr) or not ctr.hold == 'liquid' then return end
    80         -
    81         -		local liqid = m:get_string('liquid')
    82         -		if ctr.has and -- add liquid to keg
    83         -			(liqid == ctr.has or not m:contains('liquid')) then
    84         -			if not ctr.empty then log.err(stack:get_name(), 'does not specify its empty counterpart container') return end
    85         -
    86         -			local add = ctr.charge * stack:get_count()
    87         -			local chg = m:get_int('charge')
    88         -			if chg + add > constants.keg_volume then
    89         -				log.act(string.format('%s tried to overfill a %s keg at %s',
    90         -					user:get_player_name(),
    91         -					ctr.has, minetest.pos_to_string(pos)))
    92         -				return
           60  +		preserve_metadata = function(pos,node,meta,drops)
           61  +			if meta.liquid and meta.liquid ~= '' then
           62  +				local m = drops[1]:get_meta()
           63  +				m:from_table({fields = meta})
           64  +				local cap = kegcaption(m)
           65  +				m:set_string('description', sorcery.lib.ui.tooltip(cap))
           66  +				m:set_string('short_description', cap.title)
           67  +			end
           68  +		end;
           69  +		after_place_node = function(pos, placer, stack, tgt)
           70  +			local meta = minetest.get_meta(pos)
           71  +			local stackmeta = stack:get_meta()
           72  +			meta:from_table(stackmeta:to_table())
           73  +			if not meta:contains('infotext') then
           74  +				meta:set_string('infotext', 'Empty Keg')
           75  +			end
           76  +		end;
           77  +		on_rightclick = function(pos, node, user, stack)
           78  +			local m = minetest.get_meta(pos)
           79  +			local update = function()
           80  +				local c = kegcaption(m)
           81  +				local str = c.title
           82  +				if c.desc then str = str .. '\n(' .. c.desc .. ')' end
           83  +				if c.props then for _,p in pairs(c.props) do -- future-proofing
           84  +					str = str .. string.format('\n(%s: %s)', p.title, p.desc)
           85  +				end end
           86  +				m:set_string('infotext', str)
    93     87   			end
    94         -			m:set_int('charge', chg + add)
    95         -			m:set_string('liquid', ctr.has)
    96         -			sorcery.liquid.sound_pour(add,chg,pos)
           88  +
           89  +			if stack:is_empty() then return end
           90  +
           91  +			local ctr = sorcery.itemclass.get(stack, 'container')
           92  +			if (not ctr) or not ctr.hold == 'liquid' then return end
           93  +
           94  +			local liqid = m:get_string('liquid')
           95  +			if ctr.has and -- add liquid to keg
           96  +				(liqid == ctr.has or not m:contains('liquid')) then
           97  +				if not ctr.empty then log.err(stack:get_name(), 'does not specify its empty counterpart container') return end
           98  +
           99  +				local add = ctr.charge * stack:get_count()
          100  +				local chg = m:get_int('charge')
          101  +				if chg + add > constants.keg_volume then
          102  +					log.act(string.format('%s tried to overfill a %s keg at %s',
          103  +						user:get_player_name(),
          104  +						ctr.has, minetest.pos_to_string(pos)))
          105  +					return
          106  +				end
          107  +				m:set_int('charge', chg + add)
          108  +				m:set_string('liquid', ctr.has)
          109  +				sorcery.liquid.sound_pour(add,chg,pos)
    97    110   
    98         -			local liq = sorcery.register.liquid.db[ctr.has]
    99         -			if liq then
   100         -				update()
   101         -				log.act(string.format('%s added %u units of %s to a keg at %s',
   102         -					user:get_player_name(), add,
   103         -					ctr.has, minetest.pos_to_string(pos)))
   104         -			else log.err('no liquid entry for',ctr.has) end
          111  +				local liq = sorcery.register.liquid.db[ctr.has]
          112  +				if liq then
          113  +					update()
          114  +					log.act(string.format('%s added %u units of %s to a keg at %s',
          115  +						user:get_player_name(), add,
          116  +						ctr.has, minetest.pos_to_string(pos)))
          117  +				else log.err('no liquid entry for',ctr.has) end
   105    118   
   106         -			return ItemStack {
   107         -				name = ctr.empty;
   108         -				count = stack:get_count();
   109         -			}
   110         -		elseif not ctr.has and liqid ~= '' then -- take liquid
   111         -			local liq = sorcery.register.liquid.db[m:get_string('liquid')]
   112         -			if not liq then log.err('missing definition for liquid', liqid) return end
          119  +				return ItemStack {
          120  +					name = ctr.empty;
          121  +					count = stack:get_count();
          122  +				}
          123  +			elseif not ctr.has and liqid ~= '' then -- take liquid
          124  +				local liq = sorcery.register.liquid.db[m:get_string('liquid')]
          125  +				if not liq then log.err('missing definition for liquid', liqid) return end
   113    126   
   114         -			local basin = m:get_int('charge')
   115         -			local filled, amtleft = sorcery.liquid.fill_from_basin(stack, liqid, basin)
   116         -			if filled then
   117         -				local chg = basin - amtleft
   118         -				log.act(string.format('%s removed %u units of %s from a keg at %s',
   119         -					user:get_player_name(), chg, liqid,
   120         -					minetest.pos_to_string(pos)))
   121         -				if amtleft == 0 then
   122         -					m:set_string('liquid','')
   123         -					m:set_int('charge',0)
   124         -				else m:set_int('charge', amtleft) end
   125         -				sorcery.liquid.sound_dip(chg,avail,pos)
   126         -				update()
          127  +				local basin = m:get_int('charge')
          128  +				local filled, amtleft = sorcery.liquid.fill_from_basin(stack, liqid, basin)
          129  +				if filled then
          130  +					local chg = basin - amtleft
          131  +					log.act(string.format('%s removed %u units of %s from a keg at %s',
          132  +						user:get_player_name(), chg, liqid,
          133  +						minetest.pos_to_string(pos)))
          134  +					if amtleft == 0 then
          135  +						m:set_string('liquid','')
          136  +						m:set_int('charge',0)
          137  +					else m:set_int('charge', amtleft) end
          138  +					sorcery.liquid.sound_dip(chg,avail,pos)
          139  +					update()
   127    140   
   128         -				-- fancy visuals
   129         -				local color = sorcery.lib.color(liq.color or {255,255,255})
   130         -				local spritz = sorcery.lib.image('sorcery_droplet.png'):glow(color)
   131         -				local drop = sorcery.lib.image('sorcery_drop.png'):glow(color)
   132         -				local facing = minetest.facedir_to_dir(minetest.get_node(pos).param2)
   133         -				local noz = vector.add(pos, vector.rotate(
   134         -					vector.new(0.0,0,-0.48),
   135         -					vector.dir_to_rotation(facing)
   136         -				))
   137         -				local minnoz = vector.offset(noz, -0.03, -0.32, -0.03);
   138         -				local maxnoz = vector.offset(noz,  0.03, -0.32,  0.03);
   139         -				minetest.add_particlespawner {
   140         -					amount = 15 * chg, time = 0.1*chg;
   141         -					texture = spritz:render();
   142         -					minpos = minnoz, maxpos = maxnoz;
   143         -					minvel = vector.new(0,0,0);
   144         -					maxvel = vector.new(0,-0.1,0);
   145         -					minacc = vector.new(0,-0.1,0);
   146         -					maxacc = vector.new(0,-0.13,0);
   147         -					minsize = 0.4, maxsize = 1;
   148         -					glow = 14; -- FIXME liquid glow prop
   149         -					minexptime = 0.5, maxexptime = 0.5;
   150         -					animation = {
   151         -						type = 'sheet_2d';
   152         -						frames_w = 14;
   153         -						frames_h = 1;
   154         -						frame_length = (0.5/14) + 0.02;
   155         -					}
   156         -				}
   157         -				minetest.after(0.2, function()
          141  +					-- fancy visuals
          142  +					local color = sorcery.lib.color(liq.color or {255,255,255})
          143  +					local spritz = sorcery.lib.image('sorcery_droplet.png'):glow(color)
          144  +					local drop = sorcery.lib.image('sorcery_drop.png'):multiply(color)
          145  +					local facing = minetest.facedir_to_dir(minetest.get_node(pos).param2)
          146  +					local noz = vector.add(
          147  +						vector.offset(pos,0,keg.ofs or 0,0),
          148  +						vector.rotate(
          149  +							vector.new(0.0,0,-0.48),
          150  +							vector.dir_to_rotation(facing)
          151  +						)
          152  +					)
          153  +					local minnoz = vector.offset(noz, -0.03, -0.32, -0.03);
          154  +					local maxnoz = vector.offset(noz,  0.03, -0.32,  0.03);
   158    155   					minetest.add_particlespawner {
   159         -						amount = math.random(5,11) * chg, time = 0.13 * chg;
   160         -						texture = drop:render();
   161         -						minpos = minnoz;
   162         -						maxpos = maxnoz;
   163         -						minvel = vector.new(0,-0.1,0);
   164         -						maxvel = vector.new(0,-0.4,0);
   165         -						minacc = vector.new(0,-0.15,0);
   166         -						maxacc = vector.new(0,-0.18,0);
   167         -						minsize = 0.3, maxsize = 0.5;
          156  +						amount = 15 * chg, time = 0.1*chg;
          157  +						texture = spritz:render();
          158  +						minpos = minnoz, maxpos = maxnoz;
          159  +						minvel = vector.new(0,0,0);
          160  +						maxvel = vector.new(0,-0.1,0);
          161  +						minacc = vector.new(0,-0.1,0);
          162  +						maxacc = vector.new(0,-0.13,0);
          163  +						minsize = 0.4, maxsize = 1;
   168    164   						glow = 14; -- FIXME liquid glow prop
   169         -						minexptime = 1, maxexptime = 1.5;
          165  +						minexptime = 0.5, maxexptime = 0.5;
   170    166   						animation = {
   171    167   							type = 'sheet_2d';
   172         -							frames_w = 10;
          168  +							frames_w = 14;
   173    169   							frames_h = 1;
   174         -							frame_length = (1.5/10) + 0.02;
          170  +							frame_length = (0.5/14) + 0.02;
   175    171   						}
   176    172   					}
   177         -				end)
          173  +					minetest.after(0.2, function()
          174  +						minetest.add_particlespawner {
          175  +							amount = math.random(5,11) * chg, time = 0.13 * chg;
          176  +							texture = drop:render();
          177  +							minpos = minnoz;
          178  +							maxpos = maxnoz;
          179  +							minvel = vector.new(0,-0.1,0);
          180  +							maxvel = vector.new(0,-0.4,0);
          181  +							minacc = vector.new(0,-0.15,0);
          182  +							maxacc = vector.new(0,-0.18,0);
          183  +							minsize = 0.3, maxsize = 0.5;
          184  +							glow = 14; -- FIXME liquid glow prop
          185  +							minexptime = 1, maxexptime = 1.5;
          186  +							animation = {
          187  +								type = 'sheet_2d';
          188  +								frames_w = 10;
          189  +								frames_h = 1;
          190  +								frame_length = (1.5/10) + 0.02;
          191  +							}
          192  +						}
          193  +					end)
   178    194   
   179         -				return filled
          195  +					return filled
          196  +				end
   180    197   			end
   181         -		end
   182         -	end;
   183         -})
          198  +		end;
          199  +	})
          200  +end
   184    201   
   185    202   minetest.register_craft {
   186    203   	output = "sorcery:keg";
   187    204   	recipe = {
   188    205   		{'','screwdriver:screwdriver',''};
   189    206   		{'sorcery:screw_bronze', 'sorcery:tap', 'sorcery:screw_bronze'};
   190    207   		{'sorcery:screw_bronze', 'xdecor:barrel', 'sorcery:screw_bronze'};
   191    208   	};
   192    209   	replacements = {
   193    210   		{'screwdriver:screwdriver', 'screwdriver:screwdriver'};
   194    211   	};
   195    212   }
          213  +
          214  +minetest.register_craft {
          215  +	output = "sorcery:keg_stand";
          216  +	recipe = {
          217  +		{'','sorcery:keg',''};
          218  +		{'sorcery:screw_steel','group:wood','sorcery:screw_steel'};
          219  +		{'sorcery:screw_steel','screwdriver:screwdriver','sorcery:screw_steel'};
          220  +	};
          221  +	replacements = {{'screwdriver:screwdriver', 'screwdriver:screwdriver'}};
          222  +}
          223  +
          224  +minetest.register_craft {
          225  +	output = "sorcery:keg";
          226  +	type = 'shapeless';
          227  +	recipe = { 'sorcery:keg_stand', 'screwdriver:screwdriver' };
          228  +	replacements = {
          229  +		{'screwdriver:screwdriver', 'screwdriver:screwdriver'};
          230  +		{'sorcery:keg_stand', 'sorcery:screw_steel 4'};
          231  +	};
          232  +}