::BotRocketJump <-
{
	OnGameEvent_recalculate_holidays = function(params) {
	    BotRocketJump.CleanUp();
	    delete::BotRocketJump;
	}
    OnGameEvent_mvm_wave_complete = function(params) {
        BotRocketJump.CleanUp();
        delete::BotRocketJump;
    }
	
	CleanUp = function()
    {
        for (local i = 1; i <= MaxClients().tointeger(); i++)
        {
            local player = PlayerInstanceFromIndex(i);
            if (player != null && player.GetScriptThinkFunc() == "RocketJumpThink")
            {
                AddThinkToEnt(player, null);
            }
        }
    }
	
	GetWeaponInSlot = function(player, slot)
    {
        local size = NetProps.GetPropArraySize(player, "m_hMyWeapons");
        for (local i = 0; i < size; i++)
        {
            local weapon = NetProps.GetPropEntityArray(player, "m_hMyWeapons", i)
            if (weapon != null && weapon.IsValid() && weapon.GetSlot() == slot)
            {
                return weapon;
            }
        }
        
        return null;
    }
	
	function OnGameEvent_player_spawn(params)
    {
        local player = GetPlayerFromUserID(params.userid);
        if (!player.IsBotOfType(Constants.EBotType.TF_BOT_TYPE))
		{
			return;
		}
        
        EntFireByHandle(player, "RunScriptCode", "BotRocketJump.CheckTags(self)", 0.1, null, null);
    }
	
	CheckTags = function(player)
    {
    	player.ValidateScriptScope();
    	local scope = player.GetScriptScope();
		if (player.HasBotTag("rocketjump"))
		{
			scope.rocketJumpAt <- -1.0;
			scope.RocketJumpThink <- function()
			{
				if (self.InCond(Constants.ETFCond.TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED))
                {
                    return -1;
                }
				
				local primary = BotRocketJump.GetWeaponInSlot(self, 0);
				if (primary == null || primary != self.GetActiveWeapon())
				{
					return -1;
				}
				
				local blastJump = self.InCond(Constants.ETFCond.TF_COND_BLASTJUMPING);
				if (!blastJump)
				{
					if (!self.HasBotAttribute(Constants.FTFBotAttributeType.SUPPRESS_FIRE))
					{
						// no shooting until it's time to jump
						self.AddBotAttribute(Constants.FTFBotAttributeType.SUPPRESS_FIRE);
					}
				}
				else if (blastJump && self.HasBotAttribute(Constants.FTFBotAttributeType.SUPPRESS_FIRE))
				{
					self.RemoveBotAttribute(Constants.FTFBotAttributeType.SUPPRESS_FIRE);
				}
				
				local clip = primary.Clip1();
				local maxClip = primary.GetMaxClip1();
				if (self.HasBotAttribute(Constants.FTFBotAttributeType.HOLD_FIRE_UNTIL_FULL_RELOAD))
				{
					if (clip < maxClip)
					{
						return -1;
					}
				}
				
				// there needs to be adequate space above us
				local trace =
				{
					start  = self.EyePosition()
					end    = self.EyePosition() + Vector(0, 0, 800)
					hullmin = player.GetBoundingMins()
					hullmax = player.GetBoundingMaxs()
					mask   = 81931 // MASK_PLAYERSOLID_BRUSHONLY
					ignore = self
				};
				
				TraceHull(trace);
				if (trace.hit)
				{
					return 0.2;
				}
				
				if (!blastJump && scope.rocketJumpAt <= -1.0)
				{
					scope.rocketJumpAt = Time() + 4.0;
				}
				
				if (!blastJump && Time() >= scope.rocketJumpAt)
				{
					// look straight down
					// jump and shoot a rocket
					NetProps.SetPropInt(self, "m_afButtonForced", 
						NetProps.GetPropInt(self, "m_afButtonForced") | Constants.FButtons.IN_JUMP);
					NetProps.SetPropInt(self, "m_nButtons", 
						NetProps.GetPropInt(self, "m_nButtons") | Constants.FButtons.IN_JUMP);
						
					EntFireByHandle(self, "RunScriptCode", 
						"local scope=self.GetScriptScope();local angles=self.EyeAngles();angles.x=90.0;"
						+ "self.SnapEyeAngles(angles);self.RemoveBotAttribute(Constants.FTFBotAttributeType.SUPPRESS_FIRE);"
						+"self.PressFireButton(0.5);scope.rocketJumpAt=-1.0;",
						0.2, null, null);
					
					return 1;
				}
				else if (!blastJump && !self.HasBotAttribute(Constants.FTFBotAttributeType.SUPPRESS_FIRE))
				{
					self.AddBotAttribute(Constants.FTFBotAttributeType.SUPPRESS_FIRE);
				}
				
				return -1;
			}
			
			AddThinkToEnt(player, "RocketJumpThink");
		}
    }
}
__CollectGameEventCallbacks(BotRocketJump);