#include "gen_bot_header.h"
#include <ctype.h>
#include "teamplay_gamerules.h"
#include "monsters.h"
#include "studio.h"

//harSens: Linux compile fix
extern CLeftOutput lcout;

int m_iSpriteTexture; // Sprite index for debug-beams

extern int gmsgSayText;

void UTIL_DrawBeam(CBaseEntity *pEntity, Vector start, Vector end, int width,
        int noise, int red, int green, int blue, int brightness, int speed, int life)
{
	MESSAGE_BEGIN(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, NULL, pEntity->pev);
		WRITE_BYTE( TE_BEAMPOINTS);
		WRITE_COORD(start.x);
		WRITE_COORD(start.y);
		WRITE_COORD(start.z);
		WRITE_COORD(end.x);
		WRITE_COORD(end.y);
		WRITE_COORD(end.z);
		WRITE_SHORT( m_iSpriteTexture );
		WRITE_BYTE( 1 ); // framestart
		WRITE_BYTE( 10 ); // framerate
		WRITE_BYTE( life ); // life in 0.1's
		WRITE_BYTE( width ); // width
		WRITE_BYTE( noise );  // noise

		WRITE_BYTE( red );   // r, g, b
		WRITE_BYTE( green );   // r, g, b
		WRITE_BYTE( blue );   // r, g, b

		WRITE_BYTE( brightness );   // brightness
		WRITE_BYTE( speed );    // speed
	MESSAGE_END();
}

void UTIL_DrawBeamToAll(Vector start, Vector end, int width, int noise, int red, int green, int blue, 
						int brightness, int speed)
{
	CBasePlayer *pPlayer = NULL;

	for (int i=1;i<=gpGlobals->maxClients;i++)
	{
		pPlayer = (CBasePlayer *)UTIL_PlayerByIndex(i);

		if (IsNull(pPlayer))
			continue;

		if (pPlayer->pev->flags & FL_FAKECLIENT)
			continue; // don't bother about bots...

		UTIL_DrawBeam(pPlayer, start, end, width, noise, red, green, blue, brightness, speed);
	}
}

// Function made by PMB
Vector WrapAngles (Vector angles_to_wrap) 
{
   // this function adds or substracts 360 enough times needed to every of the three components
   // of the axial angles structure angles_to_wrap in order to set them into the range -180/+180
   // and returns the resulting axial angles structure

   static Vector angles;

   angles = angles_to_wrap; // update this function's static variable with the angles to wrap

   // check for wraparound of angles
   if (angles.x > 180)
      angles.x -= 360 * ((int) (angles.x / 360) + 1);
   if (angles.x < -180)
      angles.x += 360 * ((int) (angles.x / 360) + 1);
   if (angles.y > 180)
      angles.y -= 360 * ((int) (angles.y / 360) + 1);
   if (angles.y < -180)
      angles.y += 360 * ((int) (angles.y / 360) + 1);
   if (angles.z > 180)
      angles.z -= 360 * ((int) (angles.z / 360) + 1);
   if (angles.z < -180)
      angles.z += 360 * ((int) (angles.z / 360) + 1);

   return (angles);
}

// Function made by PMB
float UTIL_WrapAngle (float angle_to_wrap)
{
   float angle = angle_to_wrap;

   // check for wraparound of angle
   if (angle > 180)
      angle -= 360 * ((int) (angle / 360) + 1);
   if (angle < -180)
      angle += 360 * ((int) (angle / 360) + 1);

   return angle;
}

bool IsNull (edict_t *pEdict)
{
    // thanx to PMB for this function
	try
	{
		if (pEdict == NULL)
			return true;

		if (g_engfuncs.pfnEntOffsetOfPEntity (pEdict) == 0)
			return true;
   
		if (pEdict->free)
		    return true;

		if (pEdict->v.flags & FL_KILLME)
			return true;
   }
   catch (...)
   {
#ifdef _DEBUG
		FILE *fp = fopen("bot.txt", "a");
		if(fp)
		{
			fprintf(fp, "IsNull(edict_t *) Error\n");
			fclose(fp);
		}
#endif
	   return true; // failed so assuming entity isn't valid...
   }

   return false;
}

bool IsNull(CBaseEntity *pEnt)
{
    // thanx to PMB for this function
	try
	{
		if (pEnt == NULL)
			return true;

		if (pEnt->pev == NULL)
			return true;

		if (pEnt->pev->pContainingEntity == NULL)
			return true;

		if (g_engfuncs.pfnEntOffsetOfPEntity (pEnt->pev->pContainingEntity) == 0)
			return true;
   
		if (pEnt->pev->pContainingEntity->free)
		    return true;

		if (pEnt->pev->flags & FL_KILLME)
			return true;
	}
	catch (...)
    {
#ifdef _DEBUG
		FILE *fp = fopen("bot.txt", "a");
		if(fp)
		{
			fprintf(fp, "IsNull(CBaseEntity *) Error\n");
			fclose(fp);
		}
#endif
	    return true; // failed so assuming entity isn't valid...
    }

    return false;
	//return ((!pEnt) || (!pEnt->pev) || (IsNull(pEnt->pev->pContainingEntity)));
}

// Check if a player is valid
// CheckAlive(default true): check if this player is alive, if not return false
// CheckObserver(default true): If observer mode on and if this player is NOT a bot return false
bool UTIL_IsValidPlayer(CBasePlayer *pPlayer, bool CheckAlive, bool CheckObserver)
{
	if (!pPlayer || !pPlayer->pev)
		return false;

	if (IsNull(pPlayer))
		return false;
	
	if ((CheckObserver) && (BotManager.ObserverMode()) && (!UTIL_IsBot(pPlayer)))
		return false;

	if (FStrEq(STRING(pPlayer->pev->netname),""))
		return false;

    if ((CheckAlive) && ((!pPlayer->IsAlive()) || (pPlayer->m_fObserverFlag)))
        return false;

	if (!(pPlayer->pev->flags & FL_CLIENT))
		return false;

    return true;
}

void UTIL_Printf(const char *msg, int type, edict_t *pEntity)
{
	if (IsNull(pEntity))
	{
		if (!IsNull(BotManager.GetHost()))
			pEntity = BotManager.GetHost()->edict();
	}

	if ((type == HUD_PRINTCONSOLE) || (type == HUD_PRINTNOTIFY) || (IsNull(pEntity)))
	{
		(*g_engfuncs.pfnServerPrint) (const_cast<char*>(msg));
	}
	else
		ClientPrint(&pEntity->v, type, msg);
}

