sorcery  Diff

Differences From Artifact [b24c7d1147]:

To Artifact [4b624880ad]:


1
2
3
4
5
6
7
8
9
10






11


12
13
14
15
16
17
18
19
20
21
22
23

24




25
26
27
28

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133


134
135
136


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

184
185
186
187
188
189
190
191
192
193
194
195




















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

local hitbox = {
	type = 'fixed';
	fixed = {
		-0.4, -0.5, -0.5;
		 0.4,  0.2,  0.5;
	};






}


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




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' } };
		};
	};
	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'):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()
					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;
})


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'};
	};
}
























|


|
|

>
>
>
>
>
>
|
>
>












>

>
>
>
>
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|

|
|
|
|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
>
>
|
|
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
>












>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
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; 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'};
	};
}