sorcery  forcefield.lua at [b96185e88b]

File forcefield.lua artifact 2ecc37ddb4 part of check-in b96185e88b


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;
	};
})