// Function made by PMB
void UTIL_PrintEntity (edict_t *pEntity, const char *szFileName)
{
   int index;

   char temp[128];
   
   if (!szFileName)
	   sprintf(temp,"bot%i.txt",ENTINDEX(pEntity));
   else
	   strcpy(temp, szFileName);

   FILE *fp = fopen(temp,"a");
   fprintf(fp,"\n");

   // now just dump the entity variables
   fprintf(fp, "pEntity->v.classname = %d (\"%s\")\n", pEntity->v.classname, STRING (pEntity->v.classname));
   fprintf(fp, "pEntity->v.globalname = %d (\"%s\")\n", pEntity->v.globalname, STRING (pEntity->v.globalname));
   fprintf(fp, "pEntity->v.origin = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.origin.x, pEntity->v.origin.y, pEntity->v.origin.z);
   fprintf(fp, "pEntity->v.oldorigin = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.oldorigin.x, pEntity->v.oldorigin.y, pEntity->v.oldorigin.z);
   fprintf(fp, "pEntity->v.velocity = Vector (%.1f, %.1f, %.1f) - Length %.3f - Length2D %.3f\n", pEntity->v.velocity.x, pEntity->v.velocity.y, pEntity->v.velocity.z, pEntity->v.velocity.Length (), pEntity->v.velocity.Length2D ());
   fprintf(fp, "pEntity->v.basevelocity = Vector (%.1f, %.1f, %.1f) - Length %.3f - Length2D %.3f\n", pEntity->v.basevelocity.x, pEntity->v.basevelocity.y, pEntity->v.basevelocity.z, pEntity->v.velocity.Length (), pEntity->v.velocity.Length2D ());
   fprintf(fp, "pEntity->v.clbasevelocity = Vector (%.1f, %.1f, %.1f) - Length %.3f - Length2D %.3f\n", pEntity->v.clbasevelocity.x, pEntity->v.clbasevelocity.y, pEntity->v.clbasevelocity.z, pEntity->v.velocity.Length (), pEntity->v.velocity.Length2D ());
   fprintf(fp, "pEntity->v.movedir = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.movedir.x, pEntity->v.movedir.y, pEntity->v.movedir.z);
   fprintf(fp, "pEntity->v.angles = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.angles.x, pEntity->v.angles.y, pEntity->v.angles.z);
   fprintf(fp, "pEntity->v.avelocity = Vector (%.1f, %.1f, %.1f) - Length %.3f - Length2D %.3f\n", pEntity->v.avelocity.x, pEntity->v.avelocity.y, pEntity->v.avelocity.z, pEntity->v.velocity.Length (), pEntity->v.velocity.Length2D ());
   fprintf(fp, "pEntity->v.punchangle = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.punchangle.x, pEntity->v.punchangle.y, pEntity->v.punchangle.z);
   fprintf(fp, "pEntity->v.v_angle = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.v_angle.x, pEntity->v.v_angle.y, pEntity->v.v_angle.z);
   fprintf(fp, "pEntity->v.endpos = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.endpos.x, pEntity->v.endpos.y, pEntity->v.endpos.z);
   fprintf(fp, "pEntity->v.startpos = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.startpos.x, pEntity->v.startpos.y, pEntity->v.startpos.z);
   fprintf(fp, "pEntity->v.impacttime = %.3f\n", pEntity->v.impacttime);
   fprintf(fp, "pEntity->v.starttime = %.3f\n", pEntity->v.starttime);
   fprintf(fp, "pEntity->v.fixangle = %d (%s)\n", pEntity->v.fixangle, (pEntity->v.fixangle == 0 ? "nothing" : (pEntity->v.fixangle == 1 ? "force view angles" : (pEntity->v.fixangle == 2 ? "add velocity" : "???"))));
   fprintf(fp, "pEntity->v.idealpitch = %.3f\n", pEntity->v.idealpitch);
   fprintf(fp, "pEntity->v.pitch_speed = %.3f\n", pEntity->v.pitch_speed);
   fprintf(fp, "pEntity->v.ideal_yaw = %.3f\n", pEntity->v.ideal_yaw);
   fprintf(fp, "pEntity->v.yaw_speed = %.3f\n", pEntity->v.yaw_speed);
   fprintf(fp, "pEntity->v.modelindex = %d\n", pEntity->v.modelindex);
   fprintf(fp, "pEntity->v.model = %d (\"%s\")\n", pEntity->v.model, STRING (pEntity->v.model));
   fprintf(fp, "pEntity->v.viewmodel = %d (\"%s\")\n", pEntity->v.viewmodel, STRING (pEntity->v.viewmodel));
   fprintf(fp, "pEntity->v.weaponmodel = %d (\"%s\")\n", pEntity->v.weaponmodel, STRING (pEntity->v.weaponmodel));
   fprintf(fp, "pEntity->v.absmin = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.absmin.x, pEntity->v.absmin.y, pEntity->v.absmin.z);
   fprintf(fp, "pEntity->v.absmax = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.absmax.x, pEntity->v.absmax.y, pEntity->v.absmax.z);
   fprintf(fp, "pEntity->v.mins = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.mins.x, pEntity->v.mins.y, pEntity->v.mins.z);
   fprintf(fp, "pEntity->v.maxs = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.maxs.x, pEntity->v.maxs.y, pEntity->v.maxs.z);
   fprintf(fp, "pEntity->v.size = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.size.x, pEntity->v.size.y, pEntity->v.size.z);
   fprintf(fp, "pEntity->v.ltime = %.3f (current time is %.3f)\n", pEntity->v.ltime, gpGlobals->time);
   fprintf(fp, "pEntity->v.nextthink = %.3f (current time is %.3f)\n", pEntity->v.nextthink, gpGlobals->time);
   fprintf(fp, "pEntity->v.movetype = %d (%s)\n", pEntity->v.movetype, (pEntity->v.movetype == 0 ? "MOVETYPE_NONE" : (pEntity->v.movetype == MOVETYPE_WALK ? "MOVETYPE_WALK" : (pEntity->v.movetype == MOVETYPE_STEP ? "MOVETYPE_STEP" : (pEntity->v.movetype == MOVETYPE_FLY ? "MOVETYPE_FLY" : (pEntity->v.movetype == MOVETYPE_TOSS ? "MOVETYPE_TOSS" : (pEntity->v.movetype == MOVETYPE_PUSH ? "MOVETYPE_PUSH" : (pEntity->v.movetype == MOVETYPE_NOCLIP ? "MOVETYPE_NOCLIP" : (pEntity->v.movetype == MOVETYPE_FLYMISSILE ? "MOVETYPE_FLYMISSILE" : (pEntity->v.movetype == MOVETYPE_BOUNCE ? "MOVETYPE_BOUNCE" : (pEntity->v.movetype == MOVETYPE_BOUNCEMISSILE ? "MOVETYPE_BOUNCEMISSILE" : (pEntity->v.movetype == MOVETYPE_FOLLOW ? "MOVETYPE_FOLLOW" : (pEntity->v.movetype == MOVETYPE_PUSHSTEP ? "MOVETYPE_PUSHSTEP" : "???")))))))))))));
   fprintf(fp, "pEntity->v.solid = %d (%s)\n", pEntity->v.solid, (pEntity->v.solid == SOLID_NOT ? "SOLID_NOT" : (pEntity->v.solid == SOLID_TRIGGER ? "SOLID_TRIGGER" : (pEntity->v.solid == SOLID_BBOX ? "SOLID_BBOX" : (pEntity->v.solid == SOLID_SLIDEBOX ? "SOLID_SLIDEBOX" : (pEntity->v.solid == SOLID_BSP ? "SOLID_BSP" : "???"))))));
   fprintf(fp, "pEntity->v.skin = %d (\"%s\")\n", pEntity->v.skin, STRING (pEntity->v.skin));
   fprintf(fp, "pEntity->v.body = %d (\"%s\")\n", pEntity->v.body, STRING (pEntity->v.body));
   sprintf (temp, ""); // prepare pattern string
   if (pEntity->v.effects & EF_BRIGHTFIELD) strcat (temp, "EF_BRIGHTFIELD | ");
   if (pEntity->v.effects & EF_MUZZLEFLASH) strcat (temp, "EF_MUZZLEFLASH | ");
   if (pEntity->v.effects & EF_BRIGHTLIGHT) strcat (temp, "EF_BRIGHTLIGHT | ");
   if (pEntity->v.effects & EF_DIMLIGHT) strcat (temp, "EF_DIMLIGHT | ");
   if (pEntity->v.effects & EF_INVLIGHT) strcat (temp, "EF_INVLIGHT | ");
   if (pEntity->v.effects & EF_NOINTERP) strcat (temp, "EF_NOINTERP | ");
   if (pEntity->v.effects & EF_LIGHT) strcat (temp, "EF_LIGHT | ");
   if (pEntity->v.effects & EF_NODRAW) strcat (temp, "EF_NODRAW | ");
   if (strlen (temp) > 2) temp[strlen (temp) - 3] = 0; // remove trailing " | "
   fprintf(fp, "pEntity->v.effects = %d (%s)\n", pEntity->v.effects, temp);
   fprintf(fp, "pEntity->v.gravity = %.3f (fraction /1 of normal)\n", pEntity->v.gravity);
   fprintf(fp, "pEntity->v.friction = %.3f\n", pEntity->v.friction);
   fprintf(fp, "pEntity->v.light_level = %d\n", pEntity->v.light_level);
   fprintf(fp, "pEntity->v.sequence = %d (\"%s\")\n", pEntity->v.sequence, STRING (pEntity->v.sequence));
   fprintf(fp, "pEntity->v.gaitsequence = %d (\"%s\")\n", pEntity->v.gaitsequence, STRING (pEntity->v.gaitsequence));
   fprintf(fp, "pEntity->v.frame = %.3f (position /255 of total in sequence)\n", pEntity->v.frame);
   fprintf(fp, "pEntity->v.animtime = %.3f (current time is %.3f)\n", pEntity->v.animtime, gpGlobals->time);
   fprintf(fp, "pEntity->v.framerate = %.3f (times normal speed)\n", pEntity->v.framerate);
   fprintf(fp, "pEntity->v.controller = {%d, %d, %d, %d}\n", pEntity->v.controller[0], pEntity->v.controller[1], pEntity->v.controller[2], pEntity->v.controller[3]);
   fprintf(fp, "pEntity->v.blending = {%d, %d}\n", pEntity->v.blending[0], pEntity->v.blending[1]);
   fprintf(fp, "pEntity->v.scale = %.3f\n", pEntity->v.scale);
   fprintf(fp, "pEntity->v.rendermode = %d (%s)\n", pEntity->v.rendermode, (pEntity->v.rendermode == kRenderNormal ? "kRenderNormal" : (pEntity->v.rendermode == kRenderTransColor ? "kRenderTransColor" : (pEntity->v.rendermode == kRenderTransTexture ? "kRenderTransTexture" : (pEntity->v.rendermode == kRenderGlow ? "kRenderGlow" : (pEntity->v.rendermode == kRenderTransAlpha ? "kRenderTransAlpha" : (pEntity->v.rendermode == kRenderTransAdd ? "kRenderTransAdd" : "???")))))));
   fprintf(fp, "pEntity->v.renderamt = %.3f\n", pEntity->v.renderamt);
   fprintf(fp, "pEntity->v.rendercolor = Vector (%.1f, %.1f, %.1f) (RGB)\n", pEntity->v.rendercolor.x, pEntity->v.rendercolor.y, pEntity->v.rendercolor.z);
   fprintf(fp, "pEntity->v.renderfx = %d (%s)\n", pEntity->v.renderfx, (pEntity->v.renderfx == kRenderFxNone ? "kRenderFxNone" : (pEntity->v.renderfx == kRenderFxPulseSlow ? "kRenderFxPulseSlow" : (pEntity->v.renderfx == kRenderFxPulseFast ? "kRenderFxPulseFast" : (pEntity->v.renderfx == kRenderFxPulseSlowWide ? "kRenderFxPulseSlowWide" : (pEntity->v.renderfx == kRenderFxPulseFastWide ? "kRenderFxPulseFastWide" : (pEntity->v.renderfx == kRenderFxFadeSlow ? "kRenderFxFadeSlow" : (pEntity->v.renderfx == kRenderFxFadeFast ? "kRenderFxFadeFast" : (pEntity->v.renderfx == kRenderFxSolidSlow ? "kRenderFxSolidSlow" : (pEntity->v.renderfx == kRenderFxSolidFast ? "kRenderFxSolidFast" : (pEntity->v.renderfx == kRenderFxStrobeSlow ? "kRenderFxStrobeSlow" : (pEntity->v.renderfx == kRenderFxStrobeFast ? "kRenderFxStrobeFast" : (pEntity->v.renderfx == kRenderFxStrobeFaster ? "kRenderFxStrobeFaster" : (pEntity->v.renderfx == kRenderFxFlickerSlow ? "kRenderFxFlickerSlow" : (pEntity->v.renderfx == kRenderFxFlickerFast ? "kRenderFxFlickerFast" : (pEntity->v.renderfx == kRenderFxNoDissipation ? "kRenderFxNoDissipation" : (pEntity->v.renderfx == kRenderFxDistort ? "kRenderFxDistort" : (pEntity->v.renderfx == kRenderFxHologram ? "kRenderFxHologram" : (pEntity->v.renderfx == kRenderFxDeadPlayer ? "kRenderFxDeadPlayer" : (pEntity->v.renderfx == kRenderFxExplode ? "kRenderFxExplode" : (pEntity->v.renderfx == kRenderFxGlowShell ? "kRenderFxGlowShell" : (pEntity->v.renderfx == kRenderFxClampMinScale ? "kRenderFxClampMinScale" : "???"))))))))))))))))))))));
   fprintf(fp, "pEntity->v.health = %.3f\n", pEntity->v.health);
   fprintf(fp, "pEntity->v.frags = %.3f\n", pEntity->v.frags);
   sprintf (temp, "00000000000000000000000000000000"); // prepare pattern string
   for (index = 0; index < 32; index++) if (pEntity->v.weapons & (1 << index)) temp[index] = '1';
   fprintf(fp, "pEntity->v.weapons = %d (%s)\n", pEntity->v.weapons, temp);
   fprintf(fp, "pEntity->v.takedamage = %.3f (%s)\n", pEntity->v.takedamage, (pEntity->v.takedamage == DAMAGE_NO ? "DAMAGE_NO" : (pEntity->v.takedamage == DAMAGE_YES ? "DAMAGE_YES" : (pEntity->v.takedamage == DAMAGE_AIM ? "DAMAGE_AIM" : "???"))));
   fprintf(fp, "pEntity->v.deadflag = %d (%s)\n", pEntity->v.deadflag, (pEntity->v.deadflag == DEAD_NO ? "DEAD_NO" : (pEntity->v.deadflag == DEAD_DYING ? "DEAD_DYING" : (pEntity->v.deadflag == DEAD_DEAD ? "DEAD_DEAD" : (pEntity->v.deadflag == DEAD_RESPAWNABLE ? "DEAD_RESPAWNABLE" : (pEntity->v.deadflag == DEAD_DISCARDBODY ? "DEAD_DISCARDBODY" : "???"))))));
   fprintf(fp, "pEntity->v.view_ofs = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.view_ofs.x, pEntity->v.view_ofs.y, pEntity->v.view_ofs.z);
   sprintf (temp, ""); // prepare pattern string
   if (pEntity->v.button & IN_ATTACK) strcat (temp, "IN_ATTACK | ");
   if (pEntity->v.button & IN_JUMP) strcat (temp, "IN_JUMP | ");
   if (pEntity->v.button & IN_DUCK) strcat (temp, "IN_DUCK | ");
   if (pEntity->v.button & IN_FORWARD) strcat (temp, "IN_FORWARD | ");
   if (pEntity->v.button & IN_BACK) strcat (temp, "IN_BACK | ");
   if (pEntity->v.button & IN_USE) strcat (temp, "IN_USE | ");
   if (pEntity->v.button & IN_CANCEL) strcat (temp, "IN_CANCEL | ");
   if (pEntity->v.button & IN_LEFT) strcat (temp, "IN_LEFT | ");
   if (pEntity->v.button & IN_RIGHT) strcat (temp, "IN_RIGHT | ");
   if (pEntity->v.button & IN_MOVELEFT) strcat (temp, "IN_MOVELEFT | ");
   if (pEntity->v.button & IN_MOVERIGHT) strcat (temp, "IN_MOVERIGHT | ");
   if (pEntity->v.button & IN_ATTACK2) strcat (temp, "IN_ATTACK2 | ");
   if (pEntity->v.button & IN_RUN) strcat (temp, "IN_RUN | ");
   if (pEntity->v.button & IN_RELOAD) strcat (temp, "IN_RELOAD | ");
   if (pEntity->v.button & IN_ALT1) strcat (temp, "IN_ALT1 | ");
   if (pEntity->v.button & IN_SCORE) strcat (temp, "IN_SCORE | ");
   if (strlen (temp) > 2) temp[strlen (temp) - 3] = 0; // remove trailing " | "
   fprintf(fp, "pEntity->v.button = %d (%s)\n", pEntity->v.button, temp);
   fprintf(fp, "pEntity->v.impulse = %d\n", pEntity->v.impulse);
   if (pEntity->v.chain != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.chain), STRING (pEntity->v.chain->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.chain = %s\n", temp);
   if (pEntity->v.dmg_inflictor != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.dmg_inflictor), STRING (pEntity->v.dmg_inflictor->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.dmg_inflictor = %s\n", temp);
   if (pEntity->v.enemy != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.enemy), STRING (pEntity->v.enemy->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.enemy = %s\n", temp);
   if (pEntity->v.aiment != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.aiment), STRING (pEntity->v.aiment->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.aiment = %s\n", temp);
   if (pEntity->v.owner != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.owner), STRING (pEntity->v.owner->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.owner = %s\n", temp);
   if (pEntity->v.groundentity != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.groundentity), STRING (pEntity->v.groundentity->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.groundentity = %s\n", temp);
   fprintf(fp, "pEntity->v.spawnflags = %d\n", pEntity->v.spawnflags);
   sprintf (temp, ""); // prepare pattern string
   if (pEntity->v.flags & FL_FLY) strcat (temp, "FL_FLY | ");
   if (pEntity->v.flags & FL_SWIM) strcat (temp, "FL_SWIM | ");
   if (pEntity->v.flags & FL_CONVEYOR) strcat (temp, "FL_CONVEYOR | ");
   if (pEntity->v.flags & FL_CLIENT) strcat (temp, "FL_CLIENT | ");
   if (pEntity->v.flags & FL_INWATER) strcat (temp, "FL_INWATER | ");
   if (pEntity->v.flags & FL_MONSTER) strcat (temp, "FL_MONSTER | ");
   if (pEntity->v.flags & FL_GODMODE) strcat (temp, "FL_GODMODE | ");
   if (pEntity->v.flags & FL_NOTARGET) strcat (temp, "FL_NOTARGET | ");
   if (pEntity->v.flags & FL_SKIPLOCALHOST) strcat (temp, "FL_SKIPLOCALHOST | ");
   if (pEntity->v.flags & FL_ONGROUND) strcat (temp, "FL_ONGROUND | ");
   if (pEntity->v.flags & FL_PARTIALGROUND) strcat (temp, "FL_PARTIALGROUND | ");
   if (pEntity->v.flags & FL_WATERJUMP) strcat (temp, "FL_WATERJUMP | ");
   if (pEntity->v.flags & FL_FROZEN) strcat (temp, "FL_FROZEN | ");
   if (pEntity->v.flags & FL_FAKECLIENT) strcat (temp, "FL_FAKECLIENT | ");
   if (pEntity->v.flags & FL_FLOAT) strcat (temp, "FL_FLOAT | ");
   if (pEntity->v.flags & FL_GRAPHED) strcat (temp, "FL_GRAPHED | ");
   if (pEntity->v.flags & FL_IMMUNE_WATER) strcat (temp, "FL_IMMUNE_WATER | ");
   if (pEntity->v.flags & FL_IMMUNE_SLIME) strcat (temp, "FL_IMMUNE_SLIME | ");
   if (pEntity->v.flags & FL_IMMUNE_LAVA) strcat (temp, "FL_IMMUNE_LAVA | ");
   if (pEntity->v.flags & FL_PROXY) strcat (temp, "FL_PROXY | ");
   if (pEntity->v.flags & FL_ALWAYSTHINK) strcat (temp, "FL_ALWAYSTHINK | ");
   if (pEntity->v.flags & FL_BASEVELOCITY) strcat (temp, "FL_BASEVELOCITY | ");
   if (pEntity->v.flags & FL_MONSTERCLIP) strcat (temp, "FL_MONSTERCLIP | ");
   if (pEntity->v.flags & FL_ONTRAIN) strcat (temp, "FL_ONTRAIN | ");
   if (pEntity->v.flags & FL_WORLDBRUSH) strcat (temp, "FL_WORLDBRUSH | ");
   if (pEntity->v.flags & FL_SPECTATOR) strcat (temp, "FL_SPECTATOR | ");
   if (pEntity->v.flags & FL_CUSTOMENTITY) strcat (temp, "FL_CUSTOMENTITY | ");
   if (pEntity->v.flags & FL_KILLME) strcat (temp, "FL_KILLME | ");
   if (pEntity->v.flags & FL_DORMANT) strcat (temp, "FL_DORMANT | ");
   if (strlen (temp) > 2) temp[strlen (temp) - 3] = 0; // remove trailing " | "
   fprintf(fp, "pEntity->v.flags = %d (%s)\n", pEntity->v.flags, temp);
   fprintf(fp, "pEntity->v.colormap = %d (0x%X)\n", pEntity->v.colormap, pEntity->v.colormap);
   fprintf(fp, "pEntity->v.team = %d\n", pEntity->v.team);
   fprintf(fp, "pEntity->v.max_health = %.3f\n", pEntity->v.max_health);
   fprintf(fp, "pEntity->v.teleport_time = %.3f\n", pEntity->v.teleport_time);
   fprintf(fp, "pEntity->v.armortype = %.3f\n", pEntity->v.armortype);
   fprintf(fp, "pEntity->v.armorvalue = %.3f\n", pEntity->v.armorvalue);
   fprintf(fp, "pEntity->v.waterlevel = %d (%s)\n", pEntity->v.waterlevel, (pEntity->v.waterlevel == 0 ? "not in water" : (pEntity->v.waterlevel == 2 ? "walking in water" : (pEntity->v.waterlevel == 3 ? "swimming in water" : "???"))));
   fprintf(fp, "pEntity->v.watertype = %d\n", pEntity->v.watertype);
   fprintf(fp, "pEntity->v.target = %d (\"%s\")\n", pEntity->v.target, STRING (pEntity->v.target));
   fprintf(fp, "pEntity->v.targetname = %d (\"%s\")\n", pEntity->v.targetname, STRING (pEntity->v.targetname));
   fprintf(fp, "pEntity->v.netname = %d (\"%s\")\n", pEntity->v.netname, STRING (pEntity->v.netname));
   fprintf(fp, "pEntity->v.message = %d (\"%s\")\n", pEntity->v.message, STRING (pEntity->v.message));
   fprintf(fp, "pEntity->v.dmg_take = %.3f\n", pEntity->v.dmg_take);
   fprintf(fp, "pEntity->v.dmg_save = %.3f\n", pEntity->v.dmg_save);
   fprintf(fp, "pEntity->v.dmg = %.3f\n", pEntity->v.dmg);
   fprintf(fp, "pEntity->v.dmgtime = %.3f (current time is %.3f)\n", pEntity->v.dmgtime, gpGlobals->time);
   fprintf(fp, "pEntity->v.noise = %d (\"%s\")\n", pEntity->v.noise, STRING (pEntity->v.noise));
   fprintf(fp, "pEntity->v.noise1 = %d (\"%s\")\n", pEntity->v.noise1, STRING (pEntity->v.noise1));
   fprintf(fp, "pEntity->v.noise2 = %d (\"%s\")\n", pEntity->v.noise2, STRING (pEntity->v.noise2));
   fprintf(fp, "pEntity->v.noise3 = %d (\"%s\")\n", pEntity->v.noise3, STRING (pEntity->v.noise3));
   fprintf(fp, "pEntity->v.speed = %.3f\n", pEntity->v.speed);
   fprintf(fp, "pEntity->v.air_finished = %.3f\n", pEntity->v.air_finished);
   fprintf(fp, "pEntity->v.pain_finished = %.3f\n", pEntity->v.pain_finished);
   fprintf(fp, "pEntity->v.radsuit_finished = %.3f\n", pEntity->v.radsuit_finished);
   if (pEntity->v.pContainingEntity != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.pContainingEntity), STRING (pEntity->v.pContainingEntity->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.pContainingEntity = %s\n", temp);
   fprintf(fp, "pEntity->v.playerclass = %d\n", pEntity->v.playerclass);
   fprintf(fp, "pEntity->v.maxspeed = %.3f\n", pEntity->v.maxspeed);
   fprintf(fp, "pEntity->v.fov = %.3f\n", pEntity->v.fov);
   fprintf(fp, "pEntity->v.weaponanim = %d\n", pEntity->v.weaponanim);
   fprintf(fp, "pEntity->v.pushmsec = %d\n", pEntity->v.pushmsec);
   fprintf(fp, "pEntity->v.bInDuck = %d (%s)\n", pEntity->v.bInDuck, (pEntity->v.bInDuck > 0 ? "TRUE" : "FALSE"));
   fprintf(fp, "pEntity->v.flTimeStepSound = %d (current time is %.3f)\n", pEntity->v.flTimeStepSound, gpGlobals->time);
   fprintf(fp, "pEntity->v.flSwimTime = %d (current time is %.3f)\n", pEntity->v.flSwimTime, gpGlobals->time);
   fprintf(fp, "pEntity->v.flDuckTime = %d (current time is %.3f)\n", pEntity->v.flDuckTime, gpGlobals->time);
   fprintf(fp, "pEntity->v.iStepLeft = %d\n", pEntity->v.iStepLeft);
   fprintf(fp, "pEntity->v.flFallVelocity = %.3f\n", pEntity->v.flFallVelocity);
   fprintf(fp, "pEntity->v.gamestate = %d\n", pEntity->v.gamestate);
   fprintf(fp, "pEntity->v.oldbuttons = %d\n", pEntity->v.oldbuttons);
   fprintf(fp, "pEntity->v.groupinfo = %d\n", pEntity->v.groupinfo);
   fprintf(fp, "pEntity->v.iuser1 = %d\n", pEntity->v.iuser1);
   fprintf(fp, "pEntity->v.iuser2 = %d\n", pEntity->v.iuser2);
   fprintf(fp, "pEntity->v.iuser3 = %d\n", pEntity->v.iuser3);
   fprintf(fp, "pEntity->v.fuser1 = %.3f\n", pEntity->v.fuser1);
   fprintf(fp, "pEntity->v.fuser2 = %.3f\n", pEntity->v.fuser2);
   fprintf(fp, "pEntity->v.fuser3 = %.3f\n", pEntity->v.fuser3);
   fprintf(fp, "pEntity->v.fuser4 = %.3f\n", pEntity->v.fuser4);
   fprintf(fp, "pEntity->v.vuser1 = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.vuser1.x, pEntity->v.vuser1.y, pEntity->v.vuser1.z);
   fprintf(fp, "pEntity->v.vuser2 = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.vuser2.x, pEntity->v.vuser2.y, pEntity->v.vuser2.z);
   fprintf(fp, "pEntity->v.vuser3 = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.vuser3.x, pEntity->v.vuser3.y, pEntity->v.vuser3.z);
   fprintf(fp, "pEntity->v.vuser4 = Vector (%.1f, %.1f, %.1f)\n", pEntity->v.vuser4.x, pEntity->v.vuser4.y, pEntity->v.vuser4.z);
   if (pEntity->v.euser1 != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.euser1), STRING (pEntity->v.euser1->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.euser1 = %s\n", temp);
   if (pEntity->v.euser2 != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.euser2), STRING (pEntity->v.euser2->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.euser2 = %s\n", temp);
   if (pEntity->v.euser3 != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.euser3), STRING (pEntity->v.euser3->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.euser3 = %s\n", temp);
   if (pEntity->v.euser4 != NULL) sprintf (temp, "Entity #%d (\"%s\")", ENTINDEX (pEntity->v.euser4), STRING (pEntity->v.euser4->v.classname)); else sprintf (temp, "NULL");
   fprintf(fp, "pEntity->v.euser4 = %s\n", temp);

   fprintf(fp,"\n");
   fclose(fp);
   return;
}

// Find a player by his name.
CBasePlayer *FindPlayerByName(const char *pName)
{
	for(int i=1; i <= gpGlobals->maxClients; i++)
	{
		edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(i);
		if(pEdict)
		{
			CBaseEntity *pEnt = CBaseEntity::Instance(pEdict);
			if(pEnt && pEnt->IsPlayer())
			{			
				const char *pNetName = STRING(pEnt->pev->netname);
				if(strcmp(pNetName, pName) == 0)
				{
					return (CBasePlayer*)pEnt;
				}
			}
		}
	}

	return NULL;
}

// Teleport a player infront of another player
void TelePortPlayerToPlayer(edict_t *pPlayer1, edict_t *pPlayer2)
{
	// Teleport him infront of us
	UTIL_MakeVectors(pPlayer1->v.v_angle);

	Vector v_src = pPlayer1->v.origin;
	Vector v_end = v_src + Vector(0,0,20) + gpGlobals->v_forward * 100;
	TraceResult tr;

	UTIL_TraceHull(v_src, v_end, dont_ignore_monsters, 1, pPlayer1, &tr);

	if (tr.flFraction >= 1.0)
		SET_ORIGIN(pPlayer2, v_end);
}

// Determine at which side an vector is
int UTIL_EntDir(CBaseEntity *pEntity, Vector v_vec)
{
	Vector v_src = pEntity->pev->origin;
	int vecDir = 0;

	Vector v_end1 = g_vecZero;
	Vector v_end2 = g_vecZero;
	float dist1 = 0.0;
	float dist2 = 0.0;

	UTIL_MakeVectors(pEntity->pev->angles);

	// Is the vector at the left side or at the right side ?
	v_end1 = v_src - gpGlobals->v_right * 100.0;
	v_end2 = v_src + gpGlobals->v_right * 100.0;

	dist1 = (v_vec - v_end1).Length();
	dist2 = (v_vec - v_end2).Length();

	if (dist1 > dist2)
		vecDir |= dir_right; // vector is at the right side
	else if (dist2 > dist1)
		vecDir |= dir_left; // vector is at the left side

	// Is the vector lower or higher ?
	if (v_src.z > v_vec.z)
		vecDir |= dir_down; // vector is lower
	else if (v_src.z < v_vec.z)
		vecDir |= dir_up; // vector is higher

	// Is the vector behind or infront ?
	v_end1 = v_src - gpGlobals->v_forward * 100.0;
	v_end2 = v_src + gpGlobals->v_forward * 100.0;

	dist1 = (v_vec - v_end1).Length();
	dist2 = (v_vec - v_end2).Length();

	if (dist1 > dist2)
		vecDir |= dir_forward; // vector is at the right side
	else if (dist2 > dist1)
		vecDir |= dir_back; // vector is at the left side

	return vecDir;
}

Vector PredictEntityPos(CBaseEntity *pEntity, float Time, bool UseTraceLine)
{
	if (pEntity->pev->velocity.Length() < 10.0)
		return pEntity->pev->origin; // don't bother with low velocities...

	float speed = pEntity->pev->velocity.Length() * Time;

	Vector v_src = pEntity->pev->origin;
	Vector v_end = v_src + pEntity->pev->velocity.Normalize() * speed;

	if (UseTraceLine)
	{
		TraceResult tr;
		UTIL_TraceHull(v_src, v_end, dont_ignore_monsters, human_hull,
					   pEntity->pev->pContainingEntity, &tr);
		return tr.vecEndPos;
	}
	else
		return v_end;
}

// I gave the following IsxxAttack functions a try and a catch block;
// the functions where giving crashes for an unknown reason...

bool IsAttack(edict_t *pent)
{
	try
	{
		if ((pent == NULL) || (IsNull(pent)))
			return false;

		if (pent->v.classname == 0)
			return false;
	}
	catch (...)
	{
#ifdef _DEBUG
		FILE *fp = fopen("bot.txt", "a");
		fprintf(fp, "IsAttack() Error\n");
		fclose(fp);
#endif

		return false;
	}

	return ((IsBeamAttack(pent)) || (IsNonBeamAttack(pent)) || (IsKiBall(pent)) || 
			(IsOtherAttack(pent)));
}

bool IsBeamAttack(edict_t *pent)
{
	try
	{
		if ((pent == NULL) || (IsNull(pent)))
			return false;

		if (pent->v.classname == 0)
			return false;

		char name[80]="";
		strcpy(name,STRING(pent->v.classname));
	
		return ((FStrEq(name,"blueattack")) || (FStrEq(name,"burningattack")) ||
			    (FStrEq(name,"greenattack")) || (FStrEq(name,"purpleattack")) ||
				(FStrEq(name,"yellowattack")) || (FStrEq(name,"kamehameha")) ||
				(FStrEq(name,"gallitgun")) || (FStrEq(name,"masenko")) ||
				(FStrEq(name,"powerbeam")) || (FStrEq(name,"mouthblast")) ||
				(FStrEq(name,"finalflash")));
	}
	catch (...)
	{
#ifdef _DEBUG
		FILE *fp = fopen("bot.txt", "a");
		fprintf(fp, "IsBeamAttack() Error\n");
		fclose(fp);
#endif

		return false;
	}
}

bool IsNonBeamAttack(edict_t *pent)
{
	try
	{
		if ((pent == NULL) || (IsNull(pent)))
			return false;

		if (pent->v.classname == 0)
			return false;

		char name[80]=""; 
		strcpy(name,STRING(pent->v.classname));

		return ((FStrEq(name,"bigbang")) || (FStrEq(name,"finishingbuster")) || (FStrEq(name,"Spirit Bomb")) || 
			    (FStrEq(name,"Special Beam Cannon")) || (FStrEq(name,"Death Ball")) || 
				(FStrEq(name,"shieldattack")) || (FStrEq(name,"Kame Torpedo")) || (FStrEq(name,"Scattering Beam")));
	}
	catch(...)
	{
#ifdef _DEBUG
		FILE *fp = fopen("bot.txt", "a");
		fprintf(fp, "IsNonBeamAttack() Error\n");
		fclose(fp);
#endif

		return false;
	}
}

bool IsKiBall(edict_t *pent)
{
	try
	{
		if ((pent == NULL) || (IsNull(pent)))
			return false;

		if (pent->v.classname == 0)
			return false;

		char name[80]="";
		strcpy(name,STRING(pent->v.classname));

		return ((FStrEq(name,"kiblast")) || (FStrEq(name,"scattershot")) ||
			    (FStrEq(name,"renzoku")));
	}
	catch (...)
	{
#ifdef _DEBUG
		FILE *fp = fopen("bot.txt", "a");
		fprintf(fp, "IsKiBall() Error\n");
		fclose(fp);
#endif

		return false;
	}
}

bool IsOtherAttack(edict_t *pent)
{
	try
	{
		if ((pent == NULL) || (IsNull(pent)))
			return false;

		if (pent->v.classname == 0)
			return false;

		char name[80]="";
		strcpy(name,STRING(pent->v.classname));

		return ((FStrEq(name,"Destructo Disc")) || (FStrEq(name,"Frieza Disc")) || 
				(FStrEq(name,"rock")));
	}
	catch (...)
	{
#ifdef _DEBUG
		FILE *fp = fopen("bot.txt", "a");
		fprintf(fp, "IsOtherAttack() Error\n");
		fclose(fp);
#endif

		return false;
	}
}

short UTIL_GetHeadingPercentage(CBaseEntity *pEnt1, CBaseEntity *pEnt2)
{
	if ((!pEnt1) || (!pEnt2))
		return 0;

	if (pEnt2->pev->velocity.Length() == 0.0f)
		return 0;

	Vector v_predict = PredictEntityPos(pEnt2, 0.01f, false);

	float DistEnt1ToEnt2 = UTIL_Distance(pEnt1->pev->origin, pEnt2->pev->origin);
	float PredictDist = UTIL_Distance(pEnt1->pev->origin, v_predict);

	if (PredictDist > DistEnt1ToEnt2)
		return 0;

	float MaxDistCloser = pEnt2->pev->velocity.Length() * 0.01f;
	float RealDistCloser = DistEnt1ToEnt2 - PredictDist;

	return ((RealDistCloser / MaxDistCloser) * 100.0f);
}

bool EntityHeadsToPlayer(CBasePlayer *pPlayer, CBaseEntity *pEntity)
{
	return (UTIL_GetHeadingPercentage(pPlayer, pEntity) >= 65);
}

// Function code by PMB
bool EntIsInFieldOfView(CBaseEntity *pPlayer, CBaseEntity *pEnt)
{
	/* Disabled, doesnt seem to work right
	static Vector v_deviation;

	// compute deviation angles (angles between pPlayer's forward direction and v_location)
	v_deviation = WrapAngles (UTIL_VecToAngles (pEnt->pev->origin - (pPlayer->EyePosition()))
								  - pPlayer->pev->v_angle);

	// is v_location outside pPlayer's FOV width (90 degree) ?
	if (fabs (v_deviation.x) > 45)
		return false; // then v_location is not visible

	// is v_location outside pPlayer's FOV height (60 degree: consider the 4:3 screen ratio) ?
	//if (fabs (v_deviation.y) > 30)
	//	return false; // then v_location is not visible*/

	return (FInViewCone(&pEnt->pev->origin, pPlayer->edict()));
}

bool FInViewCone(Vector *pOrigin, edict_t *pEdict)
{
	Vector2D vec2LOS;
    float    flDot;

    UTIL_MakeVectors ( pEdict->v.angles );

    vec2LOS = ( *pOrigin - pEdict->v.origin ).Make2D();
    vec2LOS = vec2LOS.Normalize();

    flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() );

    if ( flDot > 0.50 )  // 60 degree field of view 
    {
		return TRUE;
    }
    else
    {
		return FALSE;
    }
}

// With this function bots can chat
void UTIL_HostSay( CBasePlayer *pPlayer, int teamonly, char *message )
{
	int   j;
    char  text[128];
    char *pc;
    CBaseEntity *client;

    if ((!message) || (!*message))
		return;

    // make sure the text has content
    for ( pc = message; pc != NULL && *pc != 0; pc++ )
    {
		if ( isprint( *pc ) && !isspace( *pc ) )
		{
			pc = NULL;   // we've found an alphanumeric character,  so text is valid
			break;
		}
    }

    if ( pc != NULL )
		return;  // no character found, so say nothing 

    // turn on color set 2  (color on,  no sound)
    if ( teamonly )
		sprintf( text, "%c(TEAM) %s: ", 2, STRING( pPlayer->pev->netname ) );
    else
		sprintf( text, "%c%s: ", 2, STRING( pPlayer->pev->netname ) );

    j = sizeof(text) - 2 - strlen(text);  // -2 for /n and null terminator
    if ( (int)strlen(message) > j )
		message[j] = 0;

	ChatClass.StoreChatMsg(pPlayer->edict(), message);

    strcat( text, message );
    strcat( text, "\n" );

    // loop through all players
    // Start with the first player.
    // This may return the world in single player if the client types something between levels or during spawn
    // so check it, or it will infinite loop

    if (gmsgSayText == 0)
		gmsgSayText = REG_USER_MSG( "SayText", -1 );

    client = NULL;
    while ( ((client = UTIL_FindEntityByClassname( client, "player" )) != NULL) &&
            (!FNullEnt(client->edict())) ) 
    {
		if ( client == pPlayer )  // skip sender of message
			continue;

        if ( teamonly && (pPlayer->pev->team != client->pev->team) )
			continue;

		MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev );
			WRITE_BYTE( pPlayer->entindex() );
			WRITE_STRING( text );
		MESSAGE_END();
    }

    // print to the sending client
    MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, pPlayer->pev );
		WRITE_BYTE( pPlayer->entindex() );
		WRITE_STRING( text );
    MESSAGE_END();
   
    // echo to server console
    g_engfuncs.pfnServerPrint( text );
}

bool UTIL_DBsAreGathered()
{
	CBaseEntity *pent = NULL;
	// Only need to examine the first DB because if one DB is glowing, all are
	pent = UTIL_FindEntityByClassname(pent, "dragonball");

	if (IsNull(pent))
		return false;

	return (pent->pev->renderfx == kRenderFxGlowShell); // DB is glowing so they must be gathered
}

bool UTIL_DBsAreActive()
{
	CBaseEntity *pent = NULL;
	// Only need to examine the first DB because if one DB is active is, all are
	pent = UTIL_FindEntityByClassname(pent, "dragonball");

	if (IsNull(pent))
		return false;

	return ((pent->pev->solid != SOLID_NOT) && (pent->pev->movetype != MOVETYPE_NOCLIP) &&
			(pent->pev->skin == 0));
}

// Simulates damaging a player by a player with a specified weapon name
void UTIL_DamagePlayer(CBasePlayer *pKiller, CBasePlayer *pVictim, const char *Weapon, float Damage)
{
	static CBaseEntity *pDamageEnt = NULL;

	if (!pDamageEnt)
		pDamageEnt = UTIL_CreateEnt("info_target",Vector(0,0,0),Vector(0,0,0),	NULL);

	if (pDamageEnt)
	{
		UTIL_MakeVectors(WrapAngles(pVictim->pev->angles+Vector(180,180,180)));
		pDamageEnt->pev->velocity = pDamageEnt->pev->velocity.Normalize() * 180 + gpGlobals->v_forward * 10;
		pDamageEnt->pev->origin = pKiller->pev->origin;
		pDamageEnt->pev->owner = pKiller->edict();
		pDamageEnt->pev->classname = MAKE_STRING(Weapon);
		pVictim->TakeDamage( pDamageEnt->pev, pKiller->pev, Damage, 0);
	}
}

// Function code by cheesy
CBaseEntity *UTIL_CreateEnt( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) 
{ 
      edict_t *pent; 
      CBaseEntity *pEntity; 

      pent = CREATE_NAMED_ENTITY( MAKE_STRING( szName )); 

      if ( FNullEnt( pent ) ) 
      {
#ifdef _DEBUG
            ALERT ( at_console, "NULL Ent in Create!\n" ); 
#endif
            return NULL; 
      }
 
      if ( !pent ) 
            pent = ENT(0); 

      pEntity = (CBaseEntity *)GET_PRIVATE(pent);  

      pEntity->pev->owner = pentOwner; 
      pEntity->pev->origin = vecOrigin; 
      pEntity->pev->angles = vecAngles; 

      DispatchSpawn( pEntity->edict() ); 

      return pEntity; 
}

void UTIL_SpawnMonster(const char *szName, Vector Origin, Vector Angles, CBaseEntity *pOwner)
{
	edict_t	*pent;
	entvars_t		*pevCreate;

	pent = CREATE_NAMED_ENTITY( MAKE_STRING(szName) );

	if ( FNullEnt( pent ) )
	{
		ALERT ( at_console, "NULL Ent in MonsterMaker!\n" );
		return;
	}
	
	pevCreate = VARS( pent );
	pevCreate->origin = Origin;
	pevCreate->angles = Angles;
	SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND );

	DispatchSpawn( ENT( pevCreate ) );
	pevCreate->owner = pOwner->edict();

	UTIL_DrawBeam(BotManager.GetHost(), BotManager.GetHost()->pev->origin, pevCreate->origin, 10, 1, 255, 0, 0, 250, 10, 20);
}

CBaseEntity *UTIL_GetLastAttackFromPlayer(CBasePlayer *pPlayer)
{
	CBaseEntity *pAttack = NULL, *pLastAttack = NULL;
	edict_t *pEdict = pPlayer->edict(); // Shortcut

	while ((pAttack = UTIL_FindEntityByString(pAttack, "globalname", "magic_attack")) != NULL)
	{
		if (IsNull(pAttack))
			continue;

		if (pAttack->pev->owner != pEdict)
			continue;

		pLastAttack = pAttack;
	}

	return pLastAttack;
}

CBaseEntity *UTIL_GetAttackFromPlayerByName(CBasePlayer *pPlayer, const char *szName)
{
	CBaseEntity *pAttack = NULL;
	edict_t *pEdict = pPlayer->edict(); // Shortcut

	while ((pAttack = UTIL_FindEntityByClassname(pAttack, szName)) != NULL)
	{
		if (pAttack->pev->owner != pEdict)
			continue;

		if (!IsNull(pAttack))
			return pAttack;
	}

	return NULL;
}

// Fires 50(ouch) tracelines to determine what is the nearest pos of a player
Vector GetNearestCollision(CBaseEntity *pEntity, float Range)
{
	Vector v_nearest = g_vecZero;
	Vector v_src, v_dest, v_dest2;
	TraceResult tr, tr2;
	int i, j;
	float nearestdistance = 9999.9;
	float distance, distance2, dist, x, y;
	x = y = 0.0;

	for (i=0;i<5;i++)
	{ 
		switch (i)
		{
		case 0:
			x=0.0;
			break;
		case 1:
			x=-40.0;
			break;
		case 2:
			x=40.0;
			break;
		case 3:
			x=-89.0;
			break;
		case 4:
			x=89.0;
			break;
		default:
			break;
		}

		for (j=0;j<5;j++)
		{
			switch (j)
			{
			case 0:
				y=-90.0;
				break;
			case 1:
				y=-45.0;
				break;
			case 2:
				y=0.0;
				break;
			case 3:
				y=45.0;
				break;
			case 4:
				y=90.0;
				break;
			default:
				break;
			}

			v_src = WrapAngles(pEntity->pev->v_angle);
			v_src.y = UTIL_WrapAngle (v_src.y + y);
			v_src.x = UTIL_WrapAngle (x);

			UTIL_MakeVectors(v_src);

			v_dest = pEntity->pev->origin + gpGlobals->v_forward * Range;

			v_dest2 = pEntity->pev->origin - gpGlobals->v_forward * Range;

	        UTIL_TraceHull (pEntity->pev->origin, v_dest,
		                    ignore_monsters, human_hull, pEntity->pev->pContainingEntity, &tr);

	        UTIL_TraceHull (pEntity->pev->origin, v_dest2,
		                    ignore_monsters, human_hull, pEntity->pev->pContainingEntity, &tr2);

			distance = (tr.vecEndPos - pEntity->pev->origin).Length();
			distance2 = (tr2.vecEndPos - pEntity->pev->origin).Length();

			if ((distance < distance2) && (tr.flFraction < 1.0f))
			{
				dist = distance;
				v_dest = tr.vecEndPos;
			}
			else if ((distance2 <= distance) && (tr2.flFraction < 1.0f))
			{
				dist = distance2;
				v_dest = tr2.vecEndPos;
			}
			else
				continue;

			if (dist < nearestdistance)
			{
				nearestdistance = dist;
				v_nearest = v_dest;
			}
		}
	}

	return v_nearest;
}

// Fires 50(ouch) tracelines to determine what is the furthest collision of a entity
Vector GetFurthestCollision(CBaseEntity *pEntity, float Range)
{
	Vector v_furthest = g_vecZero;
	Vector v_src, v_dest, v_dest2;
	TraceResult tr, tr2;
	int i, j;
	float furthestdistance = 0.0f;
	float distance, distance2, dist, x, y;
	x = y = 0.0;

	for (i=0;i<5;i++)
	{ 
		switch (i)
		{
		case 0:
			x=0.0;
			break;
		case 1:
			x=-40.0;
			break;
		case 2:
			x=40.0;
			break;
		case 3:
			x=-89.0;
			break;
		case 4:
			x=89.0;
			break;
		default:
			break;
		}

		for (j=0;j<5;j++)
		{
			switch (j)
			{
			case 0:
				y=-90.0;
				break;
			case 1:
				y=-45.0;
				break;
			case 2:
				y=0.0;
				break;
			case 3:
				y=45.0;
				break;
			case 4:
				y=90.0;
				break;
			default:
				break;
			}

			v_src = WrapAngles(pEntity->pev->v_angle);
			v_src.y = UTIL_WrapAngle (v_src.y + y);
			v_src.x = UTIL_WrapAngle (x);

			UTIL_MakeVectors(v_src);

			v_dest = pEntity->pev->origin + gpGlobals->v_forward * Range;

			v_dest2 = pEntity->pev->origin - gpGlobals->v_forward * Range;

	        UTIL_TraceHull (pEntity->pev->origin, v_dest,
		                    ignore_monsters, human_hull, pEntity->pev->pContainingEntity, &tr);

	        UTIL_TraceHull (pEntity->pev->origin, v_dest2,
		                    ignore_monsters, human_hull, pEntity->pev->pContainingEntity, &tr2);

			distance = (tr.vecEndPos - pEntity->pev->origin).Length();
			distance2 = (tr2.vecEndPos - pEntity->pev->origin).Length();

			if ((distance > distance2) && (tr.flFraction < 1.0f))
			{
				dist = distance;
				v_dest = tr.vecEndPos;
			}
			else
			{
				dist = distance2;
				v_dest = tr2.vecEndPos;
			}

			if (dist > furthestdistance)
			{
				furthestdistance = dist;
				v_furthest = v_dest;
			}
		}
	}

	return v_furthest;
}

// Fires a trace hull to a given distance and gives the distance how far the trace went
float GetCollisionDist(CBaseEntity *pEnt, int iDir, float flTraceDist)
{
	Vector v_src;

	if (pEnt->IsPlayer())
		v_src = pEnt->pev->v_angle;
	else
		v_src = pEnt->pev->angles;

	TraceResult tr;
	Vector v_end;

	tr.flFraction = 0.0f;
	v_src.x = 0;

	if (iDir & dir_left)
	{
		if (iDir & dir_back)
			v_src.y = UTIL_WrapAngle(v_src.y - 45);
		else if (iDir & dir_forward)
			v_src.y = UTIL_WrapAngle(v_src.y + 45);
		else
			v_src.y = UTIL_WrapAngle(v_src.y + 90);
	}
	if (iDir & dir_right)
	{
		if (iDir & dir_back)
			v_src.y = UTIL_WrapAngle(v_src.y + 45);
		else if (iDir & dir_forward)
			v_src.y = UTIL_WrapAngle(v_src.y - 45);
		else
			v_src.y = UTIL_WrapAngle(v_src.y - 90);
	}
	if (iDir & dir_up)
	{
		if ((iDir & dir_left) || (iDir & dir_right) ||
			(iDir & dir_forward) || (iDir & dir_back))
			v_src.x = -45;
		else
			v_src.x = -90;
	}
	if (iDir & dir_down)
	{
		if ((iDir & dir_left) || (iDir & dir_right) ||
			(iDir & dir_forward) || (iDir & dir_back))
			v_src.x = 45;
		else
			v_src.x = 90;
	}
	if (iDir & dir_back)
		v_src.y = UTIL_WrapAngle(v_src.y + 180);


	UTIL_MakeVectors(v_src);
	v_end = pEnt->pev->origin + gpGlobals->v_forward * flTraceDist;
	UTIL_TraceHull(pEnt->pev->origin, v_end, dont_ignore_monsters, human_hull,
				   pEnt->pev->pContainingEntity, &tr);

	return (tr.flFraction * flTraceDist);
}

bool IsVisible(Vector v_vec1, Vector v_vec2, CBaseEntity *pEntIgnore)
{
	TraceResult tr;
	edict_t *pIgnore = (pEntIgnore) ? pEntIgnore->edict() : NULL;

	UTIL_TraceHull(v_vec1, v_vec2, ignore_monsters, human_hull, pIgnore, &tr);
	
	return (tr.flFraction >= 1.0f);
}

bool UTIL_IsInBModel(Vector v_origin, CBaseEntity *pEnt)
{
	return ((v_origin.x >= pEnt->pev->absmin.x) &&
			(v_origin.x <= (pEnt->pev->absmin.x + pEnt->pev->size.x)) &&
			(v_origin.y >= pEnt->pev->absmin.y) &&
			(v_origin.y <= (pEnt->pev->absmin.y + pEnt->pev->size.y)) &&
			(v_origin.z >= pEnt->pev->absmin.z) &&
			(v_origin.z <= (pEnt->pev->absmin.z + pEnt->pev->size.z)));
}

char *UTIL_GetAnimName(CBaseEntity *pEnt, int Anim)
{
	void *pmodel = GET_MODEL_PTR( ENT(pEnt->pev) );
	studiohdr_t *pstudiohdr;
	
	pstudiohdr = (studiohdr_t *)pmodel;
	if (! pstudiohdr)
		return 0;

	mstudioseqdesc_t	*pseqdesc;

	pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);

	return pseqdesc[Anim].label;
}

#ifdef _DEBUG

/* DEBUG FUNCTIONS */

void DisplayDebugTexts()
{
	if (!UTIL_IsValidPlayer(BotManager.GetHost(), false, false))
		return;

	short i;
	float NearestBotDist = 9999.9, dist;
	CBot *pNearestBot = NULL;

	for (i=1;i<=gpGlobals->maxClients;i++)
	{
		CBasePlayer *pPlayer = (CBasePlayer *)UTIL_PlayerByIndex(i);
		if ((UTIL_IsValidPlayer(pPlayer, false)) && (UTIL_IsBot(pPlayer)))
		{
			dist = UTIL_Distance(BotManager.GetHost()->pev->origin, pPlayer->pev->origin);

			if (NearestBotDist > dist)
			{
				NearestBotDist = dist;
				pNearestBot = UTIL_GetBotPointer(pPlayer);
			}
		}
	}

	if (pNearestBot)
	{
		entvars_t *pev = pNearestBot->pev;
		rcout << "Info for bot: " << STRING(pev->netname) << "\n";

		rcout << "CurrentTask: ";
		if (pNearestBot->m_pCurrentBotTask)
			rcout << int(pNearestBot->m_pCurrentBotTask->TaskIdentify()) << "\n";
		else
			rcout << "None\n";

		rcout << "Previous task: " << int(pNearestBot->m_ePrevTask) << "\n";

		rcout << "\nStatus: \n\n";
		rcout << "Health: " << pev->health << "\nKi: " << pev->fuser4 << "\n";
		rcout << "Max speed: " << pNearestBot->GetMaxSpeed() << "\n";
		rcout << "Power Level: " << pNearestBot->m_iPowerLevel << "\n";
//		rcout << "Power struggle value: " << bots[NearestBotInd].bot_powerstrug << "\n";
//		rcout << "Charge beam value: " << bots[NearestBotInd].ChargeBeamVal << "\n";
//		rcout << "DangerLevel: " << pNearestBot->m_sDangerLevel << "\n";

		rcout << "\nCurrent Enemy: ";
		if (pNearestBot->m_pBotEnemy)
			rcout << STRING(pNearestBot->m_pBotEnemy->pev->netname) << "\n\n";
		else
			rcout << "NULL\n\n";

		rcout << "Hunting player: ";
		if (pNearestBot->m_pHuntPlayer)
			rcout << STRING(pNearestBot->m_pHuntPlayer->pev->netname) << "\n";
		else
			rcout << "NULL\n";

		rcout << "\nSettings: \n\n";
		rcout << "Melee percent: " << pNearestBot->m_pPersonality->melee_percent << "\n";
		rcout << "Teleport percent: " << pNearestBot->m_pPersonality->teleport_percent << "\n";
		rcout << "Swoop percent: " << pNearestBot->m_pPersonality->swoop_percent << "\n";
		rcout << "AggrLevel: " << pNearestBot->m_pPersonality->aggression_level << "\n";
		rcout << "Skill: " << pNearestBot->m_bSkillNr << "\n";
		rcout << "Perso: " << pNearestBot->m_pPersonality->perso_name << "\n";
		rcout << "DB Role: " << pNearestBot->m_eBotDBType << "\n";

//		rcout << "\nDelays: \n\n";
//		rcout << "Teleport delay: " << (bots[NearestBotInd].teleport_delay - gpGlobals->time) << "\n";

//		if (bots[NearestBotInd].CurrentBotTask)
//			rcout << "General Delay: " << (bots[NearestBotInd].CurrentBotTask->Delay - gpGlobals->time) << "\n";

	}
}

void CreateTaskForEveryBot(ETaskCode TaskCode)
{
	CBasePlayer *pPlayer;
	CBot *pBot;
	short s;

	for(s=1;s<=gpGlobals->maxClients;s++)
	{
		pPlayer = (CBasePlayer *)UTIL_PlayerByIndex(s);

		if (!UTIL_IsValidPlayer(pPlayer) || !UTIL_IsBot(pPlayer))
			continue; // Skip invalid players and non bots
			

		pBot = UTIL_GetBotPointer(pPlayer);
		if (!pBot)
			continue;

		pBot->MakeTask(TaskCode);
	}
}

void CreateComboForEveryBot(EComboType CT)
{
	CBasePlayer *pPlayer;
	CBot *pBot;
	short s;

	for(s=1;s<=gpGlobals->maxClients;s++)
	{
		pPlayer = (CBasePlayer *)UTIL_PlayerByIndex(s);

		if (!UTIL_IsValidPlayer(pPlayer) || !UTIL_IsBot(pPlayer))
			continue; // Skip invalid players and non bots
			

		pBot = UTIL_GetBotPointer(pPlayer);
		if (!pBot)
			continue;

		pBot->MakeCombo(CT);
	}
}

Vector DebugVecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj )
{
	extern cvar_t *g_psv_gravity;
	float			flGravity = g_psv_gravity->value * flGravityAdj;

	Vector vecGrenadeVel = (vecSpot2 - vecSpot1);

	// throw at a constant time
	float time = vecGrenadeVel.Length( ) / flSpeed;
	vecGrenadeVel = vecGrenadeVel * (1.0 / time);

	// adjust upward toss to compensate for gravity loss
	vecGrenadeVel.z += flGravity * time * 0.5;
	UTIL_DrawBeam(BotManager.GetHost(), vecSpot1, vecSpot1 + vecGrenadeVel * 64, 10, 1, 255, 255, 255, 250, 10, 20);

	Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
	vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5);
	
	TraceResult tr;
	UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr);
	UTIL_DrawBeam(BotManager.GetHost(), vecSpot1, vecApex, 10, 1, 255, 0, 0, 250, 10, 20);
	if (tr.flFraction != 1.0)
	{
		// fail!
		return g_vecZero;
	}

	UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr);
	UTIL_DrawBeam(BotManager.GetHost(), vecSpot2, vecApex, 10, 1, 0, 0, 255, 250, 10, 20);
	if (tr.flFraction != 1.0)
	{
		// fail!
		return g_vecZero;
	}

	return vecGrenadeVel;
}

#endif