mirror of
https://github.com/ENSL/NS.git
synced 2024-11-24 13:31:12 +00:00
8ec7b4bf0b
git-svn-id: https://unknownworlds.svn.cloudforge.com/ns1@352 67975925-1194-0748-b3d5-c16f83f1a3a1
661 lines
17 KiB
C++
661 lines
17 KiB
C++
/***
|
|
*
|
|
* Copyright (c) 1999, Valve LLC. All rights reserved.
|
|
*
|
|
* This product contains software technology licensed from Id
|
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* Use, distribution, and modification of this source code and/or resulting
|
|
* object code is restricted to non-commercial enhancements to products from
|
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
|
* without written permission from Valve LLC.
|
|
*
|
|
****/
|
|
|
|
//
|
|
// HPB_bot - botman's High Ping Bastard bot
|
|
//
|
|
// (http://planethalflife.com/botman/)
|
|
//
|
|
// util.cpp
|
|
//
|
|
|
|
#include "dlls/extdll.h"
|
|
#include "dlls/util.h"
|
|
#include "HPB_bot/engine/engine.h"
|
|
#include "dlls/cbase.h"
|
|
#include "dlls/player.h"
|
|
|
|
#include "bot.h"
|
|
#include "bot_func.h"
|
|
|
|
|
|
extern int mod_id;
|
|
extern bot_t bots[32];
|
|
extern edict_t *pent_info_ctfdetect;
|
|
extern char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH];
|
|
extern int num_teams;
|
|
|
|
int gmsgTextMsg = 0;
|
|
int gmsgSayText = 0;
|
|
int gmsgShowMenu = 0;
|
|
|
|
|
|
Vector UTIL_VecToAngles( const Vector &vec )
|
|
{
|
|
float rgflVecOut[3];
|
|
VEC_TO_ANGLES(vec, rgflVecOut);
|
|
return Vector(rgflVecOut);
|
|
}
|
|
|
|
|
|
// Overloaded to add IGNORE_GLASS
|
|
void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr )
|
|
{
|
|
TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass?0x100:0), pentIgnore, ptr );
|
|
}
|
|
|
|
|
|
void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr )
|
|
{
|
|
TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), pentIgnore, ptr );
|
|
}
|
|
|
|
|
|
void UTIL_MakeVectors( const Vector &vecAngles )
|
|
{
|
|
MAKE_VECTORS( vecAngles );
|
|
}
|
|
|
|
|
|
edict_t *UTIL_FindEntityInSphere( edict_t *pentStart, const Vector &vecCenter, float flRadius )
|
|
{
|
|
edict_t *pentEntity;
|
|
|
|
pentEntity = FIND_ENTITY_IN_SPHERE( pentStart, vecCenter, flRadius);
|
|
|
|
if (!FNullEnt(pentEntity))
|
|
return pentEntity;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
edict_t *UTIL_FindEntityByString( edict_t *pentStart, const char *szKeyword, const char *szValue )
|
|
{
|
|
edict_t *pentEntity;
|
|
|
|
pentEntity = FIND_ENTITY_BY_STRING( pentStart, szKeyword, szValue );
|
|
|
|
if (!FNullEnt(pentEntity))
|
|
return pentEntity;
|
|
return NULL;
|
|
}
|
|
|
|
edict_t *UTIL_FindEntityByClassname( edict_t *pentStart, const char *szName )
|
|
{
|
|
return UTIL_FindEntityByString( pentStart, "classname", szName );
|
|
}
|
|
|
|
edict_t *UTIL_FindEntityByTargetname( edict_t *pentStart, const char *szName )
|
|
{
|
|
return UTIL_FindEntityByString( pentStart, "targetname", szName );
|
|
}
|
|
|
|
|
|
int UTIL_PointContents( const Vector &vec )
|
|
{
|
|
return POINT_CONTENTS(vec);
|
|
}
|
|
|
|
|
|
void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax )
|
|
{
|
|
SET_SIZE( ENT(pev), vecMin, vecMax );
|
|
}
|
|
|
|
|
|
void UTIL_SetOrigin( entvars_t *pev, const Vector &vecOrigin )
|
|
{
|
|
SET_ORIGIN(ENT(pev), vecOrigin );
|
|
}
|
|
|
|
|
|
void ClientPrint( edict_t *pEntity, int msg_dest, const char *msg_name)
|
|
{
|
|
// if (gmsgTextMsg == 0)
|
|
// gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 );
|
|
//
|
|
// pfnMessageBegin( MSG_ONE, gmsgTextMsg, NULL, pEntity );
|
|
//
|
|
// pfnWriteByte( msg_dest );
|
|
// pfnWriteString( msg_name );
|
|
// pfnMessageEnd();
|
|
}
|
|
|
|
void UTIL_SayText( const char *pText, edict_t *pEdict )
|
|
{
|
|
// if (gmsgSayText == 0)
|
|
// gmsgSayText = REG_USER_MSG( "SayText", -1 );
|
|
//
|
|
// pfnMessageBegin( MSG_ONE, gmsgSayText, NULL, pEdict );
|
|
// pfnWriteByte( ENTINDEX(pEdict) );
|
|
// if (mod_id == FRONTLINE_DLL)
|
|
// pfnWriteShort(0);
|
|
// pfnWriteString( pText );
|
|
// pfnMessageEnd();
|
|
}
|
|
|
|
|
|
void UTIL_HostSay( edict_t *pEntity, int teamonly, char *message )
|
|
{
|
|
// int j;
|
|
// char text[128];
|
|
// char *pc;
|
|
// int sender_team, player_team;
|
|
// edict_t *client;
|
|
//
|
|
// // 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( pEntity->v.netname ) );
|
|
// else
|
|
// sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) );
|
|
//
|
|
// j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator
|
|
// if ( (int)strlen(message) > j )
|
|
// message[j] = 0;
|
|
//
|
|
// 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 );
|
|
//
|
|
// sender_team = UTIL_GetTeam(pEntity);
|
|
//
|
|
// client = NULL;
|
|
// while ( ((client = UTIL_FindEntityByClassname( client, "player" )) != NULL) &&
|
|
// (!FNullEnt(client)) )
|
|
// {
|
|
// if ( client == pEntity ) // skip sender of message
|
|
// continue;
|
|
//
|
|
// player_team = UTIL_GetTeam(client);
|
|
//
|
|
// if ( teamonly && (sender_team != player_team) )
|
|
// continue;
|
|
//
|
|
// pfnMessageBegin( MSG_ONE, gmsgSayText, NULL, client );
|
|
// pfnWriteByte( ENTINDEX(pEntity) );
|
|
// if (mod_id == FRONTLINE_DLL)
|
|
// pfnWriteShort(0);
|
|
// pfnWriteString( text );
|
|
// pfnMessageEnd();
|
|
// }
|
|
//
|
|
// // print to the sending client
|
|
// pfnMessageBegin( MSG_ONE, gmsgSayText, NULL, pEntity );
|
|
// pfnWriteByte( ENTINDEX(pEntity) );
|
|
// if (mod_id == FRONTLINE_DLL)
|
|
// pfnWriteShort(0);
|
|
// pfnWriteString( text );
|
|
// pfnMessageEnd();
|
|
//
|
|
// // echo to server console
|
|
// g_engfuncs.pfnServerPrint( text );
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
edict_t *DBG_EntOfVars( const entvars_t *pev )
|
|
{
|
|
if (pev->pContainingEntity != NULL)
|
|
return pev->pContainingEntity;
|
|
ALERT(at_console, "entvars_t pContainingEntity is NULL, calling into engine");
|
|
edict_t* pent = (*g_engfuncs.pfnFindEntityByVars)((entvars_t*)pev);
|
|
if (pent == NULL)
|
|
ALERT(at_console, "DAMN! Even the engine couldn't FindEntityByVars!");
|
|
((entvars_t *)pev)->pContainingEntity = pent;
|
|
return pent;
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
// return team number 0 through 3 based what MOD uses for team numbers
|
|
int UTIL_GetTeam(edict_t *pEntity)
|
|
{
|
|
if (mod_id == TFC_DLL)
|
|
{
|
|
return pEntity->v.team - 1; // TFC teams are 1-4 based
|
|
}
|
|
else if (mod_id == CSTRIKE_DLL)
|
|
{
|
|
char *infobuffer;
|
|
char model_name[32];
|
|
|
|
infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity );
|
|
strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model")));
|
|
|
|
if ((strcmp(model_name, "terror") == 0) || // Phoenix Connektion
|
|
(strcmp(model_name, "arab") == 0) || // old L337 Krew
|
|
(strcmp(model_name, "leet") == 0) || // L337 Krew
|
|
(strcmp(model_name, "artic") == 0) || // Artic Avenger
|
|
(strcmp(model_name, "guerilla") == 0)) // Gorilla Warfare
|
|
{
|
|
return 0;
|
|
}
|
|
else if ((strcmp(model_name, "urban") == 0) || // Seal Team 6
|
|
(strcmp(model_name, "gsg9") == 0) || // German GSG-9
|
|
(strcmp(model_name, "sas") == 0) || // UK SAS
|
|
(strcmp(model_name, "gign") == 0) || // French GIGN
|
|
(strcmp(model_name, "vip") == 0)) // VIP
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0; // return zero if team is unknown
|
|
}
|
|
else if ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL))
|
|
{
|
|
// OpFor CTF map...
|
|
|
|
char *infobuffer;
|
|
char model_name[32];
|
|
|
|
infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity );
|
|
strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model")));
|
|
|
|
if ((strcmp(model_name, "ctf_barney") == 0) ||
|
|
(strcmp(model_name, "cl_suit") == 0) ||
|
|
(strcmp(model_name, "ctf_gina") == 0) ||
|
|
(strcmp(model_name, "ctf_gordon") == 0) ||
|
|
(strcmp(model_name, "otis") == 0) ||
|
|
(strcmp(model_name, "ctf_scientist") == 0))
|
|
{
|
|
return 0;
|
|
}
|
|
else if ((strcmp(model_name, "beret") == 0) ||
|
|
(strcmp(model_name, "drill") == 0) ||
|
|
(strcmp(model_name, "grunt") == 0) ||
|
|
(strcmp(model_name, "recruit") == 0) ||
|
|
(strcmp(model_name, "shephard") == 0) ||
|
|
(strcmp(model_name, "tower") == 0))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0; // return zero if team is unknown
|
|
}
|
|
else if (mod_id == FRONTLINE_DLL)
|
|
{
|
|
return pEntity->v.team - 1; // Front Line Force teams are 1-4 based
|
|
}
|
|
else if(mod_id == AVH_DLL)
|
|
{
|
|
return pEntity->v.team;
|
|
}
|
|
else // must be HL or OpFor deathmatch...
|
|
{
|
|
char *infobuffer;
|
|
char model_name[32];
|
|
|
|
if (team_names[0][0] == 0)
|
|
{
|
|
char *pName;
|
|
char teamlist[MAX_TEAMS*MAX_TEAMNAME_LENGTH];
|
|
int i;
|
|
|
|
num_teams = 0;
|
|
strcpy(teamlist, CVAR_GET_STRING("mp_teamlist"));
|
|
pName = teamlist;
|
|
pName = strtok(pName, ";");
|
|
|
|
while (pName != NULL && *pName)
|
|
{
|
|
// check that team isn't defined twice
|
|
for (i=0; i < num_teams; i++)
|
|
if (strcmp(pName, team_names[i]) == 0)
|
|
break;
|
|
if (i == num_teams)
|
|
{
|
|
strcpy(team_names[num_teams], pName);
|
|
num_teams++;
|
|
}
|
|
pName = strtok(NULL, ";");
|
|
}
|
|
}
|
|
|
|
infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity );
|
|
strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model")));
|
|
|
|
for (int index=0; index < num_teams; index++)
|
|
{
|
|
if (strcmp(model_name, team_names[index]) == 0)
|
|
return index;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// return class number 0 through N
|
|
int UTIL_GetClass(edict_t *pEntity)
|
|
{
|
|
char *infobuffer;
|
|
char model_name[32];
|
|
|
|
infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity );
|
|
strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model")));
|
|
|
|
if (mod_id == FRONTLINE_DLL)
|
|
{
|
|
if ((strcmp(model_name, "natorecon") == 0) ||
|
|
(strcmp(model_name, "axisrecon") == 0))
|
|
{
|
|
return 0; // recon
|
|
}
|
|
else if ((strcmp(model_name, "natoassault") == 0) ||
|
|
(strcmp(model_name, "axisassault") == 0))
|
|
{
|
|
return 1; // assault
|
|
}
|
|
else if ((strcmp(model_name, "natosupport") == 0) ||
|
|
(strcmp(model_name, "axissupport") == 0))
|
|
{
|
|
return 2; // support
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int UTIL_GetBotIndex(edict_t *pEdict)
|
|
{
|
|
int index;
|
|
|
|
for (index=0; index < 32; index++)
|
|
{
|
|
if (bots[index].pEdict == pEdict)
|
|
{
|
|
return index;
|
|
}
|
|
}
|
|
|
|
return -1; // return -1 if edict is not a bot
|
|
}
|
|
|
|
|
|
bot_t *UTIL_GetBotPointer(edict_t *pEdict)
|
|
{
|
|
int index;
|
|
|
|
for (index=0; index < 32; index++)
|
|
{
|
|
if (bots[index].pEdict == pEdict)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index < 32)
|
|
return (&bots[index]);
|
|
|
|
return NULL; // return NULL if edict is not a bot
|
|
}
|
|
|
|
|
|
bool IsAlive(edict_t *pEdict)
|
|
{
|
|
return ((pEdict->v.deadflag == DEAD_NO) &&
|
|
(pEdict->v.health > 0) && !(pEdict->v.flags & FL_NOTARGET));
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
bool FVisible( const Vector &vecOrigin, edict_t *pEdict )
|
|
{
|
|
TraceResult tr;
|
|
Vector vecLookerOrigin;
|
|
|
|
// look through caller's eyes
|
|
vecLookerOrigin = pEdict->v.origin + pEdict->v.view_ofs;
|
|
|
|
int bInWater = (UTIL_PointContents (vecOrigin) == CONTENTS_WATER);
|
|
int bLookerInWater = (UTIL_PointContents (vecLookerOrigin) == CONTENTS_WATER);
|
|
|
|
// don't look through water
|
|
if (bInWater != bLookerInWater)
|
|
return FALSE;
|
|
|
|
UTIL_TraceLine(vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, pEdict, &tr);
|
|
|
|
if (tr.flFraction != 1.0)
|
|
{
|
|
return FALSE; // Line of sight is not established
|
|
}
|
|
else
|
|
{
|
|
return TRUE; // line of sight is valid.
|
|
}
|
|
}
|
|
|
|
|
|
Vector GetGunPosition(edict_t *pEdict)
|
|
{
|
|
return (pEdict->v.origin + pEdict->v.view_ofs);
|
|
}
|
|
|
|
|
|
void UTIL_SelectItem(edict_t *pEdict, char *item_name)
|
|
{
|
|
FakeClientCommand(pEdict, item_name, NULL, NULL);
|
|
}
|
|
|
|
|
|
Vector VecBModelOrigin(edict_t *pEdict)
|
|
{
|
|
return pEdict->v.absmin + (pEdict->v.size * 0.5);
|
|
}
|
|
|
|
|
|
bool UpdateSounds(edict_t *pEdict, edict_t *pPlayer)
|
|
{
|
|
float distance;
|
|
static bool check_footstep_sounds = TRUE;
|
|
static float footstep_sounds_on;
|
|
float sensitivity = 1.0;
|
|
float volume;
|
|
|
|
// update sounds made by this player, alert bots if they are nearby...
|
|
|
|
if (check_footstep_sounds)
|
|
{
|
|
check_footstep_sounds = FALSE;
|
|
footstep_sounds_on = CVAR_GET_FLOAT("mp_footsteps");
|
|
}
|
|
|
|
if (footstep_sounds_on > 0.0)
|
|
{
|
|
CBasePlayer* thePlayer = (CBasePlayer*)CBaseEntity::Instance(pPlayer);
|
|
|
|
// check if this player is moving fast enough to make sounds...
|
|
if (pPlayer->v.velocity.Length2D() > thePlayer->GetMaxWalkSpeed())
|
|
{
|
|
volume = 500.0; // volume of sound being made (just pick something)
|
|
|
|
Vector v_sound = pPlayer->v.origin - pEdict->v.origin;
|
|
|
|
distance = v_sound.Length();
|
|
|
|
// is the bot close enough to hear this sound?
|
|
if (distance < (volume * sensitivity))
|
|
{
|
|
Vector bot_angles = UTIL_VecToAngles( v_sound );
|
|
|
|
pEdict->v.ideal_yaw = bot_angles.y;
|
|
|
|
BotFixIdealYaw(pEdict);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void UTIL_ShowMenu( edict_t *pEdict, int slots, int displaytime, bool needmore, char *pText )
|
|
{
|
|
// if (gmsgShowMenu == 0)
|
|
// gmsgShowMenu = REG_USER_MSG( "ShowMenu", -1 );
|
|
//
|
|
// pfnMessageBegin( MSG_ONE, gmsgShowMenu, NULL, pEdict );
|
|
//
|
|
// pfnWriteShort( slots );
|
|
// pfnWriteChar( displaytime );
|
|
// pfnWriteByte( needmore );
|
|
// pfnWriteString( pText );
|
|
//
|
|
// pfnMessageEnd();
|
|
}
|
|
|
|
void UTIL_BuildFileName(char *filename, char *arg1, char *arg2)
|
|
{
|
|
|
|
if (mod_id == VALVE_DLL)
|
|
#ifndef __linux__
|
|
strcpy(filename, "valve\\");
|
|
#else
|
|
strcpy(filename, "valve/");
|
|
#endif
|
|
|
|
else if (mod_id == TFC_DLL)
|
|
#ifndef __linux__
|
|
strcpy(filename, "tfc\\");
|
|
#else
|
|
strcpy(filename, "tfc/");
|
|
#endif
|
|
|
|
else if (mod_id == CSTRIKE_DLL)
|
|
#ifndef __linux__
|
|
strcpy(filename, "cstrike\\");
|
|
#else
|
|
strcpy(filename, "cstrike/");
|
|
#endif
|
|
|
|
else if (mod_id == GEARBOX_DLL)
|
|
#ifndef __linux__
|
|
strcpy(filename, "gearbox\\");
|
|
#else
|
|
strcpy(filename, "gearbox/");
|
|
#endif
|
|
|
|
else if (mod_id == FRONTLINE_DLL)
|
|
#ifndef __linux__
|
|
strcpy(filename, "frontline\\");
|
|
#else
|
|
strcpy(filename, "frontline/");
|
|
#endif
|
|
|
|
else if (mod_id == AVH_DLL)
|
|
{
|
|
string filenameString = string(getModDirectory());
|
|
#ifndef __linux__
|
|
filenameString += "\\";
|
|
#else
|
|
filenameString += '/';
|
|
#endif
|
|
strcpy(filename,filenameString.c_str());
|
|
}
|
|
else
|
|
{
|
|
filename[0] = 0;
|
|
return;
|
|
}
|
|
|
|
if ((arg1) && (*arg1) && (arg2) && (*arg2))
|
|
{
|
|
strcat(filename, arg1);
|
|
|
|
#ifndef __linux__
|
|
strcat(filename, "\\");
|
|
#else
|
|
strcat(filename, "/");
|
|
#endif
|
|
|
|
strcat(filename, arg2);
|
|
}
|
|
else if ((arg1) && (*arg1))
|
|
{
|
|
strcat(filename, arg1);
|
|
}
|
|
|
|
printf("UTIL_BuildFileName:");
|
|
printf(filename);
|
|
printf("\n");
|
|
}
|
|
|
|
//=========================================================
|
|
// UTIL_LogPrintf - Prints a logged message to console.
|
|
// Preceded by LOG: ( timestamp ) < message >
|
|
//=========================================================
|
|
void UTIL_LogPrintf( char *fmt, ... )
|
|
{
|
|
va_list argptr;
|
|
static char string[1024];
|
|
|
|
va_start ( argptr, fmt );
|
|
vsprintf ( string, fmt, argptr );
|
|
va_end ( argptr );
|
|
|
|
// Print to server console
|
|
printf("UTIL_LogPrintf:");
|
|
printf(string);
|
|
printf("\n");
|
|
ALERT( at_logged, "%s", string );
|
|
}
|
|
|