#include "gen_bot_header.h"

//harSens: Linux compile fix
extern CLeftOutput lcout;

// ==================================================================
// Code of CBot - Begin
// ==================================================================

short CBot::GetBestEscapeSwoopDir(bool CheckBackwards)
{
	Vector v_src = pev->origin;
	Vector v_end;

	TraceResult tr1, tr2, tr3, tr4, tr5;

	v_end = v_src + gpGlobals->v_up * 750;
	UTIL_TraceHull(v_src,v_end,dont_ignore_monsters,human_hull,pev->pContainingEntity,&tr1);
	
	v_end = v_src - gpGlobals->v_up * 750;
	UTIL_TraceHull(v_src,v_end,dont_ignore_monsters,human_hull,pev->pContainingEntity,&tr2);

	v_end = v_src + gpGlobals->v_right * 750;
	UTIL_TraceHull(v_src,v_end,dont_ignore_monsters,human_hull,pev->pContainingEntity,&tr3);

	v_end = v_src - gpGlobals->v_right * 750;
	UTIL_TraceHull(v_src,v_end,dont_ignore_monsters,human_hull,pev->pContainingEntity,&tr4);

	tr5.flFraction = 0.0;

	if (CheckBackwards)
	{
		v_end = v_src - gpGlobals->v_forward * 750;
		UTIL_TraceHull(v_src,v_end,dont_ignore_monsters,human_hull,pev->pContainingEntity,
					   &tr5);
	}

	int SwoopUpVal = int(tr1.flFraction*10.0);
	int SwoopDownVal = int(tr2.flFraction*10.0);
	int SwoopRightVal = int(tr3.flFraction*10.0);
	int SwoopLeftVal = int(tr4.flFraction*10.0);
	int SwoopBackVal = int(tr5.flFraction*10.0);

	if ((UTIL_IsValidPlayer(m_pBotEnemy)) &&
		(m_pBotEnemy->pev->movetype == MOVETYPE_PLAYERSWOOP))
	{
		Vector v_src = pev->origin;
		Vector v_predict = PredictEntityPos(m_pBotEnemy, 1.0);
		Vector v_dir;

		float DirDist = 0.0;
		float PredictDist = GetDistance(v_predict);

		UTIL_MakeVectors(pev->v_angle);

		// Predict if enemy get closer when we swoop back...
		v_dir = v_src - gpGlobals->v_forward * 100;
		DirDist = GetDistance(v_dir);

		if ((DirDist-200.0) < PredictDist)
			SwoopBackVal--;

		// Predict if enemy get closer when we swoop up...
		v_dir = v_src + gpGlobals->v_up * 100;
		DirDist = GetDistance(v_dir);

		if ((DirDist-200.0) < PredictDist)
			SwoopUpVal--;

		// Predict if enemy get closer when we swoop down...
		v_dir = v_src - gpGlobals->v_up * 100;
		DirDist = GetDistance(v_dir);

		if ((DirDist-200.0) < PredictDist)
			SwoopDownVal--;

		// Predict if enemy get closer when we swoop right...
		v_dir = v_src + gpGlobals->v_right * 100;
		DirDist = GetDistance(v_dir);

		if ((DirDist-200.0) < PredictDist)
			SwoopRightVal--;

		// Predict if enemy get closer when we swoop left...
		v_dir = v_src - gpGlobals->v_right * 100;
		DirDist = GetDistance(v_dir);

		if ((DirDist-200.0) < PredictDist)
			SwoopLeftVal--;
	}

	if (m_bMadePlayerList)
		MakePlayerList();

	if (m_bPlayerCount > 0)
	{
		int i;

		// Sort the direction where the least players are
		for (i=0;i<m_bPlayerCount;i++)
		{
			int EntDir = UTIL_EntDir(this, m_pPlayerList[i]->pev->origin);

			if (EntDir & dir_back)
				SwoopBackVal--;
			if (EntDir & dir_left)
				SwoopLeftVal--;
			if (EntDir & dir_right)
				SwoopRightVal--;
			if (EntDir & dir_up)
				SwoopUpVal--;
			if (EntDir & dir_down)
				SwoopDownVal--;
		}
	}

	if ((SwoopUpVal > SwoopDownVal) && (SwoopUpVal > SwoopRightVal) &&
		(SwoopUpVal > SwoopLeftVal) && (SwoopUpVal > SwoopBackVal))
		return dir_up;
	else if ((SwoopDownVal > SwoopUpVal) && (SwoopDownVal > SwoopRightVal) &&
			 (SwoopDownVal > SwoopLeftVal) && (SwoopDownVal > SwoopBackVal))
		return dir_down;
	else if ((SwoopRightVal > SwoopUpVal) && (SwoopRightVal > SwoopDownVal) &&
			 (SwoopRightVal > SwoopLeftVal) && (SwoopRightVal > SwoopBackVal))
		return dir_right;
	else if ((SwoopLeftVal > SwoopUpVal) && (SwoopLeftVal > SwoopDownVal) &&
			 (SwoopLeftVal > SwoopRightVal) && (SwoopLeftVal > SwoopBackVal))
		return dir_left;
	else if ((SwoopBackVal > SwoopUpVal) && (SwoopBackVal > SwoopDownVal) &&
			 (SwoopBackVal > SwoopRightVal) && (SwoopBackVal > SwoopLeftVal))
		return dir_back;

	// if no 'best' direction, return a random one
	int RandNr;

	if (CheckBackwards)
		RandNr = RANDOM_LONG(0, 4);
	else
		RandNr = RANDOM_LONG(0, 3);

	switch(RandNr)
	{
	case 0:
		return dir_up;
		break;
	case 1:
		return dir_down;
		break;
	case 2:
		return dir_right;
		break;
	case 3:
		return dir_left;
		break;
	case 4:
		return dir_back;
	}

	return dir_up; // to avoid a warning message :|
}

bool CBot::BotShouldFallDown()
{
	if ((m_sDangerLevel < DANGER_MEDIUM_MIN_VAL) || (m_sDangerLevel >= DANGER_HARD_MAX_VAL))
		return false;

	if (RANDOM_LONG(1, 100) > m_pPersonality->stopfly_percent)
		return false;

	if (((m_iDangerType == DangerEnemy) || (m_iDangerType == DangerCurrentEnemy)) &&
		(m_pBotEnemy))
	{
		float EnemyDist = GetDistance(m_pBotEnemy->pev->origin);

		if (EnemyDist < 1000.0)
		{
			if (m_pBotEnemy->pev->origin.z < (pev->origin.z - 350.0f))
				return false;
		}
	}

	if (GetCollisionDist(dir_down, MIN_DIST_TO_FALL_DOWN) < MIN_DIST_TO_FALL_DOWN)
		return false;

	return true;
}

bool CBot::DangerousPlForBot(long EnemyPl)
{
	long DangerousPl = EnemyPl;

	if (m_pPersonality->aggression_level == Defensive) // its really soon dangerous
		DangerousPl -= RANDOM_LONG(100000, 250000);
	else if (m_pPersonality->aggression_level == Normal)
		DangerousPl -= RANDOM_LONG(550000, 1000000);
	else if (m_pPersonality->aggression_level == Aggressive)
		DangerousPl -= RANDOM_LONG(750000, 1250000);

	return (m_iPowerLevel < DangerousPl);
}

int CBot::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
{
	int TookDamage = CBasePlayer::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
	if (TookDamage)
	{
		m_iDamageTaken = flDamage;
		m_fLastHitTime = gpGlobals->time;
	}

	return TookDamage;
}

