#using scripts\codescripts\struct;

#using scripts\shared\callbacks_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\flag_shared;
#using scripts\shared\flagsys_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;
#using scripts\shared\visionset_mgr_shared;
#using scripts\shared\weapons\_smokegrenade;
#using scripts\shared\_oob;

#using scripts\shared\abilities\_ability_player;
#using scripts\shared\abilities\_ability_power;
#using scripts\shared\abilities\_ability_util;

    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                       	   	                                                                      	  	  	
       	   	                 	                               	                    	                                 	                                        	                            	                                                                  	                               	  	                               	                    	                                 	                                        	                            	                                                                  	                               	      	     	  

#namespace resurrect;

function autoexec __init__sytem__() {     system::register("gadget_resurrect",&__init__,undefined,undefined);    }

#precache( "fx", "player/fx_plyr_revive" );
#precache( "fx", "player/fx_plyr_revive_demat" );
#precache( "fx", "player/fx_plyr_rejack_light" );
#precache( "fx", "player/fx_plyr_rejack_smoke" );

#precache( "eventstring", "create_rejack_timer" );

function __init__()
{
	clientfield::register( "allplayers", "resurrecting" , 1, 1, "int" );
	clientfield::register( "toplayer", "resurrect_state" , 1, 2, "int" );
	clientfield::register( "clientuimodel", "hudItems.rejack.activationWindowEntered", 1, 1, "int" );
	clientfield::register( "clientuimodel", "hudItems.rejack.rejackActivated", 1, 1, "int" );
	
	ability_player::register_gadget_activation_callbacks( 40, &gadget_resurrect_on, &gadget_resurrect_off );
	ability_player::register_gadget_possession_callbacks( 40, &gadget_resurrect_on_give, &gadget_resurrect_on_take );
	ability_player::register_gadget_flicker_callbacks( 40, &gadget_resurrect_on_flicker );
	ability_player::register_gadget_is_inuse_callbacks( 40, &gadget_resurrect_is_inuse );
	ability_player::register_gadget_is_flickering_callbacks( 40, &gadget_resurrect_is_flickering );
	ability_player::register_gadget_primed_callbacks( 40, &gadget_resurrect_is_primed );
	ability_player::register_gadget_ready_callbacks( 40, &gadget_resurrect_is_ready );
	
	callback::on_connect( &gadget_resurrect_on_connect );
	callback::on_spawned( &gadget_resurrect_on_spawned );
	
	if ( !IsDefined( level.vsmgr_prio_visionset_resurrect ) )
	{
		level.vsmgr_prio_visionset_resurrect = 62;
	}
	
	if ( !IsDefined( level.vsmgr_prio_visionset_resurrect_up ) )
	{
		level.vsmgr_prio_visionset_resurrect_up = 63;
	}
	
	visionset_mgr::register_info( "visionset", "resurrect", 1, level.vsmgr_prio_visionset_resurrect, 16, true, &visionset_mgr::ramp_in_out_thread_per_player_death_shutdown, false );
	visionset_mgr::register_info( "visionset", "resurrect_up", 1, level.vsmgr_prio_visionset_resurrect_up, 16, true, &visionset_mgr::ramp_in_out_thread_per_player_death_shutdown, false );
}

function gadget_resurrect_is_inuse( slot )
{
	return self GadgetIsActive( slot );
}

function gadget_resurrect_is_flickering( slot )
{
	return self GadgetFlickering( slot );
}

function gadget_resurrect_on_flicker( slot, weapon )
{
}

function gadget_resurrect_on_give( slot, weapon )
{
	self.usedResurrect = false;
	self.resurrect_weapon = weapon;
	//self.overridePlayerDeadStatus = &gadget_resurrect_is_player_predead;
	//self.secondaryDeathCamTime = &gadget_resurrect_secondary_deathcam_time;	
}

function gadget_resurrect_on_take( slot, weapon )
{
	// executed when gadget is removed from the players inventory
	
	self.overridePlayerDeadStatus = undefined;
	self.resurrect_weapon = undefined;	
	self.secondaryDeathCamTime = undefined;
	
	self notify("resurrect_taken");
}

