#using scripts\codescripts\struct;

#using scripts\shared\callbacks_shared;
#using scripts\shared\challenges_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\scoreevents_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;
#using scripts\shared\weapons\_weaponobjects;

    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   




	
#precache( "fx", "weapon/fx_betty_exp_destroyed" );
#precache( "fx", "weapon/fx_betty_light_blue" );
#precache( "fx", "weapon/fx_betty_light_orng" );
	
#precache( "model", "wpn_t7_grenade_incendiary_world" );


#using_animtree ( "bouncing_betty" );


#namespace bouncingbetty;

function init_shared()
{
	level.bettyDestroyedFX = "weapon/fx_betty_exp_destroyed";

	level._effect["fx_betty_friendly_light"] = "weapon/fx_betty_light_blue";
	level._effect["fx_betty_enemy_light"] = "weapon/fx_betty_light_orng";

	level.bettyMinDist = 20;
	level.bettyStunTime = 1;
	
	bettyExplodeAnim = %o_spider_mine_detonate;
	bettyDeployAnim = %o_spider_mine_deploy;

	level.bettyRadius = getDvarInt( "betty_detect_radius", 180 );
	level.bettyActivationDelay = getDvarFloat( "betty_activation_delay", 1 );
	level.bettyGracePeriod = getDvarFloat( "betty_grace_period", 0.0 );
	level.bettyDamageRadius = getDvarInt( "betty_damage_radius", 180 );
	level.bettyDamageMax = getDvarInt( "betty_damage_max", 180 );
	level.bettyDamageMin = getDvarInt( "betty_damage_min", 70 );
	level.bettyDamageHeight = getDvarInt( "betty_damage_cylinder_height", 200 );

	level.bettyJumpHeight = getDvarInt( "betty_jump_height_onground", 55 );
	level.bettyJumpHeightWall = getDvarInt( "betty_jump_height_wall", 20 );
	level.bettyJumpHeightWallAngle = getDvarInt( "betty_onground_angle_threshold", 30 );
	level.bettyJumpHeightWallAngleCos = cos( level.bettyJumpHeightWallAngle ); 
	level.bettyJumpTime = getDvarFloat( "betty_jump_time", 0.7 );
	
	level.bettyBombletSpawnDistance = 20;
	level.bettyBombletCount = 4;
	
	level thread register();
	/#
		level thread bouncingBettyDvarUpdate();
	#/
	
	callback::add_weapon_watcher( &createBouncingBettyWatcher );
}

function register()
{
	clientfield::register( "missile", "bouncingbetty_state", 1, 2, "int" );
	clientfield::register( "scriptmover", "bouncingbetty_state", 1, 2, "int" );
}

/#
function bouncingBettyDvarUpdate()
{
	for(;;)
	{
		level.bettyRadius = getDvarInt( "betty_detect_radius", level.bettyRadius );
		level.bettyActivationDelay = getDvarFloat( "betty_activation_delay", level.bettyActivationDelay );
		level.bettyGracePeriod = getDvarFloat( "betty_grace_period", level.bettyGracePeriod );
		level.bettyDamageRadius = getDvarInt( "betty_damage_radius", level.bettyDamageRadius );
		level.bettyDamageMax = getDvarInt( "betty_damage_max", level.bettyDamageMax );
		level.bettyDamageMin = getDvarInt( "betty_damage_min", level.bettyDamageMin );
		level.bettyDamageHeight = getDvarInt( "betty_damage_cylinder_height", level.bettyDamageHeight );
		level.bettyJumpHeight = getDvarInt( "betty_jump_height_onground", level.bettyJumpHeight );
		level.bettyJumpHeightWall = getDvarInt( "betty_jump_height_wall", level.bettyJumpHeightWall );
		level.bettyJumpHeightWallAngle = getDvarInt( "betty_onground_angle_threshold", level.bettyJumpHeightWallAngle );
		level.bettyJumpHeightWallAngleCos = cos( level.bettyJumpHeightWallAngle );
		level.bettyJumpTime = getDvarFloat( "betty_jump_time", level.bettyJumpTime );
		wait( 3 );
	}
}
#/