bool CBot::BotCanBeamJump(bool AttackIsReleased)
{
	CBaseEntity *pAttack = NULL;
	Vector v_src;
	Vector v_end;

	// Don't beam jump when the bot is a db defender
	if ((BotManager.IsDBMode()) && (m_eBotDBType == DB_DEFENDER))
		return false;

	if (AttackIsReleased)
	{
		if (m_fControl == false)
			return false;

		pAttack = UTIL_GetLastAttackFromPlayer(this);
		if (!pAttack)
		{
			return false;
		}
		v_src = pAttack->pev->origin;
	}
	else
	{
		v_src = pev->origin;
	}

	// Weee lag :)
	Vector v_nearest = GetNearestCollision((pAttack) ? pAttack : this, 200.0f);

	if (v_nearest != g_vecZero)
	{
		m_vBeamJumpSpot = v_nearest;
		AimToVec(v_nearest);
		return true;
	}

	return false;
}

EAttackType CBot::ClassifyAttack(const char *szAttackName)
{
	if ((FStrEq(szAttackName,"kiblast")) || (FStrEq(szAttackName,"scattershot")) ||
		(FStrEq(szAttackName,"renzoku")))
		return ATTACK_KIBLAST;

	if ((FStrEq(szAttackName,"blueattack")) || (FStrEq(szAttackName,"burningattack")) ||
	    (FStrEq(szAttackName,"greenattack")) || (FStrEq(szAttackName,"purpleattack")) ||
		(FStrEq(szAttackName,"yellowattack")))
		return ATTACK_LIGHTBEAM;

	if ((FStrEq(szAttackName,"masenko")) || (FStrEq(szAttackName,"powerbeam")))
		return ATTACK_MEDIUMBEAM;
 
	if ((FStrEq(szAttackName,"kamehameha")) || (FStrEq(szAttackName,"gallitgun")) ||
		(FStrEq(szAttackName,"mouthblast")) || (FStrEq(szAttackName,"finalflash")))
		return ATTACK_HEAVYBEAM;

	if ((FStrEq(szAttackName,"bigbang")) || (FStrEq(szAttackName,"finishingbuster")) ||
		(FStrEq(szAttackName,"Spirit Bomb")) || (FStrEq(szAttackName,"Special Beam Cannon")) ||
		(FStrEq(szAttackName,"Death Ball")) || (FStrEq(szAttackName,"shieldattack")) ||
		(FStrEq(szAttackName,"Kame Torpedo")) || (FStrEq(szAttackName,"Scattering Beam")))
		return ATTACK_HEAVYPROJECTILE;

	if ((FStrEq(szAttackName,"Destructo Disc")) || (FStrEq(szAttackName,"Frieza Disc")))
		return ATTACK_DISC;
				
	if (FStrEq(szAttackName,"rock"))
		return ATTACK_TELEKINESIS;

	return ATTACK_NONE;
}

