sorcery  Artifact [2ecc37ddb4]

Artifact 2ecc37ddb41a143ee68fdca739dc8ebfffe4746ee5750505c365294c75ab25bc:

  • File forcefield.lua — part of check-in [147592b8e9] at 2020-10-26 03:58:08 on branch trunk — add over-time spellcasting abstraction to enable metamagic and in particular disjunction, add more animations and sound effects, add excavation spell, possibly some others, forget when the last commit was, edit a bunch of magitech to make it subject to the disjunction mechanism (throw up a disjunction aura and waltz right through those force fields bby, wheee), also illumination spells, tweak runeforge and rune frequence to better the balance and also limit player frustration, move some math functions into their own library category, various tweaks and bugfixes, probably other shit i don't remember (user: lexi, size: 5483) [annotate] [blame] [check-ins using]

local constants = {
	cost_per_barrier = 0.1;
	-- 0.1 points of current will be required per second per
	-- unit of charge given to a barrier-block when ley-force
	-- of counterpraxic affinity is not available
}
local aimtbl = {
	[0] = {x =  0, y =  1, z =  0};
	[1] = {x =  0, y =  0, z =  1};
	[2] = {x =  0, y =  0, z = -1};
	[3] = {x =  1, y =  0, z =  0};
	[4] = {x = -1, y =  0, z =  0};
	[5] = {x =  0, y = -1, z =  0};
}
local pofstbl = {
	[0] = {x=0.5, y=0,   z=0.5};
	[1] = {x=0.5, y=0.5, z=0};
	[2] = {x=0.5, y=0.5, z=0};
	[3] = {x=0,   y=0.5, z=0.5};
	[4] = {x=0,   y=0.5, z=0.5};
	[5] = {x=0.5, y=0,   z=0.5};
}
local calc_cost = function(pos,time)
	local node = minetest.get_node(pos)
	local aim = aimtbl[math.floor(node.param2 / 4)]
	local tgts = {}
	for i=1,5 do
		local tpos = vector.add(pos, vector.multiply(aim,i))
		local n = minetest.get_node(tpos)
		if n.name == 'air' then tgts[#tgts + 1] = {tpos,0} else
			local f = minetest.get_item_group(n.name, 'sorcery_force_barrier')
			if f > 0 then
				tgts[#tgts + 1] = {tpos,f}
			else break end
		end
	end
	return {
		aim = aim;
		maxcost = #tgts * constants.cost_per_barrier * time;
		mincost = math.min(1,#tgts) * constants.cost_per_barrier * time;
		targets = tgts;
	}
end
for i=1,10 do
	minetest.register_node('sorcery:air_barrier_' .. tostring(i), {
		drawtype = 'glasslike';
		walkable = true;
		pointable = false;
		sunlight_propagates = true;
		paramtype = 'light';
		light_source = i;
		drop = {max_items = 0, items = {}};
		on_blast = function() end; -- not affected by explosions
		tiles = {'sorcery_transparent.png'};
		groups = {
			air = 1;
			sorcery_air = 1;
			sorcery_force_barrier = i;
		};
		-- _proto = {
		-- 	strength = i;
		-- };
		on_construct = function(pos)
			minetest.get_node_timer(pos):start(1)
		end;
		on_timer = function(pos,delta)
			local dec = 40*delta
			local node = minetest.get_node(pos)
			local newstr = math.ceil(10 * ((node.param2 - dec) / 0xFF))
			local newnode = 'sorcery:air_barrier_' .. tostring(newstr)
			if newstr <= 0 then
				minetest.remove_node(pos)
				return false
			else
				for _,c in pairs {{165,255,252}, {146,205,255}, {190,93,253}} do
					minetest.add_particlespawner {
						time = 1;
						amount = 15;
						minpos = vector.add(pos, -0.6);
						maxpos = vector.add(pos, 0.6);
						minvel = {x = 0, y = 0, z = 0};
						maxvel = {x = 0, y = 0, z = 0};
						minacc = {x = -0.1, y = -0.1, z = -0.1};
						maxacc = {x =  0.1, y =  0.1, z =  0.1};
						minexptime = 0.5;
						maxexptime = 1.0;
						minsize = 0.2;
						minsize = 0.7;
						texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(c)):render();
						glow = 14;
						animation = {
							length = 1.1;
							type = 'vertical_frames';
							aspect_h = 16, aspect_w = 16;
						};
					}
				end
				minetest.swap_node(pos, {
					name = newnode;
					param1 = node.param1;
					param2 = newstr;
				})
				return true
			end
		end;
	})
end
minetest.register_node('sorcery:emitter_barrier', {
	description = "Barrier Screen Emitter";
	paramtype2 = 'facedir';
	groups = {
		cracky = 2;
		sorcery_ley_device = 1;
		sorcery_magitech = 1;
	};
	tiles = {
		'sorcery_emitter_barrier_top.png';
		'sorcery_emitter_barrier_bottom.png';
		'sorcery_emitter_barrier_front.png^[transformR270';
		'sorcery_emitter_barrier_front.png^[transformFXR90';
		'sorcery_emitter_barrier_side.png';
		'sorcery_emitter_barrier_side.png';
	};
	on_construct = function(pos)
		minetest.get_node_timer(pos):start(1)
	end;
	on_timer = function(pos,delta)
		local orientation = math.floor(minetest.get_node(pos).param2 / 4)
		local costs = calc_cost(pos,delta)
		local probe = sorcery.spell.probe(pos)
		if probe.disjunction then return true end
		local l = sorcery.ley.netcaps(pos,delta)
		if l.self.powerdraw >= costs.mincost then
			local dist = l.self.powerdraw / (constants.cost_per_barrier * delta)
			for i=1,math.floor(dist) do
				local t = costs.targets[i]
				local str = math.min(0xFF,t[2] + 50*delta);
				local fprobe = sorcery.spell.probe(t[1])
				if not fprobe.disjunction then
					minetest.swap_node(t[1], {
						name = 'sorcery:air_barrier_' .. math.max(1, math.floor(10*(str/0xFF)));
						param2 = str;
					})
					minetest.get_node_timer(t[1]):start(1)
				end
			end

			local pn = vector.add(pos, vector.divide(costs.aim,2));
			local pp = vector.add(pn, pofstbl[orientation])
			pn = vector.subtract(pn,  pofstbl[orientation])
			
			minetest.add_particlespawner {
				time = 1;
				amount = 20 * dist;
				minpos = pn;
				maxpos = pp;
				minvel = costs.aim;
				maxvel = vector.multiply(costs.aim,2);
				minsize = 0.3;
				maxsize = 0.5;
				minexptime = dist*0.5;
				maxexptime = dist*0.5;
				texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(240,255,160)):render();
				glow = 14;
				animation = {
					length = dist + 0.1;
					type = 'vertical_frames';
					aspect_h = 16, aspect_w = 16;
				};
			}
			return true
		end
		return false
	end;
	after_place_node = function(pos, placer, stack, point)
		local vec = vector.subtract(point.under, pos)
		local n = minetest.get_node(pos)
		n.param2 = minetest.dir_to_facedir(vec)
		minetest.swap_node(pos,n)
	end;
	_sorcery = {
		ley = {
			mode='consume', affinity={'counterpraxic'},
			power = function(pos,time)
				local l = calc_cost(pos,time)
				return l.mincost, l.maxcost
			end;
		};
		on_leychange = function(pos)
			minetest.get_node_timer(pos):start(1)
		end;
	};
})