sorcery  Diff

Differences From Artifact [829a9ad70b]:

To Artifact [27c07e8c34]:


   413    413   		tone = {159,235,0};
   414    414   		minpower = 4;
   415    415   		rarity = 34;
   416    416   		amulets = {
   417    417   			sapphire = {
   418    418   				name = 'Unsealing';
   419    419   				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';
          420  +				cast = function(ctx)
          421  +					if ctx.target.type ~= 'node' then return false end
          422  +					local r = 2 + math.floor(ctx.stats.power / 2)
          423  +					local cast = false
          424  +					for x = -r,r do
          425  +					for y = -r,r do
          426  +					for z = -r,r do
          427  +						if x^2 + y^2 + z^2 <= r^2 then
          428  +							local pos = vector.offset(ctx.target.under, x,y,z)
          429  +							local abv = vector.offset(ctx.target.above, x,y,z)
          430  +							local meta = minetest.get_meta(pos)
          431  +							if meta:contains('sorcery_seal_mode') then
          432  +								meta:set_string('sorcery_seal_mode', '')
          433  +								meta:set_string('sorcery_wand_key', '')
          434  +								meta:set_string('owner', '')
          435  +								sorcery.vfx.enchantment_sparkle({under=pos,above=abv}, sorcery.lib.color(12,38,255))
          436  +								cast = true
          437  +							end
          438  +						end
          439  +					end end end
          440  +					if cast then
          441  +						minetest.sound_play('sorcery_disjoin',{object=target},true)
          442  +					end
          443  +					return cast
          444  +				end;
   420    445   			};
   421    446   			amethyst = {
   422    447   				name = 'Purging';
   423    448   				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';
   424    449   				cast = function(ctx) purge(ctx.caster) end;
   425    450   			};
   426    451   			emerald = {
................................................................................
   456    481   						subjects = {{player=ctx.caster}};
   457    482   						disjunction = true, range = 4 + ctx.stats.power;
   458    483   						duration = 10 + ctx.stats.power * 3;
   459    484   						timeline = {
   460    485   							[0] = function(s,_,tl)
   461    486   								local ttns = 0.8
   462    487   								local vel = s.range / ttns
   463         -								s.visual_caster {
          488  +								s.visual_subjects {
   464    489   									amount = 300, time = ttns, glow = 14;
   465    490   									texture = sorcery.lib.image('sorcery_sputter.png'):glow(sorcery.lib.color(160,255,80)):render();
   466    491   									minpos = { x = -0.0, y = h*0.5,z = -0.0 };
   467    492   									maxpos = { x =  0.0, y = h*0.5,z =  0.0 };
   468    493   									minvel = { x = -vel, y = -0.0, z = -vel };
   469    494   									maxvel = { x =  vel, y =  0.0, z =  vel };
   470    495   									minacc = { x = -0.2, y = -0.0, z = -0.2 };
................................................................................
   663    688   												aspect_w = 16, aspect_h = 16;
   664    689   											}
   665    690   										}
   666    691   									end;
   667    692   								};
   668    693   								intervals = {
   669    694   									{period = 0.1, after = 0.15, fn = function(c)
   670         -										print('interval running')
   671    695   										for i = 1,80 do
   672    696   											local life = 0.2 + math.random() * 2
   673    697   											local dir = vector.new(math.random()-0.5,0,math.random()-0.5):normalize()
   674    698   											local pos = epicenter + (dir * (math.random()*radius))
   675         -											print('setting particle at',pos)
   676    699   											minetest.add_particle {
   677    700   												texture = tex;
   678    701   												pos = pos;
   679    702   												expirationtime = life;
   680    703   												velocity = {x = 0, y = math.random() * 0.3 + 0.1, z = 0};
   681    704   												size = 0.4 + math.random() * 3;
   682    705   												glow = 14;
................................................................................
  1071   1094   	};
  1072   1095   	genesis = {
  1073   1096   		name = 'Genesis';
  1074   1097   		tone = {235,0,175};
  1075   1098   		minpower = 5;
  1076   1099   		rarity = 23;
  1077   1100   		amulets = {
         1101  +			amethyst = {
         1102  +				name = 'Shelter';
         1103  +				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  +				cast = function(ctx)
         1105  +					local ctr = ctx.caster:get_pos()
         1106  +					local dim = { rmax = 2 + 6 * (ctx.stats.power*0.1) }
         1107  +					dim.rx = math.random(math.max(3, dim.rmax - 4), dim.rmax)
         1108  +					dim.rz = math.random(math.max(3, dim.rmax - 4), dim.rmax)
         1109  +					dim.y = math.random(4, 7)
         1110  +					for i = 1,10 do
         1111  +						if sorcery.lib.node.is_air(ctr) then
         1112  +							ctr = ctr:offset(0, -1, 0)
         1113  +						else break end
         1114  +					end
         1115  +					local soilp = function(pos)
         1116  +						local name = minetest.get_node(pos).name
         1117  +						return minetest.get_item_group(name, 'soil') ~= 0 or
         1118  +						       minetest.get_item_group(name, 'sand') ~= 0
         1119  +					end
         1120  +					if not soilp(ctr) then return false end
         1121  +					-- scan map to determine maximum dimensions
         1122  +					for x = -dim.rx, dim.rx do
         1123  +						for z = -dim.rz, dim.rz do
         1124  +							local pos = ctr:offset(x,0,z)
         1125  +							if not soilp(pos) then
         1126  +								dim.rx = math.min(dim.rx, math.abs(x))
         1127  +								dim.rz = math.min(dim.rz, math.abs(z))
         1128  +							end
         1129  +							for y = 1, dim.y do
         1130  +								if not sorcery.lib.node.is_air(pos:offset(0,y,0)) then
         1131  +									dim.y = math.min(dim.y, y)
         1132  +								end
         1133  +							end
         1134  +						end
         1135  +					end
         1136  +					-- bail if not enough room
         1137  +					if dim.rx < 2 or dim.rz < 2 or dim.y < 2 then
         1138  +						return false
         1139  +					end
         1140  +					local materials = {
         1141  +						walls = {};
         1142  +						corners = {};
         1143  +						floor = {};
         1144  +						roof = {};
         1145  +						door = {};
         1146  +						door_lock = {};
         1147  +						lamp_floor = {};
         1148  +						lamp_ceil = {};
         1149  +						lamp_wall = {};
         1150  +						lamp_ext = {};
         1151  +					}
         1152  +					local try = function(ary, ...)
         1153  +						local a = {}
         1154  +						for _, item in pairs{...} do
         1155  +							if item and minetest.registered_items[item] then
         1156  +								table.insert(a, item)
         1157  +							end
         1158  +						end
         1159  +						if next(a) then
         1160  +							table.insert(ary, a)
         1161  +							return true
         1162  +						end
         1163  +						return false
         1164  +					end
         1165  +					for name,tree in pairs(sorcery.data.trees) do
         1166  +						try(materials.corners, tree.node)
         1167  +						try(materials.walls, tree.plank)
         1168  +						try(materials.floor, tree.plank)
         1169  +					end
         1170  +					try(materials.roof, 'farming:straw')
         1171  +					try(materials.floor, 'farming:straw')
         1172  +					try(materials.roof, 'default:brick')
         1173  +					try(materials.roof, 'default:desert_stonebrick')
         1174  +					try(materials.walls, 'default:brick')       try(materials.corners, 'default:brick')
         1175  +					try(materials.walls, 'default:stonebrick') try(materials.corners, 'default:stonebrick')
         1176  +					try(materials.walls, 'default:cobble', 'default:mossycobble')
         1177  +					try(materials.walls, 'default:desert_cobble')
         1178  +					try(materials.walls, 'default:desert_stonebrick')
         1179  +
         1180  +					try(materials.corners, 'default:desert_stonebrick')
         1181  +					try(materials.corners, 'default:desert_stonebrick')
         1182  +					try(materials.corners, 'default:desert_stone_block')
         1183  +
         1184  +					try(materials.walls, 'default:sandstone')
         1185  +					try(materials.walls, 'default:sandstonebrick')
         1186  +					try(materials.walls, 'default:desert_sandstone')
         1187  +					try(materials.walls, 'default:desert_sandstone_brick')
         1188  +					try(materials.walls, 'default:silver_sandstone')
         1189  +					try(materials.walls, 'default:silver_sandstone_brick')
         1190  +
         1191  +					try(materials.walls, 'default:sandstone', 'default:silver_sandstone', 'default:desert_sandstone')
         1192  +					try(materials.walls, 'default:sandstonebrick', 'default:silver_sandstone_brick', 'default:desert_sandstone_brick')
         1193  +					try(materials.roof, 'default:sandstonebrick', 'default:silver_sandstone_brick', 'default:desert_sandstone_brick')
         1194  +
         1195  +					try(materials.corners, 'default:sandstonebrick')
         1196  +					try(materials.corners, 'default:desert_sandstone_brick')
         1197  +					try(materials.corners, 'default:silver_sandstone_brick')
         1198  +					if math.random(1,10) == 7 then
         1199  +					try(materials.corners, 'default:obsidianbrick')
         1200  +					end
         1201  +
         1202  +					try(materials.lamp_wall, 'default:torch_wall')
         1203  +					try(materials.lamp_wall, 'morelights_modern:wall_lamp')
         1204  +
         1205  +					try(materials.lamp_ext, 'default:torch')
         1206  +					try(materials.lamp_ext, 'morelights_modern:wall_lamp')
         1207  +					try(materials.lamp_ext, 'morelights_modern:lantern_f')
         1208  +
         1209  +					for _, l in pairs {
         1210  +						'default:meselamp';
         1211  +						'morelights_modern:barlight_s';
         1212  +						'morelights_modern:ceilinglight';
         1213  +						'morelights_modern:canlight_d';
         1214  +						'morelights_modern:canlight_l';
         1215  +						'morelights_vintage:hangingbulb';
         1216  +						'morelights_vintage:chandelier';
         1217  +					} do try(materials.lamp_ceil, l) end
         1218  +
         1219  +					for _, l in pairs {
         1220  +						'default:meselamp';
         1221  +						'morelights_extras:f_block',
         1222  +						'morelights_extras:sandstone_block',
         1223  +						'morelights_extras:stone_block',
         1224  +						'morelights_modern:block',
         1225  +						'morelights_vintage:block',
         1226  +					} do try(materials.lamp_floor, l) end
         1227  +
         1228  +					for _, d in pairs {
         1229  +						'doors:door_wood';
         1230  +						'doors:woodglass_door';
         1231  +						'doors:slide_door';
         1232  +						'doors:japanese_door';
         1233  +						'doors:screen_door';
         1234  +						'doors:door_glass';
         1235  +					} do try(materials.door, d) end
         1236  +
         1237  +					for _, d in pairs {
         1238  +						'doors:door_steel';
         1239  +						'xpanes:door_steel_bar';
         1240  +					} do try(materials.door_lock, d) end
         1241  +
         1242  +
         1243  +					for k,v in pairs(materials) do
         1244  +						if next(v) then
         1245  +							materials[k] = select(2, sorcery.lib.tbl.pick(v))
         1246  +						end
         1247  +					end
         1248  +					local timeline = {}
         1249  +					local per = 0.05
         1250  +					local i = 0
         1251  +					local spark = function(s,where)
         1252  +						s.visual {
         1253  +							amount = 30;
         1254  +							time = 0.2;
         1255  +							minpos = where:offset(-0.5,  0.0, -0.5);
         1256  +							maxpos = where:offset( 0.5,  1.0,  0.5);
         1257  +							minvel = vector.new(-0.4, -0.2, -0.4);
         1258  +							maxvel = vector.new( 0.4,  0.2,  0.4);
         1259  +							minacc = vector.new( 0, 0.2, 0);
         1260  +							maxacc = vector.new( 0, 0.6, 0);
         1261  +							minexptime = 0.2, maxexptime = 2.0;
         1262  +							minsize = 0.3, maxsize = 2;
         1263  +							texture = sorcery.vfx.glowspark(sorcery.lib.color(255,12,89)):render();
         1264  +							glow = minetest.LIGHT_MAX;
         1265  +							animation = {
         1266  +								type = 'vertical_frames', length = 3.1;
         1267  +								aspect_w = 16, aspect_h = 16;
         1268  +							}
         1269  +						}
         1270  +					end
         1271  +					local setplane = function(y, mcat)
         1272  +						for x = -dim.rx, dim.rx do
         1273  +							for z = -dim.rz, dim.rz do
         1274  +								timeline[{whence=0, secs=per*i}] = function(s)
         1275  +									local node = select(2, sorcery.lib.tbl.pick(mcat))
         1276  +									local p = ctr:offset(x,y,z)
         1277  +									minetest.set_node(p, {name=node})
         1278  +									spark(s,p)
         1279  +								end
         1280  +							end
         1281  +							i = i + 1
         1282  +						end
         1283  +					end
         1284  +					setplane(0, materials.floor)
         1285  +					local mpick=function(t)
         1286  +						return select(2, sorcery.lib.tbl.pick(materials[t]))
         1287  +					end
         1288  +					local t_supports = per*i
         1289  +					for y = 1, dim.y-1 do
         1290  +						local mx,mz = dim.rx, dim.rz
         1291  +						timeline[{whence=0, secs=per*i}] = function(s)
         1292  +							for _,where in pairs {
         1293  +								ctr:offset( mx,y, mz);
         1294  +								ctr:offset(-mx,y, mz);
         1295  +								ctr:offset(-mx,y,-mz);
         1296  +								ctr:offset( mx,y,-mz);
         1297  +							} do
         1298  +								minetest.set_node(where, { name = mpick'corners' })
         1299  +							end
         1300  +						end
         1301  +						i=i+1
         1302  +					end
         1303  +					local t_roof = per*i
         1304  +					setplane(dim.y, materials.roof)
         1305  +					timeline[{whence=0,secs=per*i - 0.4}] = function(s)
         1306  +						s.visual {
         1307  +							time = 30, amount = 2500;
         1308  +							minpos = ctr:offset(-dim.rx,dim.y - 0.5,-dim.rz);
         1309  +							maxpos = ctr:offset( dim.rx,dim.y + 0.5, dim.rz);
         1310  +							minacc = vector.new(0,-0.5,0);
         1311  +							maxacc = vector.new(0, 0.3,0);
         1312  +							texture = sorcery.lib.image('sorcery_sputter.png'):glow(255,17,86):render();
         1313  +							glow = minetest.LIGHT_MAX;
         1314  +							minexptime = 2.4, maxexptime = 8;
         1315  +							minsize = 0.5, maxsize = 3;
         1316  +							animation = {
         1317  +								type = 'vertical_frames', length = 1.1;
         1318  +								aspect_w = 16, aspect_h = 16;
         1319  +							};
         1320  +						}
         1321  +					end
         1322  +					local t_walls = per*i
         1323  +					for y = dim.y-1,1,-1 do
         1324  +						timeline[{whence=0, secs=per*i}] = function(s)
         1325  +							local xe, ze = dim.rx-1, dim.rz-1
         1326  +							for x=-xe,xe do
         1327  +								minetest.set_node(ctr:offset(x,y, dim.rz), {name=mpick'walls'})
         1328  +								minetest.set_node(ctr:offset(x,y,-dim.rz), {name=mpick'walls'})
         1329  +							end
         1330  +							for z=-ze,ze do
         1331  +								minetest.set_node(ctr:offset(-dim.rx,y,z), {name=mpick'walls'})
         1332  +								minetest.set_node(ctr:offset( dim.rx,y,z), {name=mpick'walls'})
         1333  +							end
         1334  +						end
         1335  +						i=i+1
         1336  +					end
         1337  +					local t_built = per*i
         1338  +					local lighting = math.random(1,2)
         1339  +					if lighting == 1 then
         1340  +						local lh = math.ceil(dim.y * .6)
         1341  +						local wlamps = {
         1342  +							ctr:offset(  dim.rx - 1 , lh,0);
         1343  +							ctr:offset(-(dim.rx - 1), lh,0);
         1344  +							ctr:offset(0, lh,   dim.rz - 1);
         1345  +							ctr:offset(0, lh, -(dim.rz - 1));
         1346  +						}
         1347  +						sorcery.lib.tbl.shuffle(wlamps)
         1348  +						for _, where in pairs(wlamps) do
         1349  +							i = i + 10
         1350  +							timeline[{whence=0, secs = per*i}] = function(s)
         1351  +								spark(s,where)
         1352  +								local node = select(2,sorcery.lib.tbl.pick(materials.lamp_wall))
         1353  +								minetest.sound_play('sorcery_put',{pos=where,gain=0.8},true)
         1354  +								minetest.set_node(where, {
         1355  +									name=node;
         1356  +									param2=minetest.dir_to_wallmounted(vector.normalize(ctr:offset(0,lh,0) - where)*-1);
         1357  +								})
         1358  +							end
         1359  +						end i=i+1
         1360  +					elseif lighting == 2 then
         1361  +						local which = math.random(1,3)
         1362  +						if which == 1 or which == 2 then
         1363  +							i = i + 20
         1364  +							timeline[{whence=0, secs = per*i}] = function(s)
         1365  +								local where = ctr:offset(0,dim.y,0)
         1366  +								spark(s,where)
         1367  +								minetest.sound_play('sorcery_put',{pos=where,gain=0.7},true)
         1368  +								minetest.item_place(ItemStack(mpick'lamp_ceil'), nil, {
         1369  +									type = "node";
         1370  +									under = where;
         1371  +									above = where:offset(0,-1,0);
         1372  +								})
         1373  +							end
         1374  +						end
         1375  +						if which == 1 or which == 3 then
         1376  +							i = i + 20
         1377  +							local flamps = {
         1378  +								ctr:offset( (dim.rx - 1), 0,  (dim.rz - 1));
         1379  +								ctr:offset(-(dim.rx - 1), 0,  (dim.rz - 1));
         1380  +								ctr:offset(-(dim.rx - 1), 0, -(dim.rz - 1));
         1381  +								ctr:offset( (dim.rx - 1), 0, -(dim.rz - 1));
         1382  +							}
         1383  +							sorcery.lib.tbl.shuffle(flamps)
         1384  +							for _, v in pairs(flamps) do
         1385  +								timeline[{whence=0, secs = per*i}] = function(s)
         1386  +									local node = select(2,sorcery.lib.tbl.pick(materials.lamp_floor))
         1387  +									spark(s,v)
         1388  +									minetest.sound_play('sorcery_put',{pos=v,gain=0.7},true)
         1389  +									minetest.set_node(v, {name = node})
         1390  +								end
         1391  +								i = i + 7
         1392  +							end
         1393  +						end
         1394  +					end
         1395  +					-- install door
         1396  +					local doorside = ({
         1397  +						vector.new( dim.rx,1,0);
         1398  +						vector.new(0,1, dim.rz);
         1399  +						vector.new(-dim.rx,1,0);
         1400  +						vector.new(0,1,-dim.rz);
         1401  +					})[math.random(1,4)]
         1402  +					local doorpos
         1403  +					if math.random(1,3) == 1 then
         1404  +						if doorside.z ~= 0 then
         1405  +							doorside.x = doorside.x + math.random(-(dim.rx-1), dim.rx-1)
         1406  +						elseif doorside.x ~= 0 then
         1407  +							doorside.z = doorside.z + math.random(-(dim.rz-1), dim.rz-1)
         1408  +						end
         1409  +					end
         1410  +					doorpos = ctr + doorside
         1411  +					local door = mpick'door'
         1412  +					i=i+5
         1413  +					timeline[{whence=0,secs=per*i}] = function(s)
         1414  +						minetest.remove_node(doorpos)
         1415  +						minetest.remove_node(doorpos:offset(0,1,0))
         1416  +						spark(s, doorpos)
         1417  +						spark(s, doorpos:offset(0,1,0))
         1418  +						minetest.sound_play('sorcery_crunch', {pos = doorpos, gain = 0.9}, true)
         1419  +						-- this is buggy af and needs to be replaced with a proper impl
         1420  +-- 						local d = ItemStack(door)
         1421  +-- 						d:get_definition().on_place(d, s.caster, {
         1422  +-- 							type = 'node';
         1423  +-- 							above = doorpos;
         1424  +-- 							under = doorpos:offset(0,-1,0);
         1425  +-- 						})
         1426  +					end
         1427  +
         1428  +					sorcery.spell.cast {
         1429  +						name = 'sorcery:shelter';
         1430  +						groups = {'genesis','construct'};
         1431  +						caster = ctx.caster;
         1432  +						anchor = ctr;
         1433  +						radius = math.max(dim.rz, dim.rx);
         1434  +						duration = per * i;
         1435  +						timeline = timeline;
         1436  +						sounds = {
         1437  +							[{whence=0,secs=t_supports}] = {
         1438  +								sound = 'sorcery_slide';
         1439  +								where = ctr:offset(0,dim.y,0);
         1440  +								ephemeral = true, pitch = 0.7;
         1441  +							};
         1442  +							[{whence=0,secs=t_roof}] = {
         1443  +								sound = 'sorcery_slide';
         1444  +								where = ctr:offset(0,dim.y,0);
         1445  +								ephemeral = true;
         1446  +							};
         1447  +						};
         1448  +					}
         1449  +				end;
         1450  +			};
  1078   1451   			mese = {
  1079   1452   				mingrade = 4;
  1080   1453   				name = 'Duplication';
  1081         -				desc = 'Bring an exact twin of any object or item into existence, no matter how common or rare it might be';
         1454  +				desc = 'Bring an exact twin of any object or item into existence, whether it be a thing quotidian or an impossible rarity';
  1082   1455   				cast = function(ctx)
  1083   1456   					local color = sorcery.lib.color(255,61,205)
  1084   1457   					local dup, sndpos, anchor, sbj, ty
  1085   1458   					if ctx.target.type == 'object' and ctx.target.ref:get_luaentity().name == '__builtin:item' then
  1086   1459   						sorcery.vfx.imbue(color, ctx.target.ref) -- causes graphics card problems???
  1087   1460   						sndpos = 'subjects'
  1088   1461   						sbj = {{player = ctx.target.ref}}
................................................................................
  1132   1505   					end
  1133   1506   					if minetest.get_item_group(ty,'do_not_duplicate') ~= 0 then
  1134   1507   						return true
  1135   1508   					end
  1136   1509   
  1137   1510   					sorcery.spell.cast {
  1138   1511   						name = 'sorcery:duplicate';
         1512  +						groups = {'genesis'};
  1139   1513   						caster = ctx.caster;
  1140   1514   						duration = math.random(10,20) * ((10 - ctx.stats.power)*0.1);
  1141   1515   						anchor = anchor;
  1142   1516   						timeline = {
  1143   1517   							[{whence=0, secs=1}] = function(s,te,tl)
  1144   1518   								local mag = sbj and 0.5 or 0.7
  1145   1519   								local pv = sbj and vector.new(0,0,0) or ctx.target.under