void CBot::SenseSurroundingAttacks(danger_info_s &DangerInfo)
{
	if (m_fAttackSenseDelay > gpGlobals->time)
		return;

	m_fAttackSenseDelay = gpGlobals->time + 0.1f; // Don't do this every frame(kinda CPU intensive)

	// Declare some shortcuts...
	CBaseEntity *pAttack = NULL;
	CBasePlayer *pPlayer;
	Vector v_end;

	float flDist;
	EAttackType AttackType;

	short HeadPercent;

	short AttackVal;
	short HighestAttackVal = 0;
	
	float TeleVal, SwoopVal, BlockVal, JumpVal, FallDownVal;

	byte DangerHeadPercent = MIN_DANGER_HEAD_PERCENT;

	if (m_pPersonality->aggression_level == Defensive)
		DangerHeadPercent *= 0.85f;
	else if (m_pPersonality->aggression_level == Aggressive)
		DangerHeadPercent *= 1.2;

	bool CheckOnlyFOV = (m_bSkillNr > 0);

	while ((pAttack = UTIL_FindEntityByString(pAttack, "globalname", "magic_attack")) != NULL)
	{
		if (IsNull(pAttack->pev->owner))
			continue; // Since we want some info about the owner aswell...

		if (g_teamplay)
		{
			if (pAttack->pev->owner->v.team == pev->team)
			{
				continue;
			}
		}

		if (pAttack->pev->velocity.Length() < 10.0f)
			continue; // Attack is not scary

		HeadPercent = UTIL_GetHeadingPercentage(this, pAttack);

		if (HeadPercent < DangerHeadPercent)
			continue;

		v_end = pAttack->pev->origin;
		flDist = GetDistance(v_end);

		if (flDist > 2000.0f)
			continue;

		if ((flDist > 250.0f) && (!EntIsInFOV(pAttack)))
			continue;

		// Can the bot 'see' the attack?
		if (FVisible(pAttack->pev->origin) == false)
			continue; // Nope

		// hmm okay we found an attack wich might be hostile... now determine how hostile it is

		// Reset all temp vars
		AttackVal = 0;
		TeleVal = m_pPersonality->teleport_percent;
		SwoopVal = m_pPersonality->swoop_percent;
		BlockVal = m_pPersonality->block_percent;
		JumpVal = m_pPersonality->jump_percent;
		FallDownVal = m_pPersonality->stopfly_percent;

		// First look how close this attack is
		if (flDist < 150.0f) // Argh
		{
			AttackVal += 160;
			TeleVal *= 1.7f;
			SwoopVal *= 0.01f;
			BlockVal *= 1.5f;
			JumpVal *= 0.01f;
			FallDownVal *= 0.01f;
		}
		else if (flDist < 350.0f)
		{
			AttackVal += 145;
			TeleVal *= 1.5f;
			SwoopVal *= 0.02f;
			BlockVal *= 1.15f;
			JumpVal *= 0.1f;
			FallDownVal *= 0.1f;
		}
		else if (flDist < 500.0f)
		{
			AttackVal += 125;
			TeleVal *= 1.25f;
			SwoopVal *= 0.15f;
			JumpVal *= 0.3f;
			FallDownVal *= 0.15f;
		}
		else if (flDist < 750.0f)
		{
			AttackVal += 100;
			TeleVal *= 1.1f;
			SwoopVal *= 0.30f;
			BlockVal *= 0.95f;
			JumpVal *= 0.55f;
			FallDownVal *= 0.2f;
		}
		else if (flDist < 875.0f)
		{
			AttackVal += 85;
			SwoopVal *= 0.5f;
			BlockVal *= 0.95f;
			JumpVal *= 0.7f;
			FallDownVal *= 0.4f;
		}
		else if (flDist < 1000.0f)
		{
			AttackVal += 75;
			SwoopVal *= 0.85f;
			BlockVal *= 0.9f;
			FallDownVal *= 0.75f;
		}
		else if (flDist < 1250.0f)
		{
			AttackVal += 60;
			BlockVal *= 0.8f;
			JumpVal *= 0.85f;
		}
		else if (flDist < 1500.0f)
		{
			AttackVal += 40;
			BlockVal *= 0.6f;
			JumpVal *= 0.6f;
		}
		else if (flDist < 2000.0f)
		{
			AttackVal += 25;
			TeleVal *= 0.95f;
			SwoopVal *= 1.05f;
			BlockVal *= 0.3f;
			JumpVal *= 0.5f;
			FallDownVal *= 1.05f;
		}

		pPlayer = (CBasePlayer *)CBaseEntity::Instance(pAttack->pev->owner);
		if (!pPlayer)
			continue;

		// Now determine how much stronger the owner of this attack is

		// Determine the pl difference between the owner and the bot
		long PlDiff = pPlayer->m_iPowerLevel - m_iPowerLevel;

		if (PlDiff > 5000000)
		{
			AttackVal += 75;
			TeleVal *= 1.75f;
			BlockVal *= 0.01f;
			JumpVal *= 0.9f;
			FallDownVal *= 0.9f;
		}
		else if (PlDiff > 3000000)
		{
			AttackVal += 65;
			TeleVal *= 1.55f;
			BlockVal *= 0.01f;
			JumpVal *= 0.95f;
			FallDownVal *= 0.95f;
		}
		else if (PlDiff > 2500000)
		{
			AttackVal += 55;
			TeleVal *= 1.2f;
			BlockVal *= 0.01f;
		}
		else if (PlDiff > 1750000)
		{
			AttackVal += 35;
			BlockVal *= 0.1f;
		}
		else if (PlDiff > 1250000)
		{
			AttackVal += 20;
			BlockVal *= 0.45f;
		}
		else if (PlDiff > 800000)
		{
			AttackVal += 10;
			BlockVal *= 0.75f;
		}
		
		// Now determine how much damage this attack has
		if (pAttack->pev->dmg > 135.0f)
		{
			AttackVal += 40;
			TeleVal *= 1.75f;
			SwoopVal *= 0.9f;
			BlockVal *= 0.5f;
			JumpVal *= 0.9f;
			FallDownVal *= 0.9f;
		}
		else if (pAttack->pev->dmg > 85.0f)
		{
			AttackVal += 25;
			TeleVal *= 1.45f;
			BlockVal *= 0.9f;
		}
		else if (pAttack->pev->dmg > 65.0f)
		{
			AttackVal += 10;
			TeleVal *= 1.2f;
		}
		else if (pAttack->pev->dmg > 40.0f)
		{
			AttackVal += 4;
		}

		if (pAttack->pev->dmg > pev->health)
		{
			AttackVal += 60;
			TeleVal *= 1.45f;
			BlockVal *= 0.5f;
		}


		// Okay, now how much health has this bot?
		if (pev->health < 10)
		{
			AttackVal += 45;
			TeleVal *= 1.55f;
			SwoopVal *= 0.9f;
			BlockVal *= 0.01f;
			JumpVal *= 0.8f;
			FallDownVal *= 0.75f;
		}
		else if (pev->health < 25)
		{
			AttackVal += 25;
			TeleVal *= 1.25f;
			SwoopVal *= 0.95f;
			BlockVal *= 0.05f;
			JumpVal *= 0.95f;
			FallDownVal *= 0.9f;
		}
		else if (pev->health < 35)
		{
			AttackVal += 10;
			BlockVal *= 0.05f;
		}

		// Now see how 'much' this attack heads to the bot
		if (HeadPercent < 90)
			AttackVal -= 35;
		else if (HeadPercent < 95)
			AttackVal -= 12;

		// What is this for attack type?
		AttackType = ClassifyAttack(STRING(pAttack->pev->classname));

		if (AttackType == ATTACK_KIBLAST)
		{
			AttackVal -= 70;
			TeleVal *= 0.35f;
			SwoopVal *= 0.35f;
			BlockVal *= 1.75f;
			JumpVal *= 0.80f;
		}
		else if (AttackType == ATTACK_LIGHTBEAM)
		{
			AttackVal -= 50;
			TeleVal *= 0.85f;
			SwoopVal *= 0.85f;
			BlockVal *= 1.25f;
			JumpVal *= 0.85f;
			FallDownVal *= 0.85f;
		}
		else if (AttackType == ATTACK_MEDIUMBEAM)
		{
			AttackVal -= 35;
			SwoopVal *= 0.95f;
		}
		else if (AttackType == ATTACK_HEAVYBEAM)
		{
			TeleVal *= 1.1f;
			SwoopVal *= 1.1f;
			BlockVal *= 0.80f;
		}
		else if (AttackType == ATTACK_HEAVYPROJECTILE)
		{
			TeleVal *= 1.1f;
			SwoopVal *= 1.15f;
			BlockVal *= 0.70f;
		}
		else if (AttackType == ATTACK_DISC)
		{
			AttackVal += 5;
			TeleVal *= 1.25f;
			SwoopVal *= 0.85f;
			BlockVal = 0.0f;
			JumpVal *= 0.95f;
			FallDownVal *= 0.95f;
		}
		else if (AttackType == ATTACK_TELEKINESIS)
		{
			TeleVal *= 1.25f;
			BlockVal = 0.0f;
		}

		if (m_pPersonality->aggression_level == Aggressive)
			AttackVal *= 0.85f;
		else if (m_pPersonality->aggression_level == Defensive)
			AttackVal *= 1.25f;

		// Yay done determinging how hostile the attack is....

		// Well was it hostile?
		if (AttackVal < DANGER_LIGHT_MIN_VAL)
			continue; // Nope :-)

		if (AttackVal > HighestAttackVal)
		{
			HighestAttackVal = AttackVal;
			DangerInfo.TeleVal = TeleVal;
			DangerInfo.SwoopVal = SwoopVal;
			DangerInfo.BlockVal = BlockVal;
			DangerInfo.JumpVal = JumpVal;
			DangerInfo.StopFlyVal = FallDownVal;
			DangerInfo.pMostDangerousEnt = pAttack;
		}
		DangerInfo.DangerValue += AttackVal;
	}

	if (DangerInfo.DangerValue > DANGER_HEAVY_MIN_VAL) // If it is this high, then there are multiple dangerous attacks...
	{
//		DangerInfo.DangerValue += 75;
		DangerInfo.TeleVal *= 1.75f;
		DangerInfo.SwoopVal *= 1.55f;
		DangerInfo.BlockVal *= 0.1f;
		DangerInfo.JumpVal *= 0.5f;
		DangerInfo.StopFlyVal *= 0.5f;
	}/*
	else if (DangerInfo.DangerValue > 200)
	{
//		DangerInfo.DangerValue += 55;
		DangerInfo.TeleVal *= 1.5f;
		DangerInfo.SwoopVal *= 1.25f;
		DangerInfo.BlockVal *= 0.25f;
		DangerInfo.JumpVal *= 0.75f;
		DangerInfo.StopFlyVal *= 0.75f;
	}
	else if (DangerInfo.DangerValue > 175)
	{
//		DangerInfo.DangerValue += 25;
		DangerInfo.TeleVal *= 1.25f;
		DangerInfo.SwoopVal *= 1.1f;
		DangerInfo.BlockVal *= 0.35f;
		DangerInfo.JumpVal *= 0.9f;
		DangerInfo.StopFlyVal *= 0.9f;
	}
	else if (DangerInfo.DangerValue > 150)
	{
//		DangerInfo.DangerValue += 10;
		DangerInfo.TeleVal *= 1.02f;
		DangerInfo.SwoopVal *= 1.02f;
		DangerInfo.BlockVal *= 0.75f;
	}*/

	DangerInfo.MayUseSolar = DangerInfo.MayUseMelee = false;
	DangerInfo.MayUseSBotLaser = true;
	if (DangerInfo.DangerValue)
		PrintAI("BlockVal : " << DangerInfo.BlockVal << "\n");
}