//self is the player
function gadget_resurrect_on_spawned()
{
	self clientfield::set_player_uimodel( "hudItems.rejack.activationWindowEntered", 0 );
	self util::show_hud( 1 ); 
	self._disable_proximity_alarms = false;
	// executed when gadget is added to the players inventory
	self flagsys::clear( "gadget_resurrect_ready" );
	self flagsys::clear( "gadget_resurrect_pending" );
	
	if ( self flagsys::get( "gadget_resurrect_activated" ) )
	{
		self thread do_resurrected_on_spawned_player_fx();
		
		self thread resurrect_drain_power();
		
		self flagsys::clear( "gadget_resurrect_activated" ); 
	}
}

function resurrect_drain_power( amount )
{
	if ( isdefined( self.resurrect_weapon ) )
	{
		slot = self GadgetGetSlot( self.resurrect_weapon );
		if ( slot >= 0 && slot < 3 )
		{
			if ( IsDefined( amount ))
			{
				self GadgetPowerChange( slot, amount );
			}
			else
			{
				self GadgetStateChange( slot, self.resurrect_weapon, 3 );
			}			
		}
	}	
}

//self is the player
function gadget_resurrect_on_connect()
{
	// setup up stuff on player connect
}

function gadget_resurrect_on( slot, weapon )
{
	// excecutes when the gadget is turned on
}

function watch_smoke_detonate()
{
	self endon( "player_input_suicide" );
	self endon( "player_input_revive" );
	self endon( "disconnect" );
	self endon( "death" );
	level endon("game_ended");
	
	while( 1 ) 
	{
		if( ( ( self IsPlayerSwimming() ) || ( self isOnGround() ) ) && !( self iswallrunning() ) && !( self istraversing() ) )
		{
			smoke_weapon = GetWeapon( "gadget_resurrect_smoke_grenade" );
			stat_weapon = GetWeapon( "gadget_resurrect" );
			smokeEffect = smokegrenade::smokeDetonate( self, stat_weapon, smoke_weapon, self.origin, 128, 5, 4 );
			smokeEffect thread watch_smoke_effect_watch_suicide( self );
			smokeEffect thread watch_smoke_effect_watch_resurrect( self );
			smokeEffect thread watch_smoke_death( self );
			return;
		}
		
		{wait(.05);};
	}
}

function watch_smoke_death( player ) // self is effect
{
	self endon( "death" );
	
	player util::waittill_any_timeout( 5, "disconnect", "death" );
	
	self delete();
}

function watch_smoke_effect_watch_suicide( player ) // self is effect
{
	self endon( "death" );
	
	player waittill ( "player_input_suicide" );
	
	self delete();
}

function watch_smoke_effect_watch_resurrect( player ) // self is effect
{
	self endon( "death" );
	
	player waittill ( "player_input_revive" );
	
	wait( .5 );
	
	self delete();
}

function gadget_resurrect_is_primed( slot, weapon ) // self == player
{
	if ( isdefined( self.resurrect_not_allowed_by ) )
		return;

	self StartResurrectViewAngleTransition();
	self.lastWaterDamageTime = GetTime();
	self._disable_proximity_alarms = true;
	self thread watch_smoke_detonate();
	self util::show_hud( 0 ); 
	visionset_mgr::activate( "visionset", "resurrect", self, ( 1.4 ), ( 4.0 ), ( .25 ) );
	self clientfield::set_to_player( "resurrect_state", 1 );
	self shellshock( "resurrect", 4.0 + 1.4, false );
}

function gadget_resurrect_is_ready( slot, weapon )
{
	return; 

	self flagsys::set( "gadget_resurrect_ready" );
	self thread resurrect_breadcrumbs( slot );
	self thread resurrect_watch_for_death( slot,weapon );
}

function gadget_resurrect_start( slot, weapon )
{
	wait 0.1;
	self GadgetSetActivateTime( slot, GetTime() );
	self thread resurrect_delay( weapon );
}

