sorcery  Check-in [15f176a7fe]

Overview
Comment:add background noise for condensers (temporary hack, need to write a proper environment sound framework as the fucking env_sounds module is completely impossible to extend), fix a couple of really stupid bugs, make higher-quality phials increase the chance of getting good runes so it's not a complete waste to burn iridium or levitanium powder on making them, add targeted disjunction and some other amulet spells
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 15f176a7fefa031a320ed873892e85e5ff4bcd338cdae268d27277b8767ea759
User & Date: lexi on 2020-10-31 19:49:49
Other Links: manifest | tags
Context
2021-04-21
01:32
ui tweaks, rework enchantment slightly check-in: 41fdb5b0b8 user: lexi tags: trunk
2020-10-31
19:49
add background noise for condensers (temporary hack, need to write a proper environment sound framework as the fucking env_sounds module is completely impossible to extend), fix a couple of really stupid bugs, make higher-quality phials increase the chance of getting good runes so it's not a complete waste to burn iridium or levitanium powder on making them, add targeted disjunction and some other amulet spells check-in: 15f176a7fe user: lexi tags: trunk
2020-10-30
19:03
squish oversized sound effect check-in: b96185e88b user: lexi tags: trunk
Changes

Modified data/runes.lua from [3a290dc995] to [56e196edd6].

    97     97   				sounds = {
    98     98   					[0] = { sound = 'sorcery_stutter', pos = 'subjects' };
    99     99   				};
   100    100   			}
   101    101   		end
   102    102   	end
   103    103   end
          104  +
          105  +local purge = function(target)
          106  +	local h = target:get_properties().eye_height * 1.1
          107  +	minetest.add_particlespawner {
          108  +		time = 0.2, amount = math.random(200,250), attached = target;
          109  +		glow = 14, texture = sorcery.vfx.glowspark(sorcery.lib.color(156,255,10)):render();
          110  +		minpos = {x = -0.3, y = -0.5, z = -0.3};
          111  +		maxpos = {x =  0.3, y =  h,   z =  0.3};
          112  +		minvel = {x = -1.8, y = -1.8, z = -1.8};
          113  +		maxvel = {x =  1.8, y =  1.8, z =  1.8};
          114  +		minsize = 0.2, maxsize = 5;
          115  +		animation = {
          116  +			type = 'vertical_frames', length = 4.1;
          117  +			aspect_w = 16, aspect_h = 16;
          118  +		};
          119  +		minexptime = 2, maxexptime = 4;
          120  +	}
          121  +	minetest.sound_play('sorcery_disjoin',{object=target},true)
          122  +	sorcery.spell.disjoin{target=target}
          123  +end
          124  +
   104    125   return {
   105    126   	translocate = {
   106    127   		name = 'Translocate';
   107    128   		tone = {0,235,233};
   108    129   		minpower = 3;
   109    130   		rarity = 7;
   110    131   		amulets = {
................................................................................
   133    154   					else
   134    155   						ctx.sparkle = false
   135    156   					end
   136    157   				end;
   137    158   				frame = {
   138    159   					tungsten = {
   139    160   						name = 'Quick Joining';
   140         -						desc = 'Give this amulet to another and they can arrive safely at your side almost instantaneously from anywhere in the world — though returning whence they came may be a more difficult matter';
          161  +						desc = 'Give this amulet to another and they can arrive safely at your side almost instantaneously from anywhere at all in the world — though returning whence they came may be a more difficult matter';
   141    162   					};
   142    163   					gold = {
   143    164   						name = 'Exchange';
   144    165   						desc = 'Give this amulet to another and they will be able to trade places with you no matter where in the world each of you might be.'; 
   145    166   					};
   146    167   					cobalt = {
   147    168   						name = 'Sending';
................................................................................
   161    182   				end;
   162    183   				cast = function(ctx)
   163    184   					if not ctx.meta:contains('rune_return_dest') then
   164    185   						local pos = ctx.caster:get_pos()
   165    186   						ctx.meta:set_string('rune_return_dest',minetest.pos_to_string(pos))
   166    187   						return true -- play effects but do not break spell
   167    188   					else
          189  +						if ctx.caster:get_attach() ~= nil then return false end
   168    190   						local pos = minetest.string_to_pos(ctx.meta:get_string('rune_return_dest'))
   169    191   						ctx.meta:set_string('rune_return_dest','')
   170    192   						local subjects = { ctx.caster }
   171    193   						local center = ctx.caster:get_pos()
   172    194   						ctx.sparkle = false
   173    195   						local delay = math.max(3,10 - ctx.stats.power) + 3*(math.random()*2-1)
   174    196   						teleport(ctx,{{ref=ctx.caster}},delay,pos)
................................................................................
   194    216   						desc = 'Use this amulet once to bind it to a particular point in the world, then use it again to seize up everyone surrounding you in the grip of a fearsome magic that will deport them all in the blink of an eye to whatever destination you have chosen';
   195    217   					};
   196    218   				};
   197    219   			};
   198    220   			ruby = minetest.get_modpath('beds') and {
   199    221   				name = 'Escape';
   200    222   				desc = 'Immediately transport yourself out of a dangerous situation back to the last place you slept, before anyone has time to net you in a disjunction';
          223  +				mingrade = 4;
   201    224   				cast = function(ctx)
   202    225   					-- if not beds.spawns then beds.read_spawns() end
   203    226   					local subjects = {ctx.caster}
   204    227   					for _,s in pairs(subjects) do
   205    228   						local spp = beds.spawn[ctx.caster:get_player_name()]
   206    229   						if spp then
   207    230   							local oldpos = s:get_pos()
................................................................................
   389    412   			sapphire = {
   390    413   				name = 'Unsealing';
   391    414   				desc = 'Wielding this amulet, a touch of your hand will unravel even the mightiest protective magics, leaving doors unsealed and walls free to tear down';
   392    415   			};
   393    416   			amethyst = {
   394    417   				name = 'Purging';
   395    418   				desc = 'Free yourself from the grip of any malicious spellwork with a snap of your fingers — interrupting all of your own active spells in the process, including impending translocations';
   396         -				cast = function(ctx)
   397         -					local h = ctx.heading.eyeheight * 1.1
   398         -					minetest.add_particlespawner {
   399         -						time = 0.2, amount = math.random(200,250), attached = ctx.caster;
   400         -						glow = 14, texture = sorcery.vfx.glowspark(sorcery.lib.color(156,255,10)):render();
   401         -						minpos = {x = -0.3, y = -0.5, z = -0.3};
   402         -						maxpos = {x =  0.3, y =  h,   z =  0.3};
   403         -						minvel = {x = -1.8, y = -1.8, z = -1.8};
   404         -						maxvel = {x =  1.8, y =  1.8, z =  1.8};
   405         -						minsize = 0.2, maxsize = 5;
   406         -						animation = {
   407         -							type = 'vertical_frames', length = 4.1;
   408         -							aspect_w = 16, aspect_h = 16;
   409         -						};
   410         -						minexptime = 2, maxexptime = 4;
   411         -					}
   412         -					minetest.sound_play('sorcery_disjoin',{object=ctx.caster},true)
   413         -					sorcery.spell.disjoin{target=ctx.caster}
   414         -				end;
          419  +				cast = function(ctx) purge(ctx.caster) end;
   415    420   			};
   416    421   			emerald = {
   417    422   				name = 'Disjunction Field';
   418    423   				desc = 'Render an area totally opaque to spellwork for a period of time, disrupting any existing spells and preventing further spellcasting therein';
   419    424   			};
   420    425   			ruby = {
   421    426   				name = 'Disjunction';
   422    427   				desc = 'Wield this amulet against a spellcaster to disrupt and abort all their spells in progress, perhaps to trap a foe intent on translocating away, or unleash its force upon the victim of a malign hex to free them from its clutches';
          428  +				mingrade = 3;
          429  +				cast = function(ctx)
          430  +					if ctx.target.type == 'object'
          431  +						then purge(ctx.target.ref)
          432  +						else return false
          433  +					end
          434  +				end;
   423    435   				frame = {
   424    436   					iridium = {
   425    437   						name = 'Nullification';
          438  +						mingrade = 5;
   426    439   						desc = 'Not only will your victim\'s spells be nullified, but all enchanted objects they carry will be stripped of their power — or possibly even destroyed outright';
   427    440   					};
   428    441   				};
   429    442   			};
   430    443   			luxite = {
   431    444   				name = 'Disjunctive Aura';
   432    445   				desc = 'For a time, all magic undertaken in your vicinity will fail totally — including your own';
................................................................................
   851    864   				mingrade = 4;
   852    865   				name = 'Duplication';
   853    866   				desc = 'Bring an exact twin of any object or item into existence, no matter how common or rare it might be';
   854    867   				cast = function(ctx)
   855    868   					local color = sorcery.lib.color(255,61,205)
   856    869   					local dup, sndpos, anchor, sbj, ty
   857    870   					if ctx.target.type == 'object' and ctx.target.ref:get_luaentity().name == '__builtin:item' then
   858         -						sorcery.vfx.imbue(color, ctx.target.ref)
          871  +						-- sorcery.vfx.imbue(color, ctx.target.ref) -- causes graphics card problems???
   859    872   						sndpos = 'subjects'
   860    873   						sbj = {{player = ctx.target.ref}}
   861    874   						local item = ItemStack(ctx.target.ref:get_luaentity().itemstring)
   862    875   						local r = function() return math.random() * 2 - 1 end
   863    876   						local putpos = vector.offset(ctx.target.ref:get_pos(), r(), 1, r())
   864    877   						dup = function()
   865    878   							item:set_count(1) -- nice try bouge-san
................................................................................
   881    894   										vp[#vp+1] = sum
   882    895   									end
   883    896   								end
   884    897   								if #vp > 0 then npos=vp[math.random(#vp)] end
   885    898   							end
   886    899   							if npos then
   887    900   								minetest.set_node(npos, minetest.get_node(ctx.target.under))
          901  +								if minetest.registered_nodes[ty].on_construct then
          902  +									minetest.registered_nodes[ty].on_construct(npos)
          903  +								end
   888    904   								minetest.get_meta(npos):from_table(origmeta)
   889    905   								return npos, true
   890    906   							else
   891    907   								local nstack = ItemStack(ty)
   892    908   								nstack:get_meta():from_table(origmeta)
   893    909   								local leftover = ctx.caster:get_inventory():add_item('main',nstack)
   894    910   								if leftover and not leftover.is_empty() then
................................................................................
   972    988   		tone = {255,194,0};
   973    989   		minpower = 1;
   974    990   		rarity = 5;
   975    991   		amulets = {
   976    992   			luxite = {
   977    993   				name = 'Glow';
   978    994   				desc = 'Swathe yourself in an aura of sparkling radiance, casting light upon all the dark places where you voyage';
          995  +				cast = function(ctx)
          996  +					local fac = (ctx.stats.power * 0.1)
          997  +					local radius = 2 + 5*fac
          998  +					local period = 0.4 - 0.3*fac
          999  +					local glowduration = 5 + 50*fac
         1000  +					sorcery.spell.cast {
         1001  +						name = "sorcery:glow";
         1002  +						caster = ctx.caster;
         1003  +						subjects = {{player=ctx.caster}};
         1004  +						duration = 40 + 120*fac;
         1005  +						nodes = {};
         1006  +						disjoin = function(self)
         1007  +							for _,n in pairs(self.nodes) do
         1008  +								if sorcery.lib.str.beginswith(minetest.get_node(n).name,'sorcery:air_glimmer_') then
         1009  +									minetest.remove_node(n)
         1010  +								end
         1011  +							end
         1012  +						end;
         1013  +						intervals = {
         1014  +							{period = period, after = {whence=0,secs=0.7}, fn = function(c)
         1015  +								print('cycling!')
         1016  +								for _,sub in pairs(c.spell.subjects) do
         1017  +									local ox, oy, oz = math.random(-radius,radius),
         1018  +													   math.random(-radius,radius),
         1019  +													   math.random(-radius,radius)
         1020  +									local pos = vector.offset(sub.player:get_pos(), ox,oy,oz)
         1021  +									print('pos',minetest.pos_to_string(pos),'player',minetest.pos_to_string(sub.player:get_pos()))
         1022  +									if sorcery.lib.node.is_air(pos) then
         1023  +										print('is air!')
         1024  +										local power = math.random(4,minetest.LIGHT_MAX)
         1025  +										minetest.set_node(pos, {
         1026  +											name = 'sorcery:air_glimmer_' .. tostring(power);
         1027  +										})
         1028  +										c.spell.nodes[#c.spell.nodes + 1] = pos
         1029  +										local d = glowduration * (0.5 + math.random()*0.5)
         1030  +										local m = minetest.get_meta(pos)
         1031  +										m:set_float('duration', d)
         1032  +										m:set_float('timeleft', d)
         1033  +										m:set_int('power', power)
         1034  +									else
         1035  +										print('not air!', dump(minetest.get_node(pos)))
         1036  +									end
         1037  +								end
         1038  +							end};
         1039  +						};
         1040  +					}
         1041  +				end;
   979   1042   				iridium = {
   980   1043   					name = 'Aura';
   981   1044   					desc = 'Dazzling golden luminance emanates from the bodies of all those around you, and you walk in light even amid the darkest depths of the earth';
   982   1045   				};
   983   1046   			};
   984   1047   			diamond = {
   985   1048   				name = 'Radiance';
   986   1049   				desc = 'Set the air around you alight with a mystic luminance, letting you see clearly a great distance in every direction for several minutes';
   987   1050   				frame = {
   988   1051   					iridium = {
   989   1052   						name = 'Sunshine';
   990   1053   						mingrade = 5;
   991   1054   						desc = 'Unleash the power of this amulet to seize ultimate control over the forces of nature and summon the Sun high into the nighttime sky';
         1055  +						cast = function(ctx)
         1056  +							local time = minetest.get_timeofday()
         1057  +							if not (time < 0.3 or time > 0.7) then return false end
         1058  +							local diff = 0.5 - time
         1059  +							local frames = 40
         1060  +							local duration = 1.5
         1061  +							local delta = diff / frames
         1062  +							local tl = {}
         1063  +							for i=1,frames do
         1064  +								local wh = {whence=0, secs=duration*(i/frames)}
         1065  +								tl[wh] = function(s)
         1066  +									minetest.set_timeofday(time + delta*i)
         1067  +								end
         1068  +							end
         1069  +							sorcery.spell.cast {
         1070  +								name = 'sorcery:sunshine';
         1071  +								caster = ctx.caster;
         1072  +								timeline = tl;
         1073  +								duration = duration;
         1074  +							}
         1075  +						end;
   992   1076   					};
   993   1077   				};
   994   1078   			};
   995   1079   		};
   996   1080   	};
   997   1081   	dominate = {
   998   1082   		name = 'Dominate';

Modified data/spells.lua from [16c84d9b57] to [dffc43152b].

   781    781   				local delta = vector.subtract(pos,center)
   782    782   				local near = 1 - (delta.x^2 + delta.y^2 + delta.z^2)/(range^2)
   783    783   				if minetest.get_node(pos).name == 'air' then
   784    784   					minetest.set_node(pos,{name='sorcery:air_glimmer_' .. tostring(lum)})
   785    785   					do local lm = minetest.get_meta(pos)
   786    786   						lm:set_float('duration',duration)
   787    787   						lm:set_float('timeleft',duration)
   788         -						lm:set_float('power',lum * near)
          788  +						lm:set_int('power',lum * near)
   789    789   					end
   790    790   				end
   791    791   			end
   792    792   		end;
   793    793   	};
   794    794   }

Modified leylines.lua from [fd8a9ad01c] to [a8ee2829a5].

    10     10   sorcery.ley.estimate = function(pos)
    11     11   	local affs = {
    12     12   		'praxic'; 'counterpraxic'; 'cognic';
    13     13   		'mandatic'; 'occlutic'; 'imperic';
    14     14   		'syncretic'; 'entropic';
    15     15   	};
    16     16   	local forcemap = minetest.get_perlin(0xe9a01d, 3, 2, 150)
    17         -	local aff1map = minetest.get_perlin(0x10eb03, 3, 2, 300)
    18         -	local aff2map = minetest.get_perlin(0x491e12, 3, 2, 240)
    19         -	local txpos = { --- :( :( :( :(
           17  +	local aff1map  = minetest.get_perlin(0x10eb03, 3, 2, 300)
           18  +	local aff2map  = minetest.get_perlin(0x491e12, 3, 2, 240)
           19  +	local txpos = { 
    20     20   		x = pos.x;
    21         -		y = pos.z;
           21  +		y = pos.z; --- :( :( :( :(
    22     22   		z = pos.y;
    23     23   	}
    24     24   
    25     25   	local normalize = function(map)
    26     26   		local v = map:get_2d(txpos)
    27     27   		return (v + 6) / 12 -- seriously??
    28     28   	end
................................................................................
   367    367   				end;
   368    368   			};
   369    369   			recipe = {
   370    370   				note = 'Captures radiant force and suffuses it through distribution net. Energy production varies with local leyline strength.';
   371    371   			};
   372    372   		};
   373    373   	})
          374  +	
          375  +	minetest.register_abm {
          376  +		name = 'Condenser sound effects';
          377  +		nodenames = {'sorcery:condenser'};
          378  +		neighbors = {'group:sorcery_ley_device'};
          379  +		interval = 5.6, chance = 1, catch_up = false;
          380  +		action = function(pos)
          381  +			local force = sorcery.ley.estimate(pos).force
          382  +			minetest.sound_play('sorcery_condenser_bg', {
          383  +				pos = pos, max_hear_distance = 5 + 8*force, gain = force*0.3;
          384  +			})
          385  +		end;
          386  +	}
   374    387   end
   375    388   
   376    389   minetest.register_craft {
   377    390   	output = 'sorcery:condenser';
   378    391   	recipe = {
   379    392   		{'sorcery:accumulator'};
   380    393   		{'sorcery:conduit'};

Modified lib/node.lua from [4b89fedafd] to [b8ef82adf6].

    69     69   	end; 
    70     70   
    71     71   	is_air = function(pos)
    72     72   		local n = sorcery.lib.node.force(pos)
    73     73   		if n.name == 'air' then return true end
    74     74   		local d = minetest.registered_nodes[n.name]
    75     75   		if not d then return false end
    76         -		return not d.walkable
           76  +		return (d.walkable == false) and (d.drawtype == 'airlike' or d.buildable_to == true)
    77     77   	end;
    78     78   
    79     79   	is_clear = function(pos)
    80     80   		if not sorcery.lib.node.is_air(pos) then return false end
    81     81   		local ents = minetest.get_objects_inside_radius(pos,0.5)
    82     82   		if #ents > 0 then return false end
    83     83   		return true

Modified runeforge.lua from [f2cf52d41a] to [4e5c236dfa].

    14     14   	rune_grades = {'Fragile', 'Weak', 'Ordinary', 'Pristine', 'Sublime'};
    15     15   	-- how many grades of rune quality/power there are
    16     16   	
    17     17   	amulet_grades = {'Slight', 'Minor', 'Major', 'Grand', 'Ultimate' };
    18     18   	-- what kind of amulet each rune grade translates to
    19     19   	
    20     20   	phial_kinds = {
    21         -		lesser   = {grade = 1; name = 'Lesser';   infusion = 'sorcery:powder_brass'};
    22         -		simple   = {grade = 2; name = 'Simple';   infusion = 'sorcery:powder_silver'};
    23         -		great    = {grade = 3; name = 'Great';    infusion = 'sorcery:powder_gold'};
    24         -		splendid = {grade = 4; name = 'Splendid'; infusion = 'sorcery:powder_electrum'};
    25         -		exalted  = {grade = 5; name = 'Exalted';  infusion = 'sorcery:powder_levitanium'};
    26         -		supreme  = {grade = 6; name = 'Supreme';  infusion = 'sorcery:essence_force'};
           21  +		lesser   = {grade = 1, name = 'Lesser';   infusion = 'sorcery:powder_brass';
           22  +			dist = { Fragile = 1, Weak = 0.7,  Ordinary = 0.1, Pristine = 0.05, Sublime = 0.01 };
           23  +		};
           24  +		simple   = {grade = 2, name = 'Simple';   infusion = 'sorcery:powder_silver';
           25  +			dist = { Fragile = 1, Weak = 0.8,  Ordinary = 0.2, Pristine = 0.07, Sublime = 0.015 };
           26  +		};
           27  +		great    = {grade = 3, name = 'Great';    infusion = 'sorcery:powder_gold';
           28  +			dist = { Fragile = 1, Weak = 0.9,  Ordinary = 0.5, Pristine = 0.1,  Sublime = 0.05 };
           29  +		};
           30  +		splendid = {grade = 4, name = 'Splendid'; infusion = 'sorcery:powder_electrum';
           31  +			dist = { Fragile = 1, Weak = 0.95, Ordinary = 0.7, Pristine = 0.3,  Sublime = 0.1 };
           32  +		};
           33  +		exalted  = {grade = 5, name = 'Exalted';  infusion = 'sorcery:powder_iridium';
           34  +			dist = { Fragile = 0, Weak = 1,    Ordinary = 0.9, Pristine = 0.5,  Sublime = 0.25 };
           35  +		};
           36  +		supreme  = {grade = 6, name = 'Supreme';  infusion = 'sorcery:powder_levitanium';
           37  +			dist = { Fragile = 0, Weak = 0,    Ordinary = 1,   Pristine = 0.7,  Sublime = 0.4 };
           38  +		};
    27     39   	};
    28     40   }
    29     41   local calc_phial_props = function(phial) --> mine interval: float, time factor: float
    30     42   	local g = phial:get_definition()._proto.data.grade
    31     43   	local i = constants.rune_mine_interval 
    32     44   	local fac = (g-1) / 5
    33     45   	return i - ((i*0.5) * fac), 0.5 * fac
................................................................................
    53     65   	local f = string.format
    54     66   	local color = sorcery.lib.color(142,232,0)
    55     67   	local fac = p.grade / 6
    56     68   	local id = f('phial_%s', name);
    57     69   	sorcery.register_potion_tbl {
    58     70   		name = id;
    59     71   		label = f('%s Phial',p.name);
    60         -		desc = "A powerful liquid consumed in the operation of a rune forge. Its quality determines how fast new runes can be constructed and how much energy is required by the process.";
           72  +		desc = "A powerful liquid consumed in the operation of a rune forge. Its quality determines how fast new runes can be constructed and how much energy is required by the process, and affects your odds of getting a high-quality rune.";
    61     73   		color = color:brighten(1 + fac*0.5);
    62     74   		imgvariant = (fac >= 5) and 'sparkle' or 'dull';
    63     75   		glow = 5+p.grade;
    64     76   		extra = {
    65     77   			groups = { sorcery_phial = p.grade };
    66     78   			_proto = { id = name, data = p };
    67     79   		};
................................................................................
   196    208   end
   197    209   
   198    210   sorcery.amulet.getspell = function(stack)
   199    211   	local m = stack:get_meta()
   200    212   	local proto = stack:get_definition()._sorcery.amulet
   201    213   	if not m:contains('amulet_rune') then return nil end
   202    214   	local rune = m:get_string('amulet_rune')
   203         -	local rg = m:get_string('amulet_rune_grade')
          215  +	local rg = m:get_int('amulet_rune_grade')
   204    216   	local rd = sorcery.data.runes[rune]
   205    217   	local spell = rd.amulets[proto.base]
   206    218   	if not spell then return nil end
   207    219   	local title,desc,cast,apply,remove,mingrade = spell.name, spell.desc, spell.cast, spell.apply, spell.remove, spell.mingrade -- FIXME in serious need of refactoring
   208    220   	local base_spell = true
   209    221   
   210    222   	if proto.frame and spell.frame and spell.frame[proto.frame] then
   211    223   		local sp = spell.frame[proto.frame]
   212         -		title = sp.name or title
   213         -		desc = sp.desc or desc
   214         -		cast = sp.desc or cast
   215         -		apply = sp.apply or apply
   216         -		remove = sp.remove or remove
   217         -		mingrade = sp.mingrade or remove
   218         -		base_spell = false
          224  +		if not sp.mingrade or rg >= sp.mingrade then
          225  +			title = sp.name or title
          226  +			desc = sp.desc or desc
          227  +			cast = sp.desc or cast
          228  +			apply = sp.apply or apply
          229  +			remove = sp.remove or remove
          230  +			mingrade = sp.mingrade or mingrade
          231  +			base_spell = false
          232  +		end
   219    233   	end
   220    234   	
   221    235   	return {
   222    236   		rune = rune, grade = rg;
   223    237   		spell = spell, mingrade = mingrade;
   224    238   		name = title, desc = desc;
   225    239   		cast = cast, apply = apply, remove = remove;
................................................................................
   237    251   	local probe = sorcery.spell.probe(pos)
   238    252   
   239    253   	local pow_min = l.self.powerdraw >= l.self.minpower
   240    254   	local pow_max = l.self.powerdraw >= l.self.maxpower
   241    255   	local has_phial = function() return not i:is_empty('phial') end
   242    256   
   243    257   	if time and has_phial() and pow_min and not probe.disjunction then -- roll for runes
   244         -		local int, powerfac = calc_phial_props(i:get_stack('phial',1))
          258  +		local phial = i:get_stack('phial',1)
          259  +		local int, powerfac = calc_phial_props(phial)
   245    260   		local rolls = math.floor(time/int)
   246    261   		local newrunes = {}
   247    262   		for _=1,rolls do
   248    263   			local choices = {}
   249    264   			for name,rune in pairs(sorcery.data.runes) do
   250    265   				-- print('considering',name)
   251    266   				-- print('-- power',rune.minpower,(rune.minpower*powerfac)*time,'//',l.self.powerdraw,l.self.powerdraw/time,'free',l.freepower,'max',l.maxpower)
................................................................................
   267    282   			end
   268    283   			-- print('rune choices:',dump(choices))
   269    284   			-- print('me',dump(l.self))
   270    285   		end
   271    286   
   272    287   		for _,r in pairs(newrunes) do
   273    288   			if i:room_for_item('cache',r) and has_phial() then
   274         -				local qual = math.random(#constants.rune_grades)
          289  +				local qual
          290  +				-- iterate through qualities from highest to lowest, rolling against the phial's
          291  +				-- distribution for each, and stopping when we find one
          292  +				local qdist = phial:get_definition()._proto.data.dist
          293  +				for i=#constants.rune_grades,1,-1 do
          294  +					local chance = qdist[constants.rune_grades[i]]
          295  +					if chance == 1 or math.random() <= chance then
          296  +						qual = i
          297  +						break
          298  +					end
          299  +				end
   275    300   				rune_set(r,{grade = qual})
   276    301   				i:add_item('cache',r)
   277    302   				-- consume a phial
   278    303   				local ph = i:get_stack('phial',1)
   279         -				local n = ph:get_name()
   280    304   				ph:take_item(1) i:set_stack('phial',1,ph)
   281         -				minetest.add_item(pos,i:add_item('refuse',ItemStack(sorcery.register.residue.db[n])))
          305  +				minetest.add_item(pos,i:add_item('refuse',ItemStack(sorcery.register.residue.db[ph:get_name()])))
   282    306   			else break end
   283    307   		end
   284    308   	end
   285    309   
   286    310   	has_phial = has_phial()
   287    311   	local spec = string.format([[
   288    312   		formspec_version[3] size[10.25,8] real_coordinates[true]

Added sounds/sorcery_condenser_bg.ogg version [51e11fd1e4].

cannot compute difference between binary files