void CBot::SenseSurroundingPlayers(danger_info_s &DangerInfo)
{
	// Declare some shortcuts...
	CBasePlayer *pPlayer;
	Vector v_end;

	float flDist;
	short HeadPercent;
	bool JustMadeASound = false;

	short EnemyVal;
	short HighestEnemyVal = 0;
	float TeleVal, SwoopVal, BlockVal, JumpVal, FallDownVal;

	if (!m_bMadePlayerList)
		MakePlayerList();

	if (m_bPlayerCount == 0)
		return;

	byte DangerHeadPercent = MIN_DANGER_HEAD_PERCENT;

	if (m_pPersonality->aggression_level == Defensive)
		DangerHeadPercent *= 0.85f;
	else if (m_pPersonality->aggression_level == Aggressive)
		DangerHeadPercent *= 1.2;

	for (byte b=0;b<m_bPlayerCount;b++)
	{
		pPlayer = m_pPlayerList[b];

		if ((g_teamplay) && (pPlayer->pev->team == pev->team))
			continue;

		v_end = pPlayer->pev->origin;
		flDist = GetDistance(v_end);

		if (flDist > 2000.0f)
			continue;

		HeadPercent = UTIL_GetHeadingPercentage(this, pPlayer);
//		rcout << "HeadPercent: " << HeadPercent << "\n";

/* UNDONE
		JustMadeASound = ((pClient->LastSoundTime > (gpGlobals->time - 1.0)) &&
						  (pClient->SoundName[0] != 0) && (flDist < 3000.0f));*/


		if ((!EntIsInFOV(pPlayer)) && (!JustMadeASound))
			continue;

		// Is this enemy 'busy'?(ie charging a combo, powerstruggling)
		if (!CanAttackPlayer(pPlayer))
			continue;

		// hmm okay we found a player wich might be hostile... now determine how hostile he/she is

		// Reset all temp vars
		EnemyVal = 0;
		TeleVal = m_pPersonality->teleport_percent;
		SwoopVal = m_pPersonality->swoop_percent;
		BlockVal = m_pPersonality->block_percent;
		JumpVal = m_pPersonality->jump_percent;
		FallDownVal = m_pPersonality->stopfly_percent;

		// Does this player swoop?(handle the danger stuff different)
		if (pPlayer->pev->movetype == MOVETYPE_PLAYERSWOOP)
		{
			if (HeadPercent < DangerHeadPercent)
				continue;

			// First look how close this attack is
			if (flDist < 150.0f) // Argh
			{
				EnemyVal += 160;
				TeleVal *= 1.7f;
				SwoopVal *= 0.01f;
				BlockVal *= 1.1f;
				JumpVal *= 0.01f;
				FallDownVal *= 0.01f;
			}
			else if (flDist < 350.0f)
			{
				EnemyVal += 130;
				TeleVal *= 1.3f;
				SwoopVal *= 0.1f;
				BlockVal *= 0.75f;
				JumpVal *= 0.1f;
				FallDownVal *= 0.1f;
			}
			else if (flDist < 500.0f)
			{
				EnemyVal += 100;
				TeleVal *= 1.25f;
				SwoopVal *= 0.25f;
				BlockVal *= 0.3f;
				JumpVal *= 0.25f;
				FallDownVal *= 0.25f;
			}
			else if (flDist < 750.0f)
			{
				EnemyVal += 100;
				TeleVal *= 1.05f;
				SwoopVal *= 0.40f;
				BlockVal *= 0.1f;
				JumpVal *= 0.45f;
				FallDownVal *= 0.45f;
			}
			else if (flDist < 875.0f)
			{
				EnemyVal += 85;
				SwoopVal *= 0.5f;
				BlockVal *= 0.07f;
				JumpVal *= 0.6f;
				FallDownVal *= 0.6f;
			}
			else if (flDist < 1000.0f)
			{
				EnemyVal += 65;
				SwoopVal *= 0.85f;
				BlockVal *= 0.05f;
			}
			else if (flDist < 1250.0f)
			{
				EnemyVal += 35;
				TeleVal *= 0.9f;
				BlockVal *= 0.03f;
			}
			else if (flDist < 2000.0f)
			{
				EnemyVal += 15;
				TeleVal *= 0.75f;
				BlockVal *= 0.01f;
				JumpVal *= 0.5f;
				FallDownVal *= 0.5f;
			}

			// Now determine how much stronger the player is

			// Determine the pl difference between the owner and the bot
			long PlDiff = pPlayer->m_iPowerLevel - m_iPowerLevel;

			if (PlDiff > 3000000)
			{
				EnemyVal += 45;
				TeleVal *= 1.55f;
				BlockVal *= 0.01f;
				JumpVal *= 0.9f;
				FallDownVal *= 0.9f;
			}
			else if (PlDiff > 2500000)
			{
				EnemyVal += 30;
				TeleVal *= 1.45f;
				BlockVal *= 0.01f;
				JumpVal *= 0.95f;
				FallDownVal *= 0.95f;
			}
			else if (PlDiff > 1500000)
			{
				EnemyVal += 20;
				TeleVal *= 1.2f;
				BlockVal *= 0.02f;
			}
			else if (PlDiff > 800000)
			{
				EnemyVal += 10;
				BlockVal *= 0.2f;
			}
				
			// Okay, now how much health has the bot?
			if (pev->health < 10)
			{
				EnemyVal += 25;
				TeleVal *= 1.25f;
				SwoopVal *= 0.95f;
				BlockVal *= 0.01f;
				JumpVal *= 0.9f;
				FallDownVal *= 0.9f;
			}
			else if (pev->health < 25)
			{
				EnemyVal += 15;
				TeleVal *= 1.1f;
				BlockVal *= 0.05f;
			}
			else if (pev->health < 35)
			{
				EnemyVal += 10;
				BlockVal *= 0.15f;
			}

			// Now see how 'much' this player heads to the bot
			if (HeadPercent < 90)
				EnemyVal -= 12;
			else if (HeadPercent < 95)
				EnemyVal -= 5;
		}
		else if (EntIsInFOV(pPlayer))
		{
			// First look how close this attack is
			if (flDist < 50.0f)
			{
				EnemyVal += 150;
				TeleVal *= 1.7f;
				SwoopVal *= 0.01f;
				BlockVal *= 0.1f;
				JumpVal *= 0.01f;
				FallDownVal *= 0.01f;
			}
			else if (flDist < 120.0f)
			{
				EnemyVal += 120;
				TeleVal *= 1.3f;
				SwoopVal *= 0.1f;
				BlockVal *= 0.01f;
				JumpVal *= 0.25f;
				FallDownVal *= 0.25f;
			}
			else if (flDist < 175.0f)
			{
				EnemyVal += 80;
				TeleVal *= 1.05f;
				SwoopVal *= 0.35f;
				BlockVal *= 0.01f;
				JumpVal *= 0.85f;
				FallDownVal *= 0.85f;
			}
			else if (flDist < 250.0f)
			{
				EnemyVal += 60;
				TeleVal *= 0.9f;
				SwoopVal *= 0.85f;
				BlockVal *= 0.01f;
			}
			else
				continue; // To far away

			// Now determine how much stronger the player is

			// Determine the pl difference between the owner and the bot
			long PlDiff = pPlayer->m_iPowerLevel - m_iPowerLevel;

			if (PlDiff > 3000000)
			{
				EnemyVal += 35;
				TeleVal *= 1.55f;
				BlockVal *= 0.01f;
				JumpVal *= 0.9f;
				FallDownVal *= 0.9f;
			}
			else if (PlDiff > 2500000)
			{
				EnemyVal += 25;
				TeleVal *= 1.45f;
				BlockVal *= 0.01f;
				JumpVal *= 0.95f;
				FallDownVal *= 0.95f;
			}
			else if (PlDiff > 1500000)
			{
				EnemyVal += 15;
				TeleVal *= 1.2f;
				BlockVal *= 0.02f;
			}
				
			// Okay, now how much health has the bot?
			if (pev->health < 10)
			{
				EnemyVal += 30;
				TeleVal *= 1.25f;
				SwoopVal *= 0.95f;
				BlockVal *= 0.01f;
				JumpVal *= 0.9f;
				FallDownVal *= 0.9f;
			}
			else if (pev->health < 25)
			{
				EnemyVal += 20;
				TeleVal *= 1.1f;
				BlockVal *= 0.05f;
			}
			else if (pev->health < 35)
			{
				EnemyVal += 10;
				BlockVal *= 0.15f;
			}

			// Now see how 'much' this player heads to the bot
			if (HeadPercent < 90)
				EnemyVal -= 25;
			else if (HeadPercent < 95)
				EnemyVal -= 10;
		}

		if (m_pPersonality->aggression_level == Aggressive)
			EnemyVal *= 0.85f;
		else if (m_pPersonality->aggression_level == Defensive)
			EnemyVal *= 1.25f;

		// Yay done determinging how hostile the player is....

		// Well was he/she hostile?
		if (EnemyVal < DANGER_LIGHT_MIN_VAL)
			continue; // Nope :-)

		if (EnemyVal > HighestEnemyVal)
		{
			HighestEnemyVal = EnemyVal;
			DangerInfo.TeleVal = TeleVal;
			DangerInfo.SwoopVal = SwoopVal;
			DangerInfo.BlockVal = BlockVal;
			DangerInfo.JumpVal = JumpVal;
			DangerInfo.StopFlyVal = FallDownVal;
			DangerInfo.pMostDangerousEnt = pPlayer;
		}
		DangerInfo.DangerValue += EnemyVal;
	}
	
	if (DangerInfo.DangerValue > DANGER_HEAVY_MIN_VAL) // If it is this high, then there are multiple dangerous players...
	{
//		DangerInfo.DangerValue += 75;
		DangerInfo.TeleVal *= 1.75f;
		DangerInfo.SwoopVal *= 1.55f;
		DangerInfo.BlockVal *= 0.01f;
		DangerInfo.JumpVal *= 0.5f;
		DangerInfo.StopFlyVal *= 0.5f;
	}
	else if (DangerInfo.DangerValue > 200)
	{
//		DangerInfo.DangerValue += 55;
		DangerInfo.TeleVal *= 1.5f;
		DangerInfo.SwoopVal *= 1.25f;
		DangerInfo.BlockVal *= 0.07f;
		DangerInfo.JumpVal *= 0.75f;
		DangerInfo.StopFlyVal *= 0.75f;
	}
	else if (DangerInfo.DangerValue > 175)
	{
//		DangerInfo.DangerValue += 25;
		DangerInfo.TeleVal *= 1.25f;
		DangerInfo.SwoopVal *= 1.1f;
		DangerInfo.BlockVal *= 0.15f;
		DangerInfo.JumpVal *= 0.9f;
		DangerInfo.StopFlyVal *= 0.9f;
	}
	else if (DangerInfo.DangerValue > 150)
	{
//		DangerInfo.DangerValue += 10;
		DangerInfo.TeleVal *= 1.02f;
		DangerInfo.SwoopVal *= 1.02f;
		DangerInfo.BlockVal *= 0.15f;
	}

	DangerInfo.MayUseSolar = DangerInfo.MayUseSBotLaser = DangerInfo.MayUseMelee = false;

	if (DangerInfo.pMostDangerousEnt)
	{
		flDist = GetDistance(DangerInfo.pMostDangerousEnt->pev->origin);
		DangerInfo.MayUseSolar = (flDist < 250.0f);
		DangerInfo.MayUseSBotLaser = (flDist > 350.0f);
		DangerInfo.MayUseMelee = (flDist < 1500.0f);
	}
}