function gadget_resurrect_off( slot, weapon )
{
	self notify( "gadget_resurrect_off" );
	
	// excecutes when the gadget is turned off
}

function resurrect_delay( weapon )
{
	self endon ( "disconnect" );
	self endon("game_ended");
	self endon ( "death" );
	
	self notify( "resurrect_delay" );
	self endon( "resurrect_delay" );
	
}

function overrideSpawn(isPredictedSpawn)
{	
	if ( !self flagsys::get( "gadget_resurrect_ready" ) )
		return false;
	if ( !self flagsys::get( "gadget_resurrect_activated" ) )
		return false;

	if (!IsDefined(	self.resurrect_origin ))
	{
		self.resurrect_origin = self.origin;
		self.resurrect_angles = self.angles;
	}
	
	return true;
}


function is_jumping()
{
	// checking PMF_JUMPING in code would give more accurate results
	ground_ent = self GetGroundEnt();
	return (!isdefined(ground_ent));
}


function player_position_valid()
{
	//if ( self IsWallRunning() || self is_jumping() )
		//return false;
	if ( self clientfield::get_to_player( "out_of_bounds" ) )
		return false;
	
	return true;
}


function resurrect_breadcrumbs(slot)
{
	self endon("disconnect");
	self endon("game_ended");
	self endon("resurrect_taken");
	self.resurrect_slot = slot;

	while(1)
	{
		if (IsAlive(self) && self player_position_valid() )
		{
			self.resurrect_origin = self.origin;
			self.resurrect_angles = self.angles;
		}
		wait 1;
	}
	
}


function glow_for_time( time )
{
	self endon("disconnect");
	self clientfield::set( "resurrecting", 1 );
	wait time;
	self clientfield::set( "resurrecting", 0 );
}

function wait_for_time( time, msg )
{
	self endon("disconnect");
	self endon("game_ended");
	
	self endon(msg);
	wait time;
	self notify(msg);
}

function wait_for_activate( msg )
{
	self endon("disconnect");
	self endon("game_ended");
	
	self endon(msg);
	while(1)
	{
		if ( self OffhandSpecialButtonPressed() )
		{
			self flagsys::set( "gadget_resurrect_activated" ); 
			self notify(msg);
		}
		{wait(.05);};
	}
}

function bot_wait_for_activate( msg, time )
{
	self endon("disconnect");
	self endon("game_ended");
	
	self endon(msg);
	
	if ( !self util::is_bot() )
	{
		return;
	}	
	
	time = int( time + 1 );
	
	randWait = RandomInt( time );
	
	wait randWait;
	
	self flagsys::set( "gadget_resurrect_activated" ); 
	self notify(msg);	
}

function do_resurrect_hint_fx()
{
	offset = (0,0,40);
	fxOrg = spawn( "script_model", self.resurrect_origin + offset );
	fxOrg SetModel( "tag_origin" );

	fx = PlayFxOnTag( "player/fx_plyr_revive", fxOrg, "tag_origin" );
	
	self waittill("resurrect_time_or_activate");	
	
	fxOrg delete();
}

function do_resurrected_on_dead_body_fx()
{
	if ( isdefined( self.body ) )
	{
		fx = PlayFx( "player/fx_plyr_revive_demat", self.body.origin );
		
		self.body NotSolid();
		self.body Ghost();
	}	
}

function do_resurrected_on_spawned_player_fx()
{
	playsoundatposition( "mpl_resurrect_npc", self.origin );
	
	fx = PlayFx( "player/fx_plyr_rejack_light", self.origin );
}

