#using scripts\codescripts\struct;

#using scripts\shared\callbacks_shared;
#using scripts\shared\challenges_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\damagefeedback_shared;
#using scripts\shared\entityheadicons_shared;
#using scripts\shared\killcam_shared;
#using scripts\shared\scoreevents_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;
#using scripts\shared\weapons\_tacticalinsertion;
#using scripts\shared\weapons\_weaponobjects;
#using scripts\shared\_burnplayer;

    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   


#namespace incendiary;

function autoexec __init__sytem__() {     system::register("incendiary_grenade",&init_shared,undefined,undefined);    }


function init_shared()
{
	level.incendiaryfireDamage = GetDvarInt( "scr_incendiaryfireDamage", 35 ); // how much damage will the fire do each tick
	level.incendiaryfireDamageHardcore = GetDvarInt( "scr_incendiaryfireDamageHardcore", 15 ); // how much damage will the fire do each tick in hardcore
 	level.incendiaryfireDuration = GetDvarInt ("scr_incendiaryfireDuration", 5 ); // time damage triggers will last.
 	level.incendiaryfxDuration = GetDvarFloat( "scr_incendiaryfxDuration", 0.4 ); // Incendiary fx duration
	level.incendiaryDamageRadius = GetDvarInt( "scr_incendiaryDamageRadius", 125 ); // radius of individual damages
	level.incendiaryfireDamageTickTime = GetDvarFloat( "scr_incendiaryfireDamageTickTime", 1 ); // time between damage hits
	
	
 	level.incendiaryDamageThisTick = [];
 	
	callback::on_spawned( &create_incendiary_watcher );
}

/#
function updateIncendiaryFromDvars()
{
	level.incendiaryfireDamage = GetDvarInt( "scr_incendiaryfireDamage", level.incendiaryfireDamage ); 
	level.incendiaryfireDamageHardcore = GetDvarInt( "scr_incendiaryfireDamageHardcore", level.incendiaryfireDamageHardcore ); 
 	level.incendiaryfireDuration = GetDvarInt( "scr_incendiaryfireDuration", level.incendiaryfireDuration ); 
	level.incendiaryDamageRadius = GetDvarInt( "scr_incendiaryDamageRadius", level.incendiaryDamageRadius );
	level.incendiaryfireDamageTickTime = GetDvarFloat( "scr_incendiaryfireDamageTickTime", level.incendiaryfireDamageTickTime );	
 	level.incendiaryfxDuration = GetDvarFloat( "scr_incendiaryfxDuration", level.incendiaryfxDuration );
}
#/

function create_incendiary_watcher() // self == player
{
	watcher = self weaponobjects::createUseWeaponObjectWatcher( "incendiary_grenade", self.team );
	
	watcher.onSpawn = &incendiary_system_spawn;
}

function incendiary_system_spawn( watcher, player ) // self == incendiary grenade
{
	player endon( "death" );
	player endon( "disconnect" );
	level endon( "game_ended" );
	
	player AddWeaponStat( self.weapon, "used", 1 );	
	thread watchForExplode( player );
}


function watchForExplode( owner )
{
	self endon( "hacked" );
	self endon( "delete" );
	
	killCamEnt = spawn( "script_model", self.origin );
	killCamEnt util::deleteAfterTime( 15.0 );
	killCamEnt.startTime = gettime();
	killCamEnt linkto( self );
	killCamEnt setWeapon( self.weapon );

	killcamEnt killcam::store_killcam_entity_on_entity(self);
	
	self waittill( "projectile_impact_explode", origin, normal, surface );
	killCamEnt unlink();
	/#
	updateIncendiaryFromDvars();
	#/
	PlaySoundAtPosition ("wpn_incendiary_core_start" ,self.origin);
	
	generateLocations( origin, owner, normal, killCamEnt );
}

function getstepoutdistance( normal )
{
	if ( normal[2] < 0.5 )
	{
		stepoutdistance = normal * GetDvarInt( "scr_incendiary_stepout_wall", 50 );
	}
	else 
	{
		stepoutdistance = normal * GetDvarInt( "scr_incendiary_stepout_ground", 12 );
	}
	return stepoutdistance;
}