void CBot::SenseSurroundingSounds(danger_info_s &DangerInfo)
{
	/* UNDONE
	edict_t *pEdict = pBot->pEdict;
	edict_t *pPlayer;
	edict_t *pMostDangerousPlayer = NULL;
	Vector v_src = pEdict->v.origin;

	if (!pBot->MadePlayerList)
		MakePlayerList(pBot);

	float NearestDist = 9999.9;

	if (pBot->PlayerCount > 0)
	{
		ClientInfo_t *pClient;
		int SoundMakerVal;
		int BestSoundMakerVal = 0;
		float flDist = 0.0;
		TraceResult tr;

		for(int i=0;i<pBot->PlayerCount;i++)
		{
			SoundMakerVal = 1;

			pPlayer = pBot->PlayerList[i];

			// Skip team mates if team play is enabled
			if ((g_teamplay) && (pPlayer->pev->team == pEdict->v.team))
				continue;
			
			flDist = UTIL_Distance(pEdict->v.origin, pPlayer->pev->origin);

			if (flDist > 3000.0)
				continue;

			Vector vecEnemy = pPlayer->pev->origin;

			// since a scouter is 2d, calculate the distance in 2d :)
			Vector v_dist = vecEnemy - GetGunPosition(pBot->pEdict);
			v_dist.z = 0;
			float distance = v_dist.Length();

			bool OnScouter = ((distance <= 2300.0) || (pBot->SBotType > 0));
			bool InViewCone = (FInViewCone(&vecEnemy, pBot->pEdict));

			if ((!InViewCone) && (!OnScouter))
				continue;

			// Only check if player is facing the bot...
			UTIL_TraceLine(pPlayer->pev->origin, pEdict->v.origin, dont_ignore_monsters, pPlayer, &tr);
			if (tr.pHit != pEdict)
				continue;
			
			pClient = UTIL_GetClientPointer(pPlayer);
			if (!pClient) // Shouldn't happen
			{
#ifdef _DEBUG
				lcout << "Couldn't get client pointer in SenseSurroundingSounds()!\n";
#endif
				continue;
			}

			if (pClient->LastSoundTime > gpGlobals->time)
			{
				SoundType_e SoundType = ClassifySound(pClient->SoundName);

				// Only avoid laser sounds
				if (SoundType == LaserSound)
				{
					// don't react on a candy beam when the distance is to high...
					if ((FStrEq(pClient->SoundName,"weapons/candyattack.wav")) &&
						(flDist > 300.0))
						continue;

					if (NearestDist > flDist)
					{
						NearestDist = flDist;
						SoundMakerVal++;
					}

					if (SoundMakerVal > BestSoundMakerVal)
					{
						BestSoundMakerVal = SoundMakerVal;
						pMostDangerousPlayer = pPlayer;
						break; // For now just break
					}
				}
			}
		}
	}

	if (pMostDangerousPlayer)
	{
		DangerInfo.DangerValue = 175;

		if (m_pPersonality->aggression_level == Aggressive)
			DangerInfo.DangerValue *= 0.85f;
		else if (m_pPersonality->aggression_level == Defensive)
			DangerInfo.DangerValue *= 1.25f;

		DangerInfo.TeleVal = static_cast<float>(m_pPersonality->teleport_percent) * 1.75f;
		DangerInfo.SwoopVal = static_cast<float>(m_pPersonality->swoop_percent) * 0.2f;
		DangerInfo.BlockVal = 0.01f;
		DangerInfo.JumpVal = static_cast<float>(m_pPersonality->jump_percent) * 0.3f;
		DangerInfo.StopFlyVal = static_cast<float>(m_pPersonality->stopfly_percent) * 0.3f;
		DangerInfo.pMostDangerousEnt = pMostDangerousPlayer;
		DangerInfo.MayUseSolar = DangerInfo.MayUseSBotLaser = DangerInfo.MayUseMelee = false;
	}*/
}

void CBot::SenseHit(danger_info_s &DangerInfo)
{
	if (m_fLastHitTime > (gpGlobals->time - 0.5f))
	{
		DangerInfo.DangerValue = 175;

		if (m_pPersonality->aggression_level == Aggressive)
			DangerInfo.DangerValue *= 0.85f;
		else if (m_pPersonality->aggression_level == Defensive)
			DangerInfo.DangerValue *= 1.25f;

		DangerInfo.TeleVal = static_cast<float>(m_pPersonality->teleport_percent) * 1.75f;
		DangerInfo.SwoopVal = static_cast<float>(m_pPersonality->swoop_percent) * 0.2f;
		DangerInfo.BlockVal = 0.01f;
		DangerInfo.JumpVal = static_cast<float>(m_pPersonality->jump_percent) * 0.3f;
		DangerInfo.StopFlyVal = static_cast<float>(m_pPersonality->stopfly_percent) * 0.3f;

		/* UNDONE ?
		if (IsNull(pev->dmg_inflictor) == false)
		{
			if (pev->dmg_inflictor->v.flags & FL_CLIENT) // Bot hurt by a player?
				DangerInfo.pMostDangerousEnt = pev->dmg_inflictor;
			else if ((IsNull(pev->dmg_inflictor->v.owner) == false) &&
					 (pev->dmg_inflictor->v.owner->v.flags & FL_CLIENT))
				DangerInfo.pMostDangerousEnt = pev->dmg_inflictor->v.owner;
		}*/

		DangerInfo.MayUseSolar = DangerInfo.MayUseSBotLaser = DangerInfo.MayUseMelee = false;
		m_fLastHitTime = 0.0f;
	}
}