//******************************************************************
//                                                                 *
//                                                                 *
//******************************************************************
function createBouncingBettyWatcher() // self == player
{
	watcher = self weaponobjects::createProximityWeaponObjectWatcher( "bouncingbetty", self.team );
	
	watcher.onSpawn =&onSpawnBouncingBetty;
	watcher.watchForFire = true;
	watcher.onDetonateCallback =&bouncingBettyDetonate;
	//Eckert - playing sound later
	//watcher.activateSound = "fly_betty_exp";
	watcher.activateSound = "wpn_betty_alert";
	watcher.hackable = true;
	watcher.hackerToolRadius = level.equipmentHackerToolRadius;
	watcher.hackerToolTimeMs = level.equipmentHackerToolTimeMs;
	watcher.ownerGetsAssist = true;
	watcher.ignoreDirection = true;
	watcher.immediateDetonation = true;
	watcher.immunespecialty = "specialty_immunetriggerbetty";
	
	watcher.detectionMinDist = level.bettyMinDist;
	watcher.detectionGracePeriod = level.bettyGracePeriod;
	watcher.detonateRadius = level.bettyRadius;
	watcher.onFizzleOut = &bouncingbetty::onBouncingBettyFizzleOut;
	
	watcher.stun =&weaponobjects::weaponStun;
	watcher.stunTime = level.bettyStunTime;

	watcher.activationDelay = level.bettyActivationDelay;
}

function onBouncingBettyFizzleOut()
{
	if ( isdefined( self.mineMover ) )
	{
		if ( isdefined( self.mineMover.killcament ) )	
		{
			self.mineMover.killcament delete();
		}
		self.mineMover delete();
	}
	self delete();
}

//******************************************************************
//                                                                 *
//                                                                 *
//******************************************************************
function onSpawnBouncingBetty( watcher, owner ) // self == betty ent
{
	weaponobjects::onSpawnProximityWeaponObject( watcher, owner );
	self.originalOwner = owner;
	self thread spawnMineMover();
	self trackOnOwner( owner );
	self thread trackUsedStatOnDeath();
	self thread doNoTrackUsedStatOnPickup();
	self thread trackUsedOnHack();
}

function trackUsedStatOnDeath()
{
	self endon( "do_not_track_used" );
	self waittill( "death" );
	waittillframeend; // to compensate for timiing issues with notifies and death
	if ( isdefined( self.owner ) )
	{
		self.owner trackBouncingBettyAsUsed(); // since betties can be picked up or hacked, we track them as used on death
	}
	self notify( "end_doNoTrackUsedOnPickup" );
	self notify( "end_doNoTrackUsedOnHacked" );
}

function doNoTrackUsedStatOnPickup() // self == betty ent
{
	self endon( "end_doNoTrackUsedOnPickup" );
	self waittill( "picked_up" );
	self notify( "do_not_track_used" );
}

function trackUsedOnHack() // self == betty ent
{
	self endon( "end_doNoTrackUsedOnHacked" );
	self waittill( "hacked" );
	self.originalOwner trackBouncingBettyAsUsed(); // since betties can be picked up or hacked, we track them as used on hack too
	self notify( "do_not_track_used" ); // remove old one as it was hacked
}

function trackBouncingBettyAsUsed()
{
	if ( IsPlayer( self ) )
	{
		self AddWeaponStat( GetWeapon( "bouncingbetty" ), "used", 1 );
	}
}

function trackOnOwner( owner )
{
	if ( level.trackBouncingBettiesOnOwner === true )
	{
		if ( !isdefined( owner ) )
			return;
		
		if ( !isdefined( owner.activeBouncingBetties ) )
		{
			owner.activeBouncingBetties = [];
		}
		else
		{
			ArrayRemoveValue( owner.activeBouncingBetties, undefined );
		}

		owner.activeBouncingBetties[ owner.activeBouncingBetties.size ] = self;
	}
}