function generateLocations( position, owner, normal, killCamEnt )
{
	startPos = position + getstepoutdistance( normal );
	desiredEndPos = startPos + ( 0, 0, 60 );
	physTrace = PhysicsTrace( startPos, desiredEndPos, ( -4, -4, -4 ), ( 4, 4, 4 ), self, (1 << 0) );
	goalPos = ( ( physTrace[ "fraction" ] < 1 ) ? physTrace[ "position"]  : desiredEndPos );
	
	killCamEnt moveto( goalPos, 0.5 );
	rotation = RandomInt( 360 );
	
	if ( normal[2] < 0.1 ) // vertical wall
	{
		black = ( 0.1, 0.1, 0.1 );
			
		trace = hitPos( startPos, startpos + ( -normal * 70 ) + ( 0,0, -1 ) * 70, black );
		tracePosition = trace["position"];	
		incendiaryGrenade = GetWeapon( "incendiary_fire" );
		
		if ( trace["fraction"] < 0.9 )
		{
			wallnormal = trace["normal"];
			SpawnTimedFX( incendiaryGrenade, trace["position"], wallnormal, level.incendiaryfireDuration, self.team  );
		}
	}

	fxCount = GetDvarInt( "scr_incendiary_fx_count", 6 );
	spawnAllLocs( owner, startPos, normal, 1, rotation, killcament, fxCount );
}

function getLocationForFX( startPos, fxIndex, fxCount, defaultDistance, rotation )
{
	currentAngle = ( ( 360 / fxCount ) * fxIndex );
	cosCurrent = cos( currentAngle + rotation );
	sinCurrent = sin( currentAngle + rotation );
	
	return startPos + ( defaultDistance * cosCurrent, defaultDistance * sinCurrent, 0 );
}

function spawnAllLocs( owner, startPos, normal, multiplier, rotation, killcament, fxCount )
{
	defaultDistance = GetDvarInt( "scr_incendiary_trace_distance", 220 ) * multiplier;
	defaultDropDistance = GetDvarInt( "scr_incendiary_trace_down_distance", 90 );
	
	// DROCHE:TODO
	// if we are going to keep this grenade this should be moved to code
	
	colorArray = [];
	colorArray[colorArray.size] = ( 0.9, 0.2, 0.2 );
	colorArray[colorArray.size] = ( 0.2, 0.9, 0.2 );
	colorArray[colorArray.size] = ( 0.2, 0.2, 0.9 );
	colorArray[colorArray.size] = ( 0.9, 0.9, 0.9 );


	locations = [];
	locations["color"] = [];
	locations["loc"] = [];
	locations["tracePos"] = [];
	locations["distSqrd"] = [];
	locations["fxtoplay"] = [];
	locations["radius"] = [];

	
	for( fxIndex = 0; fxIndex < fxCount; fxIndex++ )
	{
		locations["point"][fxIndex] = getLocationForFX( startPos, fxIndex, fxCount, defaultDistance, rotation );
		locations["color"][fxIndex] = colorArray[fxIndex % colorArray.size];
	}
		
	for ( count = 0; count < fxCount; count++ )
	{
		trace = hitPos( startPos, locations["point"][count], locations["color"][count] );
		tracePosition = trace["position"];
		locations["tracePos"][count] = tracePosition;
		 
		if ( trace["fraction"] < 0.7 )
		{
			locations["loc"][count] = tracePosition;
			locations["normal"][count] = trace["normal"];
			continue;
		}
		
		average = startPos/2 + tracePosition/2;

		trace = hitPos( average, average - ( 0, 0, defaultDropDistance ), locations["color"][count] );
		if ( trace["fraction"] != 1 )
		{
			locations["loc"][count] = trace["position"];
			locations["normal"][count] = trace["normal"];
		}
	}	

	// startPos = startPos - getstepoutdistance( normal ); // start pos is already a good position for fx, we are using a different sized trigger now.
	
	incendiaryGrenade = GetWeapon( "incendiary_fire" );

	SpawnTimedFX( incendiaryGrenade, startPos, normal, level.incendiaryfireDuration, self.team );
	
	level.incendiaryDamageRadius = GetDvarInt( "scr_incendiaryDamageRadius", level.incendiaryDamageRadius );
	
	thread damageEffectArea ( owner, startPos, level.incendiaryDamageRadius, level.incendiaryDamageRadius, killCamEnt );
	
	for ( count = 0; count < locations["point"].size; count++ )
	{
		if ( isdefined ( locations["loc"][count] ) )
		{
			normal = locations["normal"][count];
				
			SpawnTimedFX( incendiaryGrenade, locations["loc"][count], normal, level.incendiaryfireDuration, self.team );
		}
	}
}