void CBot::BotSense()
{
	danger_info_s AttackDangerInfo, PlayerDangerInfo, SoundDangerInfo, HitDangerInfo;
	danger_info_s *pReactOnDangerInfo = NULL;

	int SenseChecks = 0;
	bool CheckEverything = false;

	if (m_pCurrentBotTask)
		SenseChecks = m_pCurrentBotTask->GetBotSenseChecks();
	else
		CheckEverything = true;

	// Reset danger vars
	m_sDangerLevel = m_iDangerType = 0;

	if ((SenseChecks == 0) && (!CheckEverything))
	{
		// Don't sense when the bot don't want to O_o
		return;
	}

	if ((SenseChecks & CheckAttacks) || (CheckEverything))
		SenseSurroundingAttacks(AttackDangerInfo);

	if ((SenseChecks & CheckSurroundingPlayers) || (CheckEverything))
		SenseSurroundingPlayers(PlayerDangerInfo);

	if ((SenseChecks & CheckSounds) || (CheckEverything))
		SenseSurroundingSounds(SoundDangerInfo);

	if ((SenseChecks & CheckAttacks) || (CheckEverything))
		SenseHit(HitDangerInfo);

	// Check where the bot should react on

	if (AttackDangerInfo.DangerValue)
	{
		pReactOnDangerInfo = &AttackDangerInfo;
		m_iDangerType = DangerAttack;
	}
	
	if (PlayerDangerInfo.DangerValue)
	{
		if ((!pReactOnDangerInfo) ||
			(PlayerDangerInfo.DangerValue > pReactOnDangerInfo->DangerValue))
		{
			pReactOnDangerInfo = &PlayerDangerInfo;

			if ((m_pBotEnemy == pReactOnDangerInfo->pMostDangerousEnt) ||
			    (EnemyIsInList((CBasePlayer *)pReactOnDangerInfo->pMostDangerousEnt)))
				m_iDangerType = DangerCurrentEnemy;
			else
				m_iDangerType = DangerEnemy;
		}
	}

	if (SoundDangerInfo.DangerValue)
	{
		if ((!pReactOnDangerInfo) ||
			(SoundDangerInfo.DangerValue > pReactOnDangerInfo->DangerValue))
		{
			pReactOnDangerInfo = &SoundDangerInfo;
			m_iDangerType = DangerSound;
		}
	}

	if (HitDangerInfo.DangerValue)
	{
		if ((!pReactOnDangerInfo) ||
			(HitDangerInfo.DangerValue > pReactOnDangerInfo->DangerValue))
		{
			pReactOnDangerInfo = &HitDangerInfo;
			m_iDangerType = DangerHit;
		}
	}

	bool ReactOnDanger = false;

	if (pReactOnDangerInfo)
	{
		m_sDangerLevel = pReactOnDangerInfo->DangerValue;

		if (m_pCurrentBotTask)
		{
			ReactOnDanger = (m_pCurrentBotTask->ReactOnDanger(pReactOnDangerInfo));
		}
		else
			ReactOnDanger = true;
	}

	// React on danger?
	if (ReactOnDanger)
	{
		// Bot is low on ki?
		if (GetKi() < 300)
		{
			float KiFactor = 0.0f;
			if (GetKi()) // We don't want a zero devide...
				KiFactor = float((GetKi() / 1000.0f));

			// Teleport eats ki. So less chance for that.
			pReactOnDangerInfo->TeleVal *= KiFactor;
			// But stopping with fly gives you ki instead :-)
			pReactOnDangerInfo->StopFlyVal *= (2.0f - KiFactor);
		}

		// damn :( now lets see how we are going to do that...

		bool BotCanShoot = ((HasWeapons()) && (BotManager.BotsShoot()) &&
							(BotManager.BotsSearchEnemies()));

		// First check if the bot should melee to handle the danger(mainly counter attacking)
		if ((pReactOnDangerInfo->MayUseMelee) && (pReactOnDangerInfo->pMostDangerousEnt) &&
			(BotCanShoot) &&
			(EnemyIsInMeleeRange((CBasePlayer *)pReactOnDangerInfo->pMostDangerousEnt)))
		{
			CBasePlayer *pEnemy = (CBasePlayer *)pReactOnDangerInfo->pMostDangerousEnt; // Shortcut
			short MeleePercent = m_pPersonality->melee_percent;
			float flDist = GetDistance(pEnemy->pev->origin);

			if (m_pPersonality->aggression_level == Aggressive)
				MeleePercent *= 1.25f;
			else if (m_pPersonality->aggression_level == Defensive)
				MeleePercent *= 0.8f;

			if ((BotManager.IsDBMode()) && (m_eBotDBType == DB_DEFENDER))
				MeleePercent *= 1.5f;

			if (pEnemy->pev->movetype != MOVETYPE_PLAYERSWOOP)
			{
				bool CanKick = CanMeleeKickPlayer(pEnemy);
				if (RANDOM_LONG(1, 100) <= MeleePercent)
				{
					if ((flDist < 175.0) && (CanKick))
					{
						m_pBotEnemy = pEnemy;
						MakeTask(TaskKickEnemy);
						return;
					}
					else if ((GetKi() > 400) && (flDist < 350.0) && (m_bSkillNr < 3))
					{
						m_pBotEnemy = pEnemy;

						if (RANDOM_LONG(1, 100) <= m_pPersonality->teleport_percent)
						{
							MakeCombo(COMBO_TYPE_TELE_KICK);
						}
						else if (flDist > 225.0f)
						{
							MakeCombo(COMBO_TYPE_FORWARD_SWOOP);
						}
						return;
					}
				}
			}
			else
			{
				if (RANDOM_LONG(1, 100) <= MeleePercent)
				{
					if ((flDist > 150.0f) && (flDist < 850.0f) && (m_bSkillNr <= 1) &&
						(GetKi() > 400) && (RANDOM_LONG(1, 100) <= m_pPersonality->teleport_percent))
					{
						if (MakeTeleMelee(pEnemy))
						{
							m_pBotEnemy = pEnemy;
							return;
						}
					}
					if ((flDist > 500.0f) && (m_fShootDelay <= gpGlobals->time) &&
						(RANDOM_LONG(1, 100) <= 65))
					{
						m_pBotEnemy = pEnemy;
						MakeCombo(COMBO_TYPE_FORWARD_SWOOP);
						return;
					}
				}
			}
		}

		if (pev->waterlevel == 3)
		{
			// If the bot is underwater don't try to jump or release fly
			pReactOnDangerInfo->JumpVal = pReactOnDangerInfo->StopFlyVal = 0.0;
		}

		if (!(pev->flags & FL_ONGROUND))
			pReactOnDangerInfo->JumpVal = 0.0;
		else
			pReactOnDangerInfo->StopFlyVal = 0.0f;

		if (pReactOnDangerInfo->StopFlyVal > 0.0)
		{
			if (GetCollisionDist(dir_down, MIN_DIST_TO_FALL_DOWN) < MIN_DIST_TO_FALL_DOWN)
				pReactOnDangerInfo->StopFlyVal = 0.0;
		}

		bool BotMayUseSolarFlare = false;
		bool UseSolar = false;

		if (pReactOnDangerInfo->pMostDangerousEnt &&
			pReactOnDangerInfo->pMostDangerousEnt->IsPlayer())
		{
			CBasePlayer *pPlayer = (CBasePlayer *)pReactOnDangerInfo->pMostDangerousEnt;
			float EnemyDist = GetDistance(pReactOnDangerInfo->pMostDangerousEnt->pev->origin);
			BotMayUseSolarFlare = ((pReactOnDangerInfo->MayUseSolar) && (GetKi() > 600) &&
								   (BotCanShoot) && (EnemyDist < 250.0) &&
								   (HasWeapon(WEAPON_SOLARFLARE)) &&  
								   (pPlayer->m_fBlinded == false) &&
								   (RANDOM_LONG(1, 100) <= 
								   m_pPersonality->solarflare_percent));
		}

		TMultiChoice<EReactOnDangerType> AvoidChoice;

		AvoidChoice.Insert(ReactWithTeleport, pReactOnDangerInfo->TeleVal);
		AvoidChoice.Insert(ReactWithSwoop, pReactOnDangerInfo->SwoopVal);
		AvoidChoice.Insert(ReactWithBlock, pReactOnDangerInfo->BlockVal);
		AvoidChoice.Insert(ReactWithJump, pReactOnDangerInfo->JumpVal);
		AvoidChoice.Insert(ReactWithStopFly, pReactOnDangerInfo->StopFlyVal);

		if ((pReactOnDangerInfo->MayUseSBotLaser) && (pReactOnDangerInfo->pMostDangerousEnt) &&
			(IsSuperBot()) && (GetKi() > 200) && (GetMaxSpeed() > 0.0f) &&
			(BotCanShoot))
		{
			// yay im a superbot, i can cheat :D
			AvoidChoice.Insert(ReactWithSBotLaser, m_pSBotSettings->laser_percent);
		}

		EReactOnDangerType Choice = ReactNone;
		AvoidChoice.GetSelection(Choice);

		if (Choice == ReactWithTeleport)
		{
			if (BotMayUseSolarFlare)
			{
				UseSolar = true;
				Teleport();
			}
			else if ((RANDOM_LONG(1, 100) <= m_pPersonality->teleport_percent) && 
				     (pReactOnDangerInfo->DangerValue >= 300))
			{
				MakeCombo(COMBO_TYPE_MULTI_TELEPORT);
			}
			else
				MakeTask(TaskTeleport);

			if (pReactOnDangerInfo->DangerValue >= DANGER_HEAVY_MIN_VAL)
				m_fTeleportDelay = 0.0; // do it as fast as possible
		}
		else if (Choice == ReactWithSwoop)
		{
			m_pSwoopAvoidEnt = pReactOnDangerInfo->pMostDangerousEnt;
			MakeAvoidSwoopTask();
		}
		else if (Choice == ReactWithBlock)
		{
			m_pEntToBlock = pReactOnDangerInfo->pMostDangerousEnt;
			MakeTask(TaskBlock);
		}
		else if (Choice == ReactWithJump)
		{
			MakeTask(TaskNormalJump);

			int RandNr = RANDOM_LONG(1, 3);

			if (RandNr == 0)
				m_sJumpDir = dir_left;
			else if (RandNr == 1)
				m_sJumpDir = dir_right;
			
			if (RANDOM_LONG(0, 1))
				m_sJumpDir |= dir_back;
		}
		else if (Choice == ReactWithStopFly)
		{
			m_bShouldFly = false;
			if (m_fFlying)
				StopFly();

			m_fCheckFlyDelay = gpGlobals->time + RANDOM_FLOAT(1.0, 1.4);

			if (BotMayUseSolarFlare)
				UseSolar = true;
		}
		else if (Choice == ReactWithSBotLaser)
		{
			MakeTask(TaskDrainEnts);
		}

		if (UseSolar)
		{
			if ((m_pActiveItem) && (m_pActiveItem->m_iId != WEAPON_SOLARFLARE))
				SelectItem("weapon_solarflare");
			pev->button |= IN_ATTACK;
		}
	}
}