//******************************************************************
//                                                                 *
//                                                                 *
//******************************************************************
function spawnMineMover() // self == betty ent
{
	self endon( "death" );
	self util::waitTillNotMoving();
	self clientfield::set( "bouncingbetty_state", 2 );

	self UseAnimTree( #animtree );
	self SetAnim( %o_spider_mine_deploy, 1.0, 0.0, 1.0 );

	mineMover = spawn( "script_model", self.origin );
	mineMover.angles = self.angles;
	mineMover SetModel( "tag_origin" );
	mineMover.owner = self.owner;
	mineUp = AnglesToUp( mineMover.angles );
	z_offset = GetDvarFloat( "scr_bouncing_betty_killcam_offset", 18.0 );

	mineMover EnableLinkTo();
	mineMover LinkTo( self );

	mineMover.killCamOffset = VectorScale( mineUp, z_offset );
	mineMover.weapon = self.weapon;
	mineMover playsound ("wpn_betty_arm");

	killcamEnt = spawn( "script_model", mineMover.origin + mineMover.killCamOffset );
	killcamEnt.angles = ( 0,0,0 );
	killcamEnt SetModel( "tag_origin" );
	killcamEnt SetWeapon( self.weapon );

	mineMover.killcamEnt = killcamEnt;
	
	self.mineMover = mineMover;

	self thread killMineMoverOnPickup();
}

//******************************************************************
//                                                                 *
//                                                                 *
//******************************************************************
function killMineMoverOnPickup() // self == betty ent
{
	self.mineMover endon( "death" );

	self util::waittill_any( "picked_up", "hacked" );
	
	self killMineMover();
}

//******************************************************************
//                                                                 *
//                                                                 *
//******************************************************************
function killMineMover() // self == betty ent
{
	if ( isdefined( self.mineMover ))
	{
		if ( isdefined( self.mineMover.killcamEnt ) )
		{
			self.mineMover.killcamEnt delete();
		}
		self.mineMover delete();
	}
}

//******************************************************************
//                                                                 *
//                                                                 *
//******************************************************************
function bouncingBettyDetonate( attacker, weapon, target ) // self == betty
{
	if ( IsDefined( weapon ) && weapon.isValid )
	{
		self.destroyedBy = attacker;
		if ( isdefined( attacker ) )
		{
			if ( self.owner util::IsEnemyPlayer( attacker ) )
			{
				attacker challenges::destroyedExplosive( weapon );
				scoreevents::processScoreEvent( "destroyed_bouncingbetty", attacker, self.owner, weapon );
			}
		}

		self bouncingBettyDestroyed();
	}
	else if ( isdefined( self.mineMover ))
	{
		self.mineMover.ignore_team_kills = true;
		self.mineMover SetModel( self.model );
		self.mineMover thread bouncingBettyJumpAndExplode();
		self delete();
	}
	else
	{
		// tagTMR<NOTE>: special case where betty hasn't settled yet but something has triggered a detonate
		// i.e. the moving platforms doors on drone, etc
		self bouncingBettyDestroyed();
	}
}

//******************************************************************
//                                                                 *
//                                                                 *
//******************************************************************
function bouncingBettyDestroyed(  ) // self == betty
{
	PlayFX( level.bettyDestroyedFX, self.origin );
	PlaySoundAtPosition ( "dst_equipment_destroy", self.origin );
	
	if ( isdefined( self.trigger ) )
	{
		self.trigger delete();
	}

	self killMineMover();

	self RadiusDamage( self.origin, 128, 110, 10, self.owner, "MOD_EXPLOSIVE", self.weapon );

	self delete();
}

//******************************************************************
//                                                                 *
//                                                                 *
//******************************************************************
function bouncingBettyJumpAndExplode() // self == script mover spawned at weaponobject location
{	
	jumpDir = VectorNormalize( AnglesToUp( self.angles ) );
	
	if ( jumpDir[2] > level.bettyJumpHeightWallAngleCos )
	{
		jumpHeight = level.bettyJumpHeight;
	}
	else
	{
		jumpHeight = level.bettyJumpHeightWall;
	}
	
	explodePos = self.origin + jumpDir * jumpHeight;
	
	self.killCamEnt MoveTo( explodePos + self.killCamOffset, level.bettyJumpTime, 0, level.bettyJumpTime );

	self clientfield::set( "bouncingbetty_state", 1 );

	wait( level.bettyJumpTime );	

	self thread mineExplode( jumpDir, explodePos );
}


function mineExplode( explosionDir, explodePos )
{
	if ( !isdefined( self ) || !isdefined( self.owner ) )
		return;
	
	self playsound( "wpn_betty_explo" );

	self clientfield::set( "sndRattle", 1 );
	
	{wait(.05);}; // needed or the effect doesn't play
	if ( !isdefined( self ) || !isdefined(self.owner) )
		return;
	
	self CylinderDamage( explosionDir * level.bettyDamageHeight, explodePos, level.bettyDamageRadius, level.bettyDamageRadius, level.bettyDamageMax, level.bettyDamageMin, self.owner, "MOD_EXPLOSIVE", self.weapon );
	self ghost();
	
	wait( 0.1 ); 
	
	
	if ( !isdefined( self ) || !isdefined(self.owner) )
		return;
	
	if ( isdefined( self.trigger ) )
		self.trigger delete();
	
	self.killCamEnt delete();
	self delete();
}