/#
function incendiary_debug_line( from, to, color, depthTest, time )
{
	debug_rcbomb = GetDvarInt( "scr_incendiary_debug", 0 );
	if ( debug_rcbomb == 1 )
	{
		if ( !isdefined(time) )
		{
			time = 100;
		}
		if ( !isdefined(depthTest) )
		{
			depthTest = true;
		}
		Line( from, to, color, 1, depthTest, time);
	}
}
#/
	
	

function damageEffectArea ( owner, position, radius, height, killCamEnt )
{
	trigger_radius_position = position - ( 0 , 0, height );
	trigger_radius_height = height * 2;

	fireEffectArea = spawn( "trigger_radius", trigger_radius_position, 0, radius, trigger_radius_height );
	
	// Create head icon
//	objective = GetEquipmentHeadObjective( GetWeapon( "incendiary_grenade" ) );
//	killCamEnt entityheadicons::setEntityHeadIcon( owner.pers["team"], owner, (0,0,0), objective );

/#
	if( GetDvarint( "scr_draw_triggers" ) )
		level thread util::drawcylinder( trigger_radius_position, radius, trigger_radius_height, undefined, "incendiary_draw_cylinder_stop" );
#/
	
	// raps stuff
	if ( isdefined( level.rapsOnBurnRaps ) )
	{
		owner thread [[level.rapsOnBurnRaps]]( fireEffectArea );
	}
	
	ownerOriginalTeam = owner.team;

	// loop variables
	loopWaitTime = level.incendiaryFireDamageTickTime;
	durationOfIncendiary = level.incendiaryFireDuration;

	// loop for the duration of the effect
	while (durationOfIncendiary > 0)
	{
		if ( isdefined( owner ) && owner.team !== ownerOriginalTeam )
		{
			break;
		}
		
		durationOfIncendiary -= loopWaitTime;
		damageApplied = false;

		potential_targets = self getPotentialTargets( owner );
		foreach( target in potential_targets )
		{
			self tryToApplyFireDamage( target, owner, position, fireEffectArea, loopWaitTime, killcament );
		}

		wait (loopWaitTime);
	}
	
	// Delete head icon
	if ( isdefined( killCamEnt ) )
		killCamEnt entityheadicons::destroyEntityHeadIcons();
	// clean up
	fireEffectArea delete();	

/#
	if( GetDvarint( "scr_draw_triggers" ) )
		level notify( "incendiary_draw_cylinder_stop" );
#/
}	

function getPotentialTargets( owner ) // self == incendiary grenade
{
	// try getting team based targets first
	owner_team = ( isdefined( owner ) ? owner.team : undefined );
	if ( level.teambased && isdefined( owner_team ) && level.friendlyfire == 0 )
	{
		enemy_team = ( owner_team == "axis" ? "allies" : "axis" );
		potential_targets = [];
		potential_targets = ArrayCombine( potential_targets, GetPlayers( enemy_team ), false, false );
		potential_targets = ArrayCombine( potential_targets, GetAITeamArray( enemy_team ), false, false );
		potential_targets = ArrayCombine( potential_targets, GetVehicleTeamArray( enemy_team ), false, false );
		potential_targets[ potential_targets.size ] = owner;
		return potential_targets;
	}
	
	// now get all targets
	all_targets = [];
	all_targets = ArrayCombine( all_targets, level.players, false, false );
	all_targets = ArrayCombine( all_targets, GetAIArray(), false, false );
	all_targets = ArrayCombine( all_targets, GetVehicleArray(), false, false );

	// if this is hardcore, then every entity is a potential target
	if ( level.friendlyfire > 0 )
		return all_targets;

	// remove all targets not on the same team, except owner
	potential_targets = [];
	foreach( target in all_targets )
	{
		if ( !isdefined( target ) )
			continue;

		if( !isdefined( target.team ) )
			continue;
				
		if( isdefined( owner ) )
		{
			if( target != owner )				
			{
				if( !isdefined( owner_team ) )
					continue;
				
				if( target.team == owner_team )
					continue;
			}
		}
		else
		{
			if ( !isdefined( self ) )
				continue;

			if( !isdefined( self.team ) )
				continue;

			if( target.team == self.team )
				continue;
		}

		potential_targets[ potential_targets.size ] = target;
	}
	
	return potential_targets;
}