// ==================================================================
// Code of CBot - End
// ==================================================================

// ==================================================================
// Task Code - Begin
// ==================================================================

bool CPowerUpTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if (pDangerInfo->DangerValue < DANGER_MEDIUM_MIN_VAL)
		return false;

	short MinKiLevel = GetKiTarget();

	if (pBot->m_sKiGainTarget)
		MinKiLevel = pBot->m_sKiGainTarget;

	if (pDangerInfo->DangerValue <= DANGER_MEDIUM_MAX_VAL)
		MinKiLevel = 100; // hurry up
	else
		MinKiLevel = 20;

	if (pBot->GetKi() >= MinKiLevel)
	{
		TaskState = DONE;
		return true;
	}

	return false;
}

bool CTeleportTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if (pDangerInfo->DangerValue >= DANGER_HEAVY_MIN_VAL)
		pBot->m_fTeleportDelay = 0.0;
	else if (pDangerInfo->DangerValue >= DANGER_HARD_MIN_VAL)
	{
		if ((pBot->m_fTeleportDelay - gpGlobals->time) > 0.1)
			pBot->m_fTeleportDelay = gpGlobals->time + 0.1;
	}

	return false;
}

bool CBlockTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if (pDangerInfo->pMostDangerousEnt)
		pBot->m_pEntToBlock = pDangerInfo->pMostDangerousEnt; // Update ent to block

	return false; // Don't react because we are already reacting :)
}

bool CAscendTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if (pBot->m_iDangerType == DangerEnemy)
		return false;

	if (pDangerInfo->DangerValue <= DANGER_MEDIUM_MIN_VAL)
		return false;

	if (pBot->m_iDangerType == DangerHit)
	{
		float DangerousDamage = pBot->m_iDamageTaken * 2.0f;

		if (pBot->m_pPersonality->aggression_level == Defensive)
			DangerousDamage *= 1.25f;
		else if (pBot->m_pPersonality->aggression_level == Aggressive)
			DangerousDamage *= 0.75f;

		if (pEdict->v.health < DangerousDamage)
			return false;
	}

	float MaxTimeLeftToStop = 2.0;

	if (pBot->m_pPersonality->aggression_level == Defensive)
		MaxTimeLeftToStop *= 1.25;
	else if (pBot->m_pPersonality->aggression_level == Aggressive)
		MaxTimeLeftToStop *= 0.75;

	if ((pBot->m_flAscendTime - gpGlobals->time) > MaxTimeLeftToStop)
	{
		pBot->Descend(true);
		// Don't check for ascending for a while
		pBot->m_fLastAscendCheck = gpGlobals->time + RANDOM_FLOAT(10.0f, 25.0f);
		return true;
	}

	return false;
}

bool CRecoverHPTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	int MinHealth = 140;

	if (pDangerInfo->DangerValue < DANGER_MEDIUM_MIN_VAL)
		MinHealth = 120;
	else if (pDangerInfo->DangerValue <= DANGER_MEDIUM_MAX_VAL)
		MinHealth = 30;
	else
		MinHealth = 0;

	MinHealth -= (100-((pBot->GetKi()/1000)*100));

	if (pEdict->v.health >= MinHealth)
		return true;

	return false;
}

bool CWallJumpTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if ((pDangerInfo->DangerValue >= DANGER_HEAVY_MIN_VAL) &&
		(pBot->m_iDangerType != DangerEnemy) &&	(pBot->m_iDangerType != DangerCurrentEnemy))
	{
		return ((!pBot->m_fWallJump) && (pBot->m_Melee.m_eThrowStatus != THROW_WALLSTICK));
	}
	return false;
}

