class "PsyAntennaPP" (effector)
function PsyAntennaPP:__init() super(1001,10000000)
	self.params							= effector_params();
end
function PsyAntennaPP:process(pp)
	pp:assign		(self.params);
    effector.process(self,pp);
    return          true;
end

class "PsyAntenna"
pa_phase={
	phIdle 								= 0,
	phStarting 							= 1,
	phWorking 							= 2,
	phStopping							= 3
}
function PsyAntenna:__init				()
// ----------------------------------------------------------------------------------------
// settings
// ----------------------------------------------------------------------------------------
// phantom gen
// ----------------------------------------------------------------------------------------
	self.phantom_max 					= 0 //8 //10	// max phantoms
	self.phantom_spawn_probability		= 0.1;	// spawn probability (0..1)
	self.phantom_spawn_radius			= 30.0;	// average radius 30.0m +-15m
	self.phantom_spawn_height			= 2.5 //3	// average height from actor pos +-1.5m
	// antenna
	self.hit_amplitude					= 1.0;	// hit_amplitude*hit_factor.a
	// pause time [from]=to
	self.idle_time						= {};
	self.idle_time[20]					= 21;
// ----------------------------------------------------------------------------------------
// postprocess
// ----------------------------------------------------------------------------------------
	self.base_amplitude					= color(0.2,0.15,0.0);		// max base color diff			[0.0-0.5]
	self.gray_amplitude					= 0.5;						// gray max intensity			[0.0-1.0]
	self.add_factor						= 0.1;	//0.3				// factor * color_animator(RGB)	[0.0-1.0]
	self.dual_amplitude					= 0.075 //0.05				// H&V same						[0.0-0.2]
	self.gray_color						= color(0.33,0.33,0.33);	// RGB							[0.0-1.0]
	self.noise_var						= noise(0.9,0.3,30);		// intensity, grain, fps		[0.0-1.0,0.0-1.0,1-100]
// ----------------------------------------------------------------------------------------
// class variables initialize
	self.phase 							= pa_phase.phIdle;
	self.power_factor					= fcolor();
	self.eff_time						= 0;
	self.starting_anim					= color_animator			("levels\\psy_antenna\\starting");
	self.starting_time					= self.starting_anim:length	();
	self.working_anim					= color_animator			("levels\\psy_antenna\\working");
	self.stopping_anim					= color_animator			("levels\\psy_antenna\\stopping");
	self.stopping_time					= self.stopping_anim:length();
	self.hit_time						= 0;
	self.intensity						= 0;
	self.pp 							= PsyAntennaPP();
	self.pp:start						();
end
function PsyAntenna:__finalize			()
	self.pp:finish 						();
end;


g_PsyAntenna	 						= PsyAntenna();

function PsyAntenna:construct			()
end

function PsyAntenna:load				(F)
	self.phase 							= F:r_u32();
end
function PsyAntenna:save				(F)
	F:r_u32								(self.phase);
end

function PsyAntenna:is_idle_time		(tm)
	if tm>=13 and tm<14 then 			return true;
	elseif tm>=20 and tm<21 then 		return true; 
	end;
	return false;
end
function PsyAntenna:update_postprocess	()
	self.pp.params.color_base			= color(0.5+self.base_amplitude.r*self.intensity,0.5+self.base_amplitude.g*self.intensity,0.5+self.base_amplitude.b*self.intensity);
	self.pp.params.color_gray			= color(self.gray_color.r,self.gray_color.g,self.gray_color.b);
	self.pp.params.color_add 			= color(self.power_factor.r*self.add_factor,self.power_factor.g*self.add_factor,self.power_factor.b*self.add_factor);
	self.pp.params.gray					= self.gray_amplitude*self.intensity;
	self.pp.params.dual					= duality(self.dual_amplitude*self.power_factor.a,self.dual_amplitude*self.power_factor.a);
//	self.pp.params.noise				= self.noise_var;
end
function PsyAntenna:update_psy_hit		(dt)
	local d_time						= time_global()-self.hit_time;
	if d_time>200 and self.power_factor.a>0.01 then
		self.hit_time					= time_global();
		local psy_hit 					= hit();
		psy_hit.power 					= self.power_factor.a*self.hit_amplitude;
		psy_hit.direction 				= vector():set( 0, 0, 0 );
		psy_hit.impulse 				= 0;
		psy_hit.draftsman 				= db.actor; 
		psy_hit.type 					= hit.telepatic;
		db.actor:hit					(psy_hit);
	end;