function tryToApplyFireDamage( target, owner, position, fireEffectArea, resetFireTime, killcament )  // self == incendiary grenade
{
	// see if we're not in the fire area
	if ( ( !isdefined(target.infireArea) ) || (target.infireArea == false) )
	{
		// since we're not in the poison area, now see if we're in the fire area
		if ( target istouching(fireEffectArea) && ( !isdefined(target.sessionstate) || target.sessionstate == "playing" ) )
		{
			trace = bullettrace( position, target GetShootAtPos(), false, target, true );

			if ( trace["fraction"] == 1 )
			{
				target.lastburnedBy = owner;
				target thread damageInFireArea( fireEffectArea, killcament, trace, position, resetFireTime );
			}
		}
	}
}

function damageInFireArea( fireEffectArea, killcament, trace, position, resetFireTime ) // self == player in fire area
{
	self endon( "disconnect" );
	self endon( "death" );

	timer = 0;

	damage = level.incendiaryfireDamage;
	if( level.hardcoreMode )
	{
		damage = level.incendiaryfireDamageHardcore;
	}
	
	if ( canDoFireDamage( killCamEnt, self, resetFireTime ) )
	{
/#
		level.incendiary_debug = GetDvarInt( "scr_incendiary_debug", 0 );
		if ( level.incendiary_debug )
		{
			if ( !isdefined( level.incendiaryDamageTime ) )
			{
				level.incendiaryDamageTime = GetTime();
			}

			iprintlnbold( level.incendiaryDamageTime - getTime() );
			level.incendiaryDamageTime = getTime();
		}
#/
		self DoDamage( damage, fireEffectArea.origin, self.lastburnedBy, killCamEnt, "none", "MOD_BURNED", 0, GetWeapon( "incendiary_fire" ) );
		
		entnum = self getentitynumber();

		self thread sndFireDamage();
	}
}


function sndFireDamage()
{	
	self notify( "sndFire" );
	self endon( "death" );
	self endon( "disconnect" );
	self endon( "sndFire" );
	
	if( !isdefined( self.sndFireEnt ) )
	{
		self.sndFireEnt = spawn( "script_origin", self.origin );
		self.sndFireEnt linkto( self, "tag_origin" );
		self.sndFireEnt playsound( "chr_burn_start" );
		self thread sndFireDamage_DeleteEnt(self.sndFireEnt);
	}
	
	self.sndFireEnt playloopsound( "chr_burn_start_loop", .5 );
	wait(3);
	self.sndFireEnt delete();
	self.sndFireEnt = undefined;
}
function sndFireDamage_DeleteEnt(ent)
{
	self endon( "disconnect" );
	self waittill( "death" );
	
	if( isdefined( ent ) )
		ent delete(); //pfx_fire_incendiary
}


function hitPos( start, end, color )
{
	trace = bullettrace( start, end, false, undefined );
	
/#
	level.incendiary_debug = GetDvarInt( "scr_incendiary_debug", 0 );
	if ( level.incendiary_debug )
	{
		debugstar(trace["position"], 2 * 1000, color);
	}

	thread incendiary_debug_line( start, trace["position"], color, true, 80 );
#/
	
	return trace;
}

function canDoFireDamage( killCamEnt, victim, resetFireTime )
{
	entNum = victim getentitynumber();
	if ( !isdefined( level.incendiaryDamageThisTick[entNum] ) )
	{
		level.incendiaryDamageThisTick[entNum] = 0;
		level thread resetFireDamage( entnum, resetFireTime );
		return true;
	}
	
	return false;
}

function resetFireDamage( entnum, time  )
{
	if ( time > 0.05 )
	{
		wait( time - 0.05 );
	}
	level.incendiaryDamageThisTick[entnum] = undefined;
}

	