bool CChargeAttackTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if (pDangerInfo->DangerValue >= DANGER_MEDIUM_MIN_VAL)
	{
		if (RANDOM_LONG(1, 100) <= pBot->m_pPersonality->teleport_percent)
		{
			bool GoTeleport = false;

			if (pBot->m_iChargePercent > 0)
			{
				if (pBot->m_pClass->CanTeleportWhileCharging())
				{
					GoTeleport = true;
				}
			}
			else
				GoTeleport = true;

			if (GoTeleport)
			{
				pBot->Teleport();
				return false;
			}
		}
		
		if (pBot->BotShouldFallDown())
		{
			if (pBot->m_fFlying)
				pBot->StopFly();

			pBot->m_bShouldFly = false;
			pBot->m_fCheckFlyDelay = gpGlobals->time + RANDOM_FLOAT(0.8, 1.2);
			return false;
		}
		
		if (pBot->m_iChargePercent >= 33)
		{
			if ((pBot->m_pCurrentWeaponInfo) && (pBot->m_pCurrentWeaponInfo->bCanBeamJump) &&
				(pDangerInfo->DangerValue < DANGER_HARD_MIN_VAL) && (pBot->BotCanBeamJump(false)))
			{
				pBot->m_eTaskAfterTask = TaskBeamJump;
				TaskState = DONE;
				pEdict->v.button |= IN_ATTACK; // Otherwise the beam will be released
				return false;
			}

			bool AttackHeadsToBot = false;

			if ((pBot->m_pBotEnemy) && (pBot->m_iDangerType == DangerAttack))
			{
				CBaseEntity *pEnemyAttack = UTIL_GetLastAttackFromPlayer(pBot->m_pBotEnemy);

				if (pEnemyAttack)
				{
					if (EntityHeadsToPlayer(pBot, pEnemyAttack))
					{
						AttackHeadsToBot = true;
						// stop charging...

						// set next time to shoot
						pBot->AddShootDelay();

						if (RANDOM_LONG(1, 100) <= pBot->m_pPersonality->beamexplode_percent)
							pBot->m_bLetBeamExplode = true;
						else
							pBot->m_bLetBeamExplode = false;

						pBot->m_eTaskAfterTask = TaskControlBeam;
						TaskState = DONE;

						// Aim at the attack
						pBot->AimToVec(pEnemyAttack->pev->origin);
					}
				}
			}
			
			if ((AttackHeadsToBot) || (pDangerInfo->DangerValue < DANGER_HARD_MIN_VAL))
				return false;

			// Charging attack is a beam?
			if (pBot->m_pCurrentWeaponInfo && pBot->AttackIsBeam(pBot->m_pCurrentWeaponInfo))
			{
				// Switch to melee or sword, otherwise the attack will be releashed
				if (pEdict->v.playerclass == 7)
					pBot->SelectItem("weapon_sword");
				else
					pBot->SelectItem("weapon_melee");
			}
		}
		return true;
	}
	return false;
}

bool CShootNonChargebleTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if (pDangerInfo->DangerValue >= DANGER_MEDIUM_MIN_VAL)
	{
		if (RANDOM_LONG(1, 100) <= pBot->m_pPersonality->teleport_percent)
		{
			pBot->Teleport();
			return false;
		}
		
		if ((pDangerInfo->DangerValue <= DANGER_MEDIUM_MAX_VAL) && (pBot->BotShouldFallDown()))
		{
			if (pBot->m_fFlying)
				pBot->StopFly();

			pBot->m_bShouldFly = false;
			pBot->m_fCheckFlyDelay = gpGlobals->time + RANDOM_FLOAT(0.8, 1.2);
			return false;
		}
		
		return true;
	}
	return false;
}

bool CShootScatterShotsTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if (pDangerInfo->DangerValue >= DANGER_MEDIUM_MIN_VAL)
	{
		if (RANDOM_LONG(1, 100) <= pBot->m_pPersonality->teleport_percent)
		{
			pBot->Teleport();
			return false;
		}
		
		if (pBot->BotShouldFallDown())
		{
			if (pBot->m_fFlying)
				pBot->StopFly();

			pBot->m_bShouldFly = false;
			pBot->m_fCheckFlyDelay = gpGlobals->time + RANDOM_FLOAT(0.8, 1.2);
			return false;
		}
		
		return true;
	}
	return false;
}

bool CControlBeamTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if (pDangerInfo->DangerValue < DANGER_MEDIUM_MIN_VAL)
		return false;

	CBaseEntity *pAttack = UTIL_GetLastAttackFromPlayer(pBot);
	if (!pAttack) // Shouldn't happen
	{
		pEdict->v.button |= IN_ATTACK2;
		return true;
	}

	Vector v_attack = pAttack->pev->origin;
	float BotToAttackDist = pBot->GetDistance(v_attack);
	float MinExplodeAttackDist = (pAttack->pev->dmg * 12.5f);

	if ((pBot->m_pBotEnemy) && (pBot->m_iDangerType == DangerAttack))
	{
		CBaseEntity *pEnemyAttack = UTIL_GetLastAttackFromPlayer(pBot->m_pBotEnemy);
		if (pEnemyAttack)
		{
			if (EntIsInFieldOfView(pAttack, pEnemyAttack))
			{
				pBot->AimToVec(pEnemyAttack->pev->origin);
				BotShouldAimAtAttack = true;
				return false;
			}
		}
	}

	if (pDangerInfo->DangerValue < DANGER_HEAVY_MIN_VAL)
	{
		if (pBot->BotCanBeamJump(true))
		{
			pBot->m_eTaskAfterTask = TaskBeamJump;
			TaskState = DONE;
			return false;
		}
		else if ((BotToAttackDist > MinExplodeAttackDist) &&
			     (pDangerInfo->DangerValue >= DANGER_HARD_MIN_VAL))
		{
			pEdict->v.button |= IN_ATTACK2;
			return true;
		}
	}
	else
	{
		pEdict->v.button |= IN_ATTACK2;
		return true;
	}

	return false;
}

bool CKameTorpTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if ((pDangerInfo->DangerValue >= DANGER_HARD_MIN_VAL) &&
		(pDangerInfo->DangerValue <= DANGER_HARD_MAX_VAL))
	{
		pEdict->v.button |= IN_ATTACK2;
		return false;
	}

	if (pDangerInfo->DangerValue < DANGER_MEDIUM_MIN_VAL)
		DesiredTorpCount = 3;
	else if (pDangerInfo->DangerValue <= DANGER_MEDIUM_MAX_VAL)
		DesiredTorpCount = 1;
	else
	{
		pEdict->v.button |= IN_ATTACK2;
		return true;
	}

	return false;
}

bool CBeamJumpTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	if ((pBot->m_fControl) && (pEdict->v.movetype == MOVETYPE_RIDEBEAM))
		return false; // Don't react on danger when beamjumping

	if (pDangerInfo->DangerValue >= DANGER_HEAVY_MIN_VAL)
	{
		if (pBot->m_iChargePercent > 0)
		{
			// Switch to another melee so the beam won't be released
			if (pEdict->v.playerclass == 7)
				pBot->SelectItem("weapon_sword");
			else
				pBot->SelectItem("weapon_melee");
		}
		else
			pEdict->v.button |= IN_ATTACK2;

		return true;
	}
	
	return false;
}

bool CDBTask::ReactOnDanger(danger_info_s *pDangerInfo)
{
	pDangerInfo->BlockVal *= 0.8f;
	pDangerInfo->TeleVal *= 1.3f;
	return (pDangerInfo->DangerValue >= DANGER_MEDIUM_MIN_VAL);
	/*
	if (pDangerInfo->DangerValue < DANGER_MEDIUM_MIN_VAL)
		return false;

	if (pDangerInfo->DangerValue <= DANGER_HARD_MAX_VAL)
	{
		if (RANDOM_LONG(1, 100) < pBot->m_pPersonality->teleport_percent)
		{
			pBot->Teleport();
			return false;
		}
	}

	return (pDangerInfo->DangerValue >= DANGER_MEDIUM_MIN_VAL);*/
}


// ==================================================================
// Task Code - End
// ==================================================================