function resurrect_watch_for_death( slot, weapon )
{
	self endon("disconnect");
	self endon("game_ended");

	self waittill("death"); 
	
	resurrect_time = 3;
	
	if ( IsDefined( weapon.gadget_resurrect_duration) )
	{
		resurrect_time = weapon.gadget_resurrect_duration / 1000.0;
	}
	
	self.usedResurrect = false;
	
	self flagsys::clear( "gadget_resurrect_activated" );
	self flagsys::set( "gadget_resurrect_pending" );
	self.resurrect_available_time = GetTime();
	
	self thread wait_for_time(resurrect_time,"resurrect_time_or_activate");
	
	self thread wait_for_activate("resurrect_time_or_activate");
	self thread bot_wait_for_activate("resurrect_time_or_activate", resurrect_time );
	
	self thread do_resurrect_hint_fx();
	
	self waittill("resurrect_time_or_activate");
	
	self flagsys::clear( "gadget_resurrect_pending" );
	
	if ( self flagsys::get( "gadget_resurrect_activated" ) )
	{
		self thread do_resurrected_on_dead_body_fx();
		
		self notify ( "end_death_delay" );
		self notify ( "end_killcam" );
		
		self.cancelKillcam = true;
		self.usedResurrect = true;
		
		self notify ( "end_death_delay" );
		self notify( "force_spawn" );
		
		if ( !( isdefined( true ) && true ) )
		{
			self.pers["resetMomentumOnSpawn"] = false;
		}
		
		if ( isdefined( level.playGadgetSuccess ) )
	    {
			self [[ level.playGadgetSuccess ]]( weapon, "resurrectSuccessDelay" );
		}
		
		//self thread glow_for_time( 7 );
	}
}



function gadget_resurrect_delay_updateTeamStatus()
{
	if ( self flagsys::get( "gadget_resurrect_ready" ) )
	{
		return true;
	}
	
	return false;
}

function gadget_resurrect_is_player_predead()
{
	should_not_be_dead = false;
	if ( self.sessionstate == "playing" && isAlive( self ) )
		should_not_be_dead = true;
		
	if ( self flagsys::get( "gadget_resurrect_pending" ) )
	{
		return true;
	}
	
	return should_not_be_dead;
}

function gadget_resurrect_secondary_deathcam_time()
{
	if ( self flagsys::get( "gadget_resurrect_pending" ) && IsDefined(self.resurrect_available_time) )
	{
		resurrect_time = 3000;
		
		weapon = self.resurrect_weapon;	
		if ( IsDefined(weapon.gadget_resurrect_duration) )
			resurrect_time = weapon.gadget_resurrect_duration;
		
		time_left = resurrect_time - ( GetTime() - self.resurrect_available_time );
		
		if ( time_left > 0 )
		{
			return time_left / 1000.0;
		}
	}
	
	return 0.0;
}
	
function enter_rejack_standby() // self == player
{
	self endon( "disconnect" );
	self endon( "death" );
	level endon("game_ended");

	self.rejack_activate_requested = false;
	
	if( isDefined( level.resetPlayerScorestreaks ) )
	{
		[[level.resetPlayerScorestreaks]]( self );
	}
	
	self init_rejack_ui();
	self thread watch_rejack_activate_requested();
	self thread watch_rejack_suicide();
	wait 1.4;
	self thread watch_rejack_activate();
	self thread watch_rejack_timeout();
	self thread watch_bad_trigger_touch();
}

function rejack_suicide()
{
	self notify( "heroAbility_off" );
	visionset_mgr::deactivate( "visionset", "resurrect", self );
	self thread remove_rejack_ui();
	self util::show_hud( 1 ); 
	player_suicide();
}

function watch_bad_trigger_touch()
{
	self endon( "player_input_revive" );
	self endon( "player_input_suicide" );
	self endon( "disconnect" );
	self endon( "death" );
	level endon("game_ended");
			
	a_killbrushes = GetEntArray( "trigger_hurt","classname" );

	while( 1 )
	{
		a_killbrushes = GetEntArray( "trigger_hurt","classname" );

		for ( i = 0; i < a_killbrushes.size; i++)
		{
			if ( self IsTouching( a_killbrushes[ i ] ) )
			{		
				if ( !a_killbrushes[ i ] IsTriggerEnabled() )
				{
					continue;
				}

				self rejack_suicide();
			}
		}
		
		if( self oob::IsTouchingAnyOOBTrigger() )
		{
			self rejack_suicide();
		}
	
		{wait(.05);};
	}
}

