sorcery  entities.lua at tip

File entities.lua from the latest check-in


local u = sorcery.lib
local flamebolt_pack, flamebolt_unpack = u.marshal.transcoder {
	age = u.marshal.t.u32;
	lastemit = u.marshal.t.u32;
}

minetest.register_entity('sorcery:spell_projectile_flamebolt',{
	initial_properties = {
		visual = "sprite";
        use_texture_alpha = 'blend';
		textures = {'sorcery_fireball.png'};
		visual_size = { x = 2, y = 2, z = 2 };
		physical = true;
		collide_with_objects = true;
		pointable = false;
		glow = 14;
		static_save = false;
		shaded = false;
	};
	on_activate = function(self)
		self.object:set_armor_groups{immortal = 1}
	end;
	on_step = function(self,dtime,collision)
		local pos = self.object:get_pos()
		if not self._meta then
			self._meta = { age = 0; lastemit = 0; emitters = {} }
			goto emit
		end

		self._meta.age = self._meta.age + dtime
		if self._meta.age >= 6 then
			goto destroy
		elseif (self._meta.age - self._meta.lastemit) < 3 then
			goto collcheck
		end

		-- fireballs dissipate when entering antimagic fields
		do local probe = sorcery.spell.probe(self.object:get_pos())
		if probe.disjunction and not self._meta.ignore_disjunction then
			sorcery.vfx.cast_sparkle(nil,sorcery.lib.color(255,90,10),3,0.3,self.object:get_pos())
			goto destroy
		end end
		
		::emit:: do
			self._meta.lastemit = self._meta.age
			local spawn = function(num, life_min, life_max, size_min, size_max, gl, speed, img)
				table.insert(self._meta.emitters, minetest.add_particlespawner {
					amount = num;
					minexptime = life_min;
					maxexptime = life_max;
					minvel = vector.multiply({ x = -1; y = -1; z = -1; }, speed);
					maxvel = vector.multiply({ x =  1; y =  1; z =  1; }, speed);
					minacc = vector.multiply({ x =  0; y = -1; z =  0; }, speed);
					maxacc = vector.multiply({ x =  0; y =  1; z =  0; }, speed);
					texture = img or u.image('sorcery_spark.png'):multiply(u.color(255,74,25):brighten(gl)):render();
					time = 3;
					glow = 14;
					minsize = size_min;
					maxsize = size_max;
					attached = self.object;
					animation = ((not img) and {
						type = "vertical_frames";
						aspect_w = 16;
						aspect_h = 16;
						length = life_max;
					}) or nil;
				})
			end
			--    #    life       size    glow speed
			spawn(50,   0.5,1,  10.0,15.0,  1.0,  1.0)
			spawn(80,   3.0,6,   5.0, 7.0,  1.7,  2.0)
			spawn(140,  1.0,7,   1.0, 6.0,  2.4,  3.0)
			spawn(250,  4.0,9,   0.3, 0.8,  3.0,  7.0)
			spawn(500,  10,20,   1.0, 1.8,  2.0,  0.2)
			spawn(500,  10,20,   0.5, 1.0,  3.0,  0.5)
		end

		::collcheck:: do
			-- if no collision then return end
			-- local nname = minetest.get_node(pos).name 
			-- if nname == 'air' or minetest.registered_nodes[nname].walkable ~= true then return
			-- elseif nname == 'ignore' then goto destroy end
			-- else fall through to explode
			if collision then -- since 5.3 only!!
				if collision.collides == false then return end
				if #collision.collisions > 0 then
					local col = collision.collisions[1]
					if col.node_pos then
						pos = col.node_pos
					elseif col.object then
						pos = col.object:get_pos()
					end
					-- fall through to explode
				else return end
			else return end
		end

		::explode:: do
			-- minetest.add_particle({
			-- 	pos = pos,
			-- 	velocity     = { x = 0, y = 0, z = 0 };
			-- 	acceleration = { x = 0, y = 0, z = 0 };
			-- 	expirationtime = 0.4,
			-- 	size = 50,
			-- 	collisiondetection = false,
			-- 	vertical = false,
			-- 	texture = "tnt_boom.png",
			-- 	glow = 14,
			-- })

			local boom = function(len,num,speed)
				-- minetest.add_particlespawner {
				-- 	amount = num;
				-- 	time = len;
				-- 	minpos = vector.subtract(pos, 1.2);
				-- 	maxpos = vector.add(pos, 1,2);
				-- 	minvel = vector.multiply({ x = -10; y = -10; z = -10; }, speed);
				-- 	maxvel = vector.multiply({ x =  10; y =  10; z =  10; }, speed);
				-- 	minacc = vector.multiply({ x =  -1; y =  -1; z =  -1; }, speed);
				-- 	maxacc = vector.multiply({ x =   1; y =   1; z =   1; }, speed);
				-- 	minexptime = 0.1;
				-- 	maxexptime = 0.3;
				-- 	minsize = 6;
				-- 	maxsize = 25;
				-- 	texture = 'tnt_smoke.png';
				-- }
			end
			boom(0.7, 140, 0.8)
			-- minetest.sound_play("tnt_explode", {pos = pos, gain = 1.5, max_hear_distance = 40}, true)
			tnt.boom(pos, {
				radius = self._blastradius;
			})
		end

		::destroy:: do
			if self._meta then for _,v in pairs(self._meta.emitters) do
				minetest.delete_particlespawner(v)
			end end
			self.object:remove()
		end
	end;
})