sorcery  Diff

Differences From Artifact [67a4930ba7]:

To Artifact [4936c92bc2]:


     1      1   -- a rune is an abstract object created by a runeforge, which can be
     2      2   -- applied to an amulet in order to imbue that amulet with unique
     3      3   -- and fearsome powers. the specific spell depends on the stone the
     4      4   -- rune is applied to, and not all runes can necessarily be applied
     5      5   -- to all stones.
     6      6   
            7  +local L = sorcery.lib
     7      8   local sparkle_region = function(s)
     8      9   	s.spell.visual_subjects {
     9     10   		amount = s.amt, time = s.time, -- attached = s;
    10     11   		minpos = s.minpos;
    11     12   		maxpos = s.maxpos;
    12     13   		minvel = { x = -0.4, y = -0.2, z = -0.4 };
    13     14   		maxvel = { x =  0.4, y =  0.2, z =  0.4 };
................................................................................
   122    123   	sorcery.spell.disjoin{target=target}
   123    124   end
   124    125   
   125    126   return {
   126    127   	translocate = {
   127    128   		name = 'Translocate';
   128    129   		tone = {0,235,233};
   129         -		minpower = 3;
   130         -		rarity = 7;
          130  +		minpower = 2;
          131  +		rarity = 8;
   131    132   		amulets = {
   132    133   			amethyst = {
   133    134   				name = 'Joining';
   134    135   				desc = 'Give this amulet to another and with a snap of their fingers they can arrive safely at your side from anywhere in the world — though returning whence they came may be a more difficult matter';
   135    136   				apply = function(ctx)
   136    137   					local maker = ctx.user:get_player_name()
   137    138   					ctx.meta:set_string('rune_join_target',maker)
................................................................................
   408    409   			};
   409    410   		};
   410    411   	};
   411    412   	disjoin = {
   412    413   		name = 'Disjoin';
   413    414   		tone = {159,235,0};
   414    415   		minpower = 4;
   415         -		rarity = 34;
          416  +		rarity = 10;
   416    417   		amulets = {
   417    418   			sapphire = {
   418    419   				name = 'Unsealing';
   419    420   				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';
          421  +				sound = 'sorcery_disjoin';
   420    422   				cast = function(ctx)
   421    423   					if ctx.target.type ~= 'node' then return false end
   422    424   					local r = 2 + math.floor(ctx.stats.power / 2)
   423    425   					local cast = false
   424    426   					for x = -r,r do
   425    427   					for y = -r,r do
   426    428   					for z = -r,r do
................................................................................
   442    444   					end
   443    445   					return cast
   444    446   				end;
   445    447   			};
   446    448   			amethyst = {
   447    449   				name = 'Purging';
   448    450   				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';
          451  +				sound = 'sorcery_disjoin';
   449    452   				cast = function(ctx) purge(ctx.caster) end;
   450    453   			};
   451    454   			emerald = {
   452    455   				name = 'Disjunction Field';
   453    456   				desc = 'Render an area totally opaque to spellwork for a period of time, disrupting any existing spells and preventing further spellcasting therein';
          457  +				sound = 'sorcery_disjoin';
   454    458   			};
   455    459   			ruby = {
   456    460   				name = 'Disjunction';
   457    461   				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';
   458    462   				mingrade = 3;
          463  +				sound = 'sorcery_disjoin';
   459    464   				cast = function(ctx)
   460    465   					if ctx.target.type == 'object'
   461    466   						then purge(ctx.target.ref)
   462    467   						else return false
   463    468   					end
   464    469   				end;
   465    470   				frame = {
................................................................................
   469    474   						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';
   470    475   					};
   471    476   				};
   472    477   			};
   473    478   			luxite = {
   474    479   				name = 'Disjunctive Aura';
   475    480   				desc = 'For a time, all magic undertaken in your vicinity will fail totally — including your own';
          481  +				sound = 'sorcery_disjoin';
   476    482   				cast = function(ctx)
   477    483   					local h = ctx.heading.eyeheight*1.1
   478    484   					sorcery.spell.cast {
   479    485   						name = 'sorcery:disjunctive-aura';
   480    486   						caster = ctx.caster, attach = 'caster';
   481    487   						subjects = {{player=ctx.caster}};
   482    488   						disjunction = true, range = 4 + ctx.stats.power;
................................................................................
   510    516   									minpos = { x = 0-range, y = -0.5, z = 0-range };
   511    517   									maxpos = { x =   range, y = h,    z =   range };
   512    518   									img = sorcery.lib.image('sorcery_flicker.png'):glow(sorcery.lib.color(120,255,30));
   513    519   								}
   514    520   							end;
   515    521   						};
   516    522   						sounds = {
   517         -							[0.00] = {sound='sorcery_disjoin',   where='caster'};
          523  +							-- [0.00] = {sound='sorcery_disjoin',   where='caster'};
   518    524   							[{whence=0,secs=0.8}] = {
   519    525   								sound='sorcery_disjoin_bg', where='subjects';
   520    526   								gain=0.5, stop = {whence=1,secs=-1.5}
   521    527   							};
   522    528   							[1.00] = {sound='sorcery_powerdown', where='caster'};
   523    529   						};
   524    530   					}
   525    531   				end
   526    532   			};
   527    533   			diamond = {
   528    534   				name = 'Mundanity';
   529    535   				desc = 'Strip away the effects of all active potions and spells in your immediate vicinity, leaving adversaries without their magicks to enhance and protect them, and allies free of any curses they may be hobbled by -- and, of course, vice versa';
          536  +				sound = 'sorcery_disjoin';
   530    537   				cast = function(ctx)
   531    538   					local where = ctx.caster:get_pos()
   532    539   					local what = minetest.get_objects_inside_radius(where, 3 + (2*ctx.stats.power))
   533    540   					local who = {}
   534    541   					local pfac = math.min(1, ctx.stats.power/8)
   535    542   					for _, w in pairs(what) do
   536    543   						if w:is_player() and w ~= ctx.caster then
................................................................................
   623    630   						};
   624    631   					}
   625    632   				end;
   626    633   				frame = {
   627    634   					iridium = {
   628    635   						name = 'Spellshatter';
   629    636   						desc = 'Blast out a tidal wave of anti-magic that will nullify active spells, but also disenchant or destroy all magical items in range of its violently mundane grip';
          637  +						sound = 'sorcery_disjoin';
   630    638   						cast = function(ctx)
   631    639   							local where = ctx.caster:get_pos()
   632    640   							local radius = 3 + (2*ctx.stats.power)
   633    641   							local what = minetest.get_objects_inside_radius(where, radius)
   634    642   							local who = {}
   635    643   							local pfac = math.min(1, ctx.stats.power/8)
   636    644   							for _, w in pairs(what) do
................................................................................
   685    693   											minsize = 0.7, maxsize = 2;
   686    694   											animation = {
   687    695   												type = 'vertical_frames', length = (21/6) + 0.1;
   688    696   												aspect_w = 16, aspect_h = 16;
   689    697   											}
   690    698   										}
   691    699   									end;
          700  +								};
          701  +								sounds = {
          702  +									[{whence=0,secs=0.8}] = {
          703  +										sound='sorcery_disjoin_bg', where=where;
          704  +										gain=0.5, stop = {whence=1,secs=-0.6}
          705  +									};
   692    706   								};
   693    707   								intervals = {
   694    708   									{period = 0.1, after = 0.15, fn = function(c)
   695    709   										for i = 1,80 do
   696    710   											local life = 0.2 + math.random() * 2
   697    711   											local dir = vector.new(math.random()-0.5,0,math.random()-0.5):normalize()
   698    712   											local pos = epicenter + (dir * (math.random()*radius))
................................................................................
   709    723   												}
   710    724   											}
   711    725   										end
   712    726   										if next(wreck) then
   713    727   											local k,p = sorcery.lib.tbl.pick(wreck)
   714    728   
   715    729   											minetest.add_particle {
   716         -												texture = sorcery.lib.image('sorcery_sparking.png'):glow(sorcery.lib.color(255,0,0)):render();
          730  +												texture = L.image('sorcery_sparking.png'):glow(L.color(0,255,0)):render();
   717    731   												pos = vector.offset(p,math.random(),math.random(),math.random());
   718    732   												expirationtime = 1;
   719    733   												size = 5 + math.random() * 4;
   720    734   												glow = 14;
   721    735   												animation = {
   722    736   													type = 'vertical_frames', length = 0.3;
   723    737   													aspect_w = 64, aspect_h = 64;
   724    738   												}
   725    739   											}
   726    740   											minetest.add_particle {
   727         -												texture = sorcery.lib.image('sorcery_crackle.png'):glow(sorcery.lib.color(255,0,0)):render();
          741  +												texture = L.image('sorcery_crackle.png'):glow(L.color(0,255,0)):render();
   728    742   												pos = vector.offset(p,math.random(),math.random(),math.random());
   729    743   												expirationtime = 1;
   730    744   												size = 4 + math.random() * 6;
   731    745   												glow = 14;
   732    746   												animation = {
   733         -													type = 'vertical_frames', length = 0.6;
          747  +													type = 'vertical_frames', length = 1.1;
   734    748   													aspect_w = 64, aspect_h = 64;
   735    749   												}
   736    750   											}
          751  +											if math.random(1,7) == 1 then
          752  +												minetest.sound_play('sorcery_' .. (math.random(1,2)==1 and 'rip' or 'crunch'), {
          753  +													pos = p;
          754  +													gain = math.random(5,13)*0.1;
          755  +												}, true)
          756  +												minetest.after(0.2, function() minetest.remove_node(p) end)
          757  +												sorcery.vfx.show {
          758  +													amount = 120, time = 0.3;
          759  +													kind = 'flicker', color = L.color(80,255,10);--(255,12,0);
          760  +													pos = p, radius = 0.4;
          761  +													velrange = 1, accrange = vector.new(0.0,0.2,0.0);
          762  +													minsize = 5, maxsize = 20;
          763  +													life = 0.6, varylife = 0.1;
          764  +												}
          765  +												sorcery.vfx.show {
          766  +													amount = 80, time = 0.2;
          767  +													minsize = 0.1, maxsize = 0.8;
          768  +													pos = p, radius = 0.6;
          769  +													node = minetest.get_node(p);
          770  +													vel = vector.new(0,7,0);
          771  +													velrange = vector.new(2, 4, 2);
          772  +													acc = vector.new(0,-9,0);
          773  +													life = 3, varylife = 0.4;
          774  +												}
          775  +												-- minetest.add_particlespawner {
          776  +												-- 	amount = 60, time = 0.2;
          777  +												-- 	texture = L.image('sorcery_flicker.png'):glow():render();
          778  +												-- 	minpos = vector.offset(p, -0.5, -0.5, -0.5);
          779  +												-- 	maxpos = vector.offset(p,  0.5,  0.5,  0.5);
          780  +												-- 	minacc = vector.new(0.0, -0.2, 0.0);
          781  +												-- 	maxacc = vector.new(0.0,  0.2, 0.0);
          782  +												-- 	minvel = vector.new(-1,-1,-1);
          783  +												-- 	maxvel = vector.new(1,1,1);
          784  +												-- 	minsize = 0.5, maxsize = 4;
          785  +												-- 	minexptime = 0.6, maxexptime = 0.7;
          786  +												-- 	animation = {
          787  +												-- 		type = 'vertical_frames';
          788  +												-- 		aspect_w = 16, aspect_h = 16;
          789  +												-- 		length = 0.8;
          790  +												-- 	}
          791  +												-- }
          792  +												table.remove(wreck,k)
          793  +											end
   737    794   										end
   738    795   									end};
   739    796   								};
   740    797   							}
   741    798   						end;
   742    799   					};
   743    800   				};
................................................................................
   744    801   			};
   745    802   		}
   746    803   	};
   747    804   	repulse = {
   748    805   		name = 'Repulse';
   749    806   		tone = {0,180,235};
   750    807   		minpower = 1;
   751         -		rarity = 5;
          808  +		rarity = 7;
   752    809   		amulets = {
   753    810   			amethyst = {
   754    811   				name = 'Hurling';
   755    812   				desc = 'Wielding this amulet, a mere flick of your fingers will lift any target of your choice bodily into the air and press upon them with tremendous repulsive force, throwing them like a hapless ragdoll out of your path';
   756    813   				cast = function(ctx)
   757    814   					if not (ctx.target and ctx.target.type == 'object') then return false end
   758    815   					local tgt = ctx.target.ref
   759    816   					local line = vector.subtract(ctx.caster:get_pos(), tgt:get_pos())
   760    817   					-- direction vector from target to caster
   761    818   					local dir,mag = sorcery.lib.math.vsep(line)
   762    819   					if mag > 6 then return false end -- no cheating!
   763    820   					local force = 20 + (ctx.stats.power * 2.5)
   764         -					minetest.sound_play('sorcery_hurl',{pos=tgt:get_pos()},true)
   765         -					local immortal = tgt:get_luaentity():get_armor_groups().immortal or 0
          821  +					minetest.sound_play('sorcery_slide',{pos=tgt:get_pos()},true)
          822  +					local immortal = 0
          823  +					-- if tgt and tgt.get_armor_groups then
          824  +						immortal = tgt:get_armor_groups().immortal or 0
          825  +					-- end
   766    826   					if minetest.is_player(tgt) or immortal == 0 then
   767    827   						tgt:punch(ctx.caster, 1, {
   768    828   							full_punch_interval = 1;
   769    829   							damage_groups = { fleshy = force / 10 };
   770    830   						})
   771    831   					end
   772    832   					sparktrail(nil,tgt,sorcery.lib.color(101,226,255))
................................................................................
   798    858   							end;
   799    859   							[{whence=0, secs=1}] = function(s)
   800    860   								s.affect {
   801    861   									duration = power * 0.50;
   802    862   									raise = 0.5;
   803    863   									-- fall = (power * 0.25) * 0.3;
   804    864   									impacts = {
   805         -										gravity = 0.1;
          865  +										gravity = 0.2;
   806    866   									};
   807    867   								}
   808    868   							end;
   809    869   						};
   810    870   						intervals = {
   811    871   							{period = 0.2, after = {whence=0, secs=2}; fn = function(c)
   812    872   							-- return gravity to normal once they touch down
................................................................................
   864    924   								for _,sub in pairs(s.subjects) do
   865    925   									sub.player:add_velocity{y=-power*2;x=0,z=0}
   866    926   								end
   867    927   							end or nil;
   868    928   						};
   869    929   						sounds = {
   870    930   							[0.3] = {
   871         -								sound = 'sorcery_hurl';
          931  +								sound = 'sorcery_slide';
   872    932   								where = 'subjects';
   873    933   								ephemeral = true;
   874    934   							};
   875    935   							[1] = (ctx.amulet.frame == 'cobalt') and {
   876    936   								sound = 'sorcery_hurl';
   877    937   								where = 'subjects';
   878    938   								ephemeral = true;
................................................................................
   904    964   				desc = 'Unleash a tidal wave of force in every direction, blasting friends and foes alike away from you with enough violence to sprain and fracture bone';
   905    965   			};
   906    966   		};
   907    967   	};
   908    968   	obliterate = {
   909    969   		name = 'Obliterate';
   910    970   		tone = {255,0,10};
   911         -		minpower = 5;
   912         -		rarity = 30;
          971  +		minpower = 4;
          972  +		rarity = 10;
   913    973   		amulets = {
   914    974   			amethyst = {
   915    975   				name = 'Sapping';
   916    976   				desc = 'Punch a hole in enemy fortifications big enough to slip through but small enough to avoid immediate attention';
   917    977   			};
   918    978   			ruby = {
   919    979   				name = 'Shattering';
................................................................................
   963   1023   				};
   964   1024   			};
   965   1025   		};
   966   1026   	};
   967   1027   	excavate = {
   968   1028   		name = 'Excavate';
   969   1029   		tone = {0,68,235};
   970         -		minpower = 3;
   971         -		rarity = 17;
         1030  +		minpower = 2;
         1031  +		rarity = 9;
   972   1032   		amulets = {
   973   1033   			luxite = {
   974   1034   				name = 'Stonestride';
   975   1035   				desc = 'Rock walls will open up before you when you brandish this amulet before them, closing up again behind you without leaving a trace of your passage';
   976   1036   			};
   977   1037   			sapphire = {
   978   1038   				name = 'Tunnelling';
................................................................................
  1091   1151   				desc = 'Cut a wide shaft up into the ceiling of a cavern';
  1092   1152   			};
  1093   1153   		};
  1094   1154   	};
  1095   1155   	genesis = {
  1096   1156   		name = 'Genesis';
  1097   1157   		tone = {235,0,175};
  1098         -		minpower = 5;
  1099         -		rarity = 23;
         1158  +		minpower = 3;
         1159  +		rarity = 12;
  1100   1160   		amulets = {
  1101   1161   			amethyst = {
  1102   1162   				name = 'Shelter';
  1103   1163   				desc = 'Pour the power of this amulet into the soil or sand and out will grow a warm and well-lit place of shelter, no matter how far you may be from civilization.';
  1104   1164   				cast = function(ctx)
  1105   1165   					local ctr = ctx.caster:get_pos()
  1106   1166   					local dim = { rmax = 2 + 6 * (ctx.stats.power*0.1) }
................................................................................
  1710   1770   				};
  1711   1771   			};
  1712   1772   		};
  1713   1773   	};
  1714   1774   	dominate = {
  1715   1775   		name = 'Dominate';
  1716   1776   		tone = {235,0,228};
  1717         -		minpower = 4;
  1718         -		rarity = 13;
         1777  +		minpower = 3;
         1778  +		rarity = 12;
  1719   1779   		amulets = {
  1720   1780   			amethyst = {
  1721   1781   				name = 'Suffocation';
  1722   1782   				desc = 'Wrap this spell tightly around your victim\'s throat, cutting off their oxygen until you release them.';
  1723   1783   			};
  1724   1784   			emerald = {
  1725   1785   				name = 'Caging';