function watch_rejack_timeout() // self == player
{
	self endon( "player_input_revive" );
	self endon( "player_input_suicide" );
	self endon( "disconnect" );
	self endon( "death" );
	level endon("game_ended");
	
	wait 4.0;
	
	self playsound ("mpl_rejack_suicide_timeout"); 
	self thread resurrect_drain_power( -30 );
	self rejack_suicide();
}

function watch_rejack_suicide() // self == player
{
	self endon( "player_input_revive" );
	self endon( "disconnect" );
	self endon( "death" );
	level endon("game_ended");

	while ( self UseButtonPressed())
	{
		wait 1;
	}

	if ( ( isdefined( self.laststand ) && self.laststand ))
	{
		startTime = GetTime();
		while ( true )
		{
			if( !( self usebuttonpressed() ) )
			{
				startTime = GetTime();
			}
			
			if( startTime + 500 < GetTime() )
			{
				self rejack_suicide();
				self playsound ("mpl_rejack_suicide");
				return;
			}
			
			wait .01;
		}
	}
}

function reload_clip_on_stand()
{
	weapons = self GetWeaponsListPrimaries();
	for ( i = 0; i < weapons.size; i++ )
	{
		self ReloadWeaponAmmo( weapons[i] );
	}
}

function watch_rejack_activate_requested()
{
	self endon( "player_input_suicide" );
	self endon( "player_input_revive" );
	self endon( "disconnect" );
	self endon( "death" );
	level endon("game_ended");
	
	while ( self OffhandSpecialButtonPressed())
	{
		{wait(.05);};
	}
	
	self.rejack_activate_requested = false;
	while( !self.rejack_activate_requested )
	{
		if( self OffhandSpecialButtonPressed() )
		{
			self.rejack_activate_requested = true;
		}
		{wait(.05);};
	}
}

function watch_rejack_activate() // self == player
{
	self endon( "player_input_suicide" );
	self endon( "disconnect" );
	self endon( "death" );
	level endon("game_ended");
	
	if ( ( isdefined( self.laststand ) && self.laststand ))
	{
		while ( true )
		{
			{wait(.05);};

			if( ( isdefined( self.rejack_activate_requested ) && self.rejack_activate_requested ) )
			{
				self notify( "player_input_revive" );
				if( isDefined( level.start_player_health_regen ) )
				{
					self thread [[level.start_player_health_regen]]();	// Manually restart the health regen as it gets ended because of the player killed
				}
				self._disable_proximity_alarms = false;
				self thread do_resurrected_on_spawned_player_fx();
				self thread resurrect_drain_power();				
				self thread rejack_ui_activate();
				visionset_mgr::deactivate( "visionset", "resurrect", self );
				visionset_mgr::activate( "visionset", "resurrect_up", self, ( .35 ), ( .1 ), ( .2 ) );
				self clientfield::set_to_player( "resurrect_state", 2 );
				self stopshellshock();
				//self SetEverHadWeaponAll( false ); 
				self reload_clip_on_stand();
				level notify( "hero_gadget_activated", self );
				self notify( "hero_gadget_activated" );
				return;
			}
		}
	}
}

function init_rejack_ui()
{
	self clientfield::set_player_uimodel( "hudItems.rejack.activationWindowEntered", 1 );
	self LUINotifyEvent( &"create_rejack_timer", 1, GetTime() + ( int( 4.0 * 1000 ) ) );
	self clientfield::set_player_uimodel( "hudItems.rejack.rejackActivated", 0 );	
}

function remove_rejack_ui()
{
	self endon( "disconnect" );
	
	wait 1.5;
	self clientfield::set_player_uimodel( "hudItems.rejack.activationWindowEntered", 0 );
	self util::show_hud( 1 ); 
}

function rejack_ui_activate()
{
	self clientfield::set_player_uimodel( "hudItems.rejack.rejackActivated", 1 );
	self thread remove_rejack_ui();
}

function player_suicide() // self == player
{
	self._disable_proximity_alarms = false;
	self notify( "player_input_suicide" );
	self clientfield::set_to_player( "resurrect_state", 0 );
	self thread resurrect_drain_power( -30 );
}