end
function PsyAntenna:generate_phantoms 	()
	if self.power_factor.a>0.1 then
		if math.random()<self.phantom_spawn_probability then
			if phantom_manager:phantom_count()<self.phantom_max then
				local yaw	 			= math.pi*2.0*math.random();
				local radius 			= self.phantom_spawn_radius*(math.random()/2.0+0.5);
				local height 			= self.phantom_spawn_height*math.random();
				local a_pos 			= db.actor:position();
				local pos 				= vector():set(math.sin(yaw)*radius+a_pos.x,a_pos.y+height,math.cos(yaw)*radius+a_pos.z);
				phantom_manager.spawn_phantom(pos);
			end;
		end;
	end;
end

function PsyAntenna:switch_to_phase		(ph)
	self.phase							= ph;
	self.eff_time		 				= 0;
	self.power_factor:set				(0,0,0,0);
end
function PsyAntenna:phase_starting		()
	self.intensity						= self.eff_time/self.starting_time;
	if self.eff_time>self.starting_time then
		self:switch_to_phase			(pa_phase.phWorking);
	else
		self.power_factor:set 			(self.starting_anim:calculate(self.eff_time/1000));
	end;
end
function PsyAntenna:phase_working		()
	self.intensity						= 1.0;
	local h								= level.get_time_hours();
	if self:is_idle_time(h) then 				
		self:switch_to_phase			(pa_phase.phStopping);
	else
		self.power_factor:set 			(self.working_anim:calculate(self.eff_time/1000));
		self:generate_phantoms 			();
	end;
end
function PsyAntenna:phase_stopping		()
	self.intensity						= 1.0-self.eff_time/self.stopping_time;
	if self.eff_time>self.stopping_time then
		self:switch_to_phase			(pa_phase.phIdle);
	else
		self.power_factor:set			(self.stopping_anim:calculate(self.eff_time/1000));
	end;
end
function PsyAntenna:phase_idle			()
	local h								= level.get_time_hours();
	if false==self:is_idle_time(h) then 				
		self:switch_to_phase			(pa_phase.phStarting);
	end;
end
function PsyAntenna:update				(dt)
	self.eff_time						= self.eff_time + dt;
	if self.phase==pa_phase.phStarting 		then self:phase_starting	();
	elseif self.phase==pa_phase.phWorking	then self:phase_working		();
	elseif self.phase==pa_phase.phStopping	then self:phase_stopping	();
	elseif self.phase==pa_phase.phIdle 		then self:phase_idle		(); end;
	if (self.intensity<0.0)				then self.intensity=0.0; end;
	if (self.intensity>1.0)				then self.intensity=1.0; end;
	self:update_postprocess 			();
	self:update_psy_hit					(dt);
end

function main()
	while db.actor==nil do wait(); end;
	if false==has_alife_info("psy_antenna_off") then
		g_PsyAntenna:construct			();
		local prev_time					= time_global();
		while 1 do
			wait						();
			local dt					= time_global()-prev_time;
			prev_time					= time_global();
			g_PsyAntenna:update			(dt);
		end
	end
end


class "PsyAntenna2"
pa_phase={
	phIdle 								= 0,
	phStarting 							= 1,
	phWorking 							= 2,
	phStopping							= 3
}
function PsyAntenna2:__init				()
// ----------------------------------------------------------------------------------------
// settings
// ----------------------------------------------------------------------------------------
// phantom gen
// ----------------------------------------------------------------------------------------
	self.phantom_max 					= 10 //8 //10	// max phantoms
	self.phantom_spawn_probability		= 0.1;	// spawn probability (0..1)
	self.phantom_spawn_radius			= 30.0;	// average radius 30.0m +-15m
	self.phantom_spawn_height			= 2.5 //3	// average height from actor pos +-1.5m
	// antenna
	self.hit_amplitude					= 1;	// hit_amplitude*hit_factor.a
	// pause time [from]=to
	self.idle_time						= {};
	self.idle_time[20]					= 21;
// ----------------------------------------------------------------------------------------
// postprocess
// ----------------------------------------------------------------------------------------
	self.base_amplitude					= color(0.2,0.15,0.0);		// max base color diff			[0.0-0.5]
	self.gray_amplitude					= 0.5;						// gray max intensity			[0.0-1.0]
	self.add_factor						= 0.1;	//0.3				// factor * color_animator(RGB)	[0.0-1.0]
	self.dual_amplitude					= 0.075 //0.05				// H&V same						[0.0-0.2]
	self.gray_color						= color(0.33,0.33,0.33);	// RGB							[0.0-1.0]
	self.noise_var						= noise(0.9,0.3,30);		// intensity, grain, fps		[0.0-1.0,0.0-1.0,1-100]
// ----------------------------------------------------------------------------------------
// class variables initialize
	self.phase 							= pa_phase.phIdle;
	self.power_factor					= fcolor();
	self.eff_time						= 0;
	self.starting_anim					= color_animator			("levels\\psy_antenna\\starting");
	self.starting_time					= self.starting_anim:length	();
	self.working_anim					= color_animator			("levels\\psy_antenna\\working");
	self.stopping_anim					= color_animator			("levels\\psy_antenna\\stopping");
	self.stopping_time					= self.stopping_anim:length();
	self.hit_time						= 0;
	self.intensity						= 0;
	self.pp 							= PsyAntennaPP();
	self.pp:start						();
	self.flag = 1;


// ----------------------------------------------------------------------------------------
// sound
// ----------------------------------------------------------------------------------------

	self.sound_intensity				= 0
	self.sound_intensity_base			= 0	// базовая интенсивность. к ней стремится текущая со скоростью self.intensity_inertion	
	self.intensity_inertion				= 0.05	// скорость изменения интенсивности ед/секунду

	self.sound_initialized				= false

	self.sound_obj_right, self.sound_obj_left = xr_sound.get_sound_object("psy_voices", "random")

	self.sound_obj_left.volume			= self.sound_intensity
	self.sound_obj_right.volume			= self.sound_intensity
	self.snd_volume						= level.get_snd_volume()
	self.mute_sound_threshold			= 0 --' Предел до которого можно занижать звук уровня. 0 - можно заглушить полностью
	self.max_mumble_volume				= 10

end
function PsyAntenna2:__finalize			()
	self.pp:finish 						();
end;

function PsyAntenna2:start2			()
	if self.flag == 0 then
	self.pp:start 	();
	self.flag = 1
	end		
end;

function PsyAntenna2:final2			()
	if self.flag == 1 then
	self.pp:finish 						();
	level.set_snd_volume				(self.snd_volume)
	self.flag = 0
	end		

end;

g_PsyAntenna2	 						= PsyAntenna2();

function PsyAntenna2:construct			()
end

function PsyAntenna2:load				(F)
	self.phase 							= F:r_u32();
end
function PsyAntenna2:save				(F)
	F:r_u32								(self.phase);
end

function PsyAntenna2:is_idle_time		(tm)
	if tm>=13 and tm<14 then 			return true;
	elseif tm>=20 and tm<21 then 		return true; 
	end;
	return false;
end


function PsyAntenna2:update_sound()
	if not self.sound_initialized then
		self.sound_obj_left:play_at_pos		(db.actor, vector():set(-1, 0, 1), 0, sound_object.s2d + sound_object.looped)
		self.sound_obj_right:play_at_pos	(db.actor, vector():set( 1, 0, 1), 0, sound_object.s2d + sound_object.looped)

		self.sound_initialized = true
	end

	local vol = 1 - ( self.sound_intensity ^ 3 ) * 0.9

	if vol < self.mute_sound_threshold then
		level.set_snd_volume( self.mute_sound_threshold )
	else
		level.set_snd_volume( vol )
	end

	self.sound_obj_left.volume  = 1 / vol - 1
	self.sound_obj_right.volume = 1 / vol - 1
end

function PsyAntenna2:update_postprocess	()
	self.pp.params.color_base			= color(0.5+self.base_amplitude.r*self.intensity,0.5+self.base_amplitude.g*self.intensity,0.5+self.base_amplitude.b*self.intensity);
	self.pp.params.color_gray			= color(self.gray_color.r,self.gray_color.g,self.gray_color.b);
	self.pp.params.color_add 			= color(self.power_factor.r*self.add_factor,self.power_factor.g*self.add_factor,self.power_factor.b*self.add_factor);
	self.pp.params.gray					= self.gray_amplitude*self.intensity;
	self.pp.params.dual					= duality(self.dual_amplitude*self.power_factor.a,self.dual_amplitude*self.power_factor.a);
//	self.pp.params.noise				= self.noise_var;
end
function PsyAntenna2:update_psy_hit		(dt)
	local d_time						= time_global()-self.hit_time;
	if d_time>200 and self.power_factor.a>0.01 then
		self.hit_time					= time_global();
		local psy_hit 					= hit();
		psy_hit.power 					= self.power_factor.a*self.hit_amplitude;
		psy_hit.direction 				= vector():set( 0, 0, 0 );
		psy_hit.impulse 				= 0;
		psy_hit.draftsman 				= db.actor; 
		psy_hit.type 					= hit.telepatic
		db.actor:hit					(psy_hit);
		psy_hit.power 					= (self.power_factor.a*self.hit_amplitude)/3;
                psy_hit.type = hit.shock
		db.actor:hit					(psy_hit);
	end;
end
function PsyAntenna2:generate_phantoms 	()
	if self.power_factor.a>=0.001 then
		--if math.random()<self.phantom_spawn_probability then
			if phantom_manager:phantom_count()<self.phantom_max then
				local yaw	 			= math.pi*2.0*math.random();
				local radius 			= self.phantom_spawn_radius*(math.random()/2.0+0.5);
				local height 			= self.phantom_spawn_height*math.random();
				local a_pos 			= db.actor:position();
				local pos 				= vector():set(math.sin(yaw)*radius+a_pos.x,a_pos.y+height,math.cos(yaw)*radius+a_pos.z);
				phantom_manager.spawn_phantom(pos);
			end;
		--end;
	end;
end

function PsyAntenna2:switch_to_phase		(ph)
	self.phase							= ph;
	self.eff_time		 				= 0;
	self.power_factor:set				(0,0,0,0);
end
function PsyAntenna2:phase_starting		()
	self.intensity						= self.eff_time/self.starting_time;
	if self.eff_time>self.starting_time then
		self:switch_to_phase			(pa_phase.phWorking);
	else
		self.power_factor:set 			(self.starting_anim:calculate(self.eff_time/1000));
	end;
end
function PsyAntenna2:phase_working		()
	self.intensity						= 1.0;
	local h								= level.get_time_hours();
	--if self:is_idle_time(h) then 				
		--self:switch_to_phase			(pa_phase.phStopping);
	--else
		self.power_factor:set 			(self.working_anim:calculate(self.eff_time/1000));
		self:generate_phantoms 			();
	--end;
end
function PsyAntenna2:phase_stopping		()
	self.intensity						= 1.0-self.eff_time/self.stopping_time;
	if self.eff_time>self.stopping_time then
		self:switch_to_phase			(pa_phase.phIdle);
	else
		self.power_factor:set			(self.stopping_anim:calculate(self.eff_time/1000));
	end;
end
function PsyAntenna2:phase_idle			()
	local h								= level.get_time_hours();
	if false==self:is_idle_time(h) then 				
		self:switch_to_phase			(pa_phase.phStarting);
	end;
end
function PsyAntenna2:update				(dt)
	self.eff_time						= self.eff_time + dt;
	if self.phase==pa_phase.phStarting 		then self:phase_starting	();
	elseif self.phase==pa_phase.phWorking	then self:phase_working		();
	elseif self.phase==pa_phase.phStopping	then self:phase_stopping	();
	elseif self.phase==pa_phase.phIdle 		then self:phase_idle		(); end;
	if (self.intensity<0.0)				then self.intensity=0.0; end;
	if (self.intensity>1.0)				then self.intensity=1.0; end;
	self:update_postprocess 			();
	self:update_psy_hit					(dt);

	function update_intensity(intensity_base, intensity)
		local di = self.intensity_inertion * dt * 0.001
		local ii = intensity_base
		if math.abs(intensity_base - intensity) >= di then
			if intensity_base < intensity then
				ii = intensity - di
			else
				ii = intensity + di
			end
		end

		if		ii < 0.0 then ii = 0.0 
		elseif	ii > 1.0 then ii = 1.0 end
		return ii
	end

	self.sound_intensity = update_intensity(self.sound_intensity_base, self.sound_intensity)
	self:update_sound()

end

