sorcery  Diff

Differences From Artifact [3a290dc995]:

To Artifact [56e196edd6]:

  • File data/runes.lua — part of check-in [15f176a7fe] at 2020-10-31 19:49:49 on branch trunk — 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 (user: lexi, size: 42828) [annotate] [blame] [check-ins using]

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