2015-06-04 11:52:48 +03:00
//
2014-09-09 18:29:42 +04:00
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) YaPB Development Team.
2014-07-30 14:17:46 +04:00
//
2014-09-09 18:29:42 +04:00
// This software is licensed under the BSD-style license.
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
// http://yapb.jeefo.net/license
2014-07-30 14:17:46 +04:00
//
# include <core.h>
2014-09-09 18:29:42 +04:00
2015-06-04 11:52:48 +03:00
ConVar yb_listenserver_welcome ( " yb_listenserver_welcome " , " 1 " , VT_NOSERVER ) ;
2014-07-30 14:17:46 +04:00
ConVar mp_roundtime ( " mp_roundtime " , NULL , VT_NOREGISTER ) ;
ConVar mp_freezetime ( " mp_freezetime " , NULL , VT_NOREGISTER ) ;
void TraceLine ( const Vector & start , const Vector & end , bool ignoreMonsters , bool ignoreGlass , edict_t * ignoreEntity , TraceResult * ptr )
{
// this function traces a line dot by dot, starting from vecStart in the direction of vecEnd,
// ignoring or not monsters (depending on the value of IGNORE_MONSTERS, true or false), and stops
// at the first obstacle encountered, returning the results of the trace in the TraceResult structure
// ptr. Such results are (amongst others) the distance traced, the hit surface, the hit plane
// vector normal, etc. See the TraceResult structure for details. This function allows to specify
// whether the trace starts "inside" an entity's polygonal model, and if so, to specify that entity
// in ignoreEntity in order to ignore it as a possible obstacle.
// this is an overloaded prototype to add IGNORE_GLASS in the same way as IGNORE_MONSTERS work.
( * g_engfuncs . pfnTraceLine ) ( start , end , ( ignoreMonsters ? TRUE : FALSE ) | ( ignoreGlass ? 0x100 : 0 ) , ignoreEntity , ptr ) ;
}
void TraceLine ( const Vector & start , const Vector & end , bool ignoreMonsters , edict_t * ignoreEntity , TraceResult * ptr )
{
// this function traces a line dot by dot, starting from vecStart in the direction of vecEnd,
// ignoring or not monsters (depending on the value of IGNORE_MONSTERS, true or false), and stops
// at the first obstacle encountered, returning the results of the trace in the TraceResult structure
// ptr. Such results are (amongst others) the distance traced, the hit surface, the hit plane
// vector normal, etc. See the TraceResult structure for details. This function allows to specify
// whether the trace starts "inside" an entity's polygonal model, and if so, to specify that entity
// in ignoreEntity in order to ignore it as a possible obstacle.
( * g_engfuncs . pfnTraceLine ) ( start , end , ignoreMonsters ? TRUE : FALSE , ignoreEntity , ptr ) ;
}
void TraceHull ( const Vector & start , const Vector & end , bool ignoreMonsters , int hullNumber , edict_t * ignoreEntity , TraceResult * ptr )
{
// this function traces a hull dot by dot, starting from vecStart in the direction of vecEnd,
// ignoring or not monsters (depending on the value of IGNORE_MONSTERS, true or
// false), and stops at the first obstacle encountered, returning the results
// of the trace in the TraceResult structure ptr, just like TraceLine. Hulls that can be traced
// (by parameter hull_type) are point_hull (a line), head_hull (size of a crouching player),
// human_hull (a normal body size) and large_hull (for monsters?). Not all the hulls in the
// game can be traced here, this function is just useful to give a relative idea of spatial
// reachability (i.e. can a hostage pass through that tiny hole ?) Also like TraceLine, this
// function allows to specify whether the trace starts "inside" an entity's polygonal model,
// and if so, to specify that entity in ignoreEntity in order to ignore it as an obstacle.
( * g_engfuncs . pfnTraceHull ) ( start , end , ignoreMonsters ? TRUE : FALSE , hullNumber , ignoreEntity , ptr ) ;
}
uint16 FixedUnsigned16 ( float value , float scale )
{
int output = ( static_cast < int > ( value * scale ) ) ;
if ( output < 0 )
output = 0 ;
if ( output > 0xffff )
output = 0xffff ;
return static_cast < uint16 > ( output ) ;
}
short FixedSigned16 ( float value , float scale )
{
int output = ( static_cast < int > ( value * scale ) ) ;
if ( output > 32767 )
output = 32767 ;
if ( output < - 32768 )
output = - 32768 ;
return static_cast < short > ( output ) ;
}
2015-06-06 16:19:20 +03:00
const char * FormatBuffer ( const char * format , . . . )
2014-07-30 14:17:46 +04:00
{
va_list ap ;
static char staticBuffer [ 3072 ] ;
va_start ( ap , format ) ;
vsprintf ( staticBuffer , format , ap ) ;
va_end ( ap ) ;
return & staticBuffer [ 0 ] ;
}
bool IsAlive ( edict_t * ent )
{
2015-06-04 11:52:48 +03:00
if ( IsEntityNull ( ent ) )
return false ;
2014-07-30 14:17:46 +04:00
2015-06-04 11:52:48 +03:00
return ent - > v . deadflag = = DEAD_NO & & ent - > v . health > 0 & & ent - > v . movetype ! = MOVETYPE_NOCLIP ;
2014-07-30 14:17:46 +04:00
}
float GetShootingConeDeviation ( edict_t * ent , Vector * position )
{
const Vector & dir = ( * position - ( ent - > v . origin + ent - > v . view_ofs ) ) . Normalize ( ) ;
MakeVectors ( ent - > v . v_angle ) ;
// he's facing it, he meant it
return g_pGlobals - > v_forward | dir ;
}
2015-06-24 15:38:48 +03:00
bool IsInViewCone ( const Vector & origin , edict_t * ent )
2014-07-30 14:17:46 +04:00
{
MakeVectors ( ent - > v . v_angle ) ;
2015-06-24 15:38:48 +03:00
if ( ( ( origin - ( ent - > v . origin + ent - > v . view_ofs ) ) . Normalize ( ) | g_pGlobals - > v_forward ) > = cosf ( ( ( ent - > v . fov > 0 ? ent - > v . fov : 90.0f ) * 0.5f ) * MATH_D2R ) )
2014-07-30 14:17:46 +04:00
return true ;
return false ;
}
bool IsVisible ( const Vector & origin , edict_t * ent )
{
2015-06-04 11:52:48 +03:00
if ( IsEntityNull ( ent ) )
2014-07-30 14:17:46 +04:00
return false ;
TraceResult tr ;
TraceLine ( ent - > v . origin + ent - > v . view_ofs , origin , true , true , ent , & tr ) ;
if ( tr . flFraction ! = 1.0 )
return false ; // line of sight is not established
return true ; // line of sight is valid.
}
2015-06-11 14:31:02 +03:00
Vector GetEntityOrigin ( edict_t * ent )
2014-07-30 14:17:46 +04:00
{
// this expanded function returns the vector origin of a bounded entity, assuming that any
// entity that has a bounding box has its center at the center of the bounding box itself.
2015-06-04 11:52:48 +03:00
if ( IsEntityNull ( ent ) )
2014-07-30 14:17:46 +04:00
return nullvec ;
if ( ent - > v . origin = = nullvec )
2015-06-11 14:31:02 +03:00
return ent - > v . absmin + ent - > v . size * 0.5 ;
2014-07-30 14:17:46 +04:00
return ent - > v . origin ;
}
void DisplayMenuToClient ( edict_t * ent , MenuText * menu )
{
if ( ! IsValidPlayer ( ent ) )
return ;
2014-09-17 20:36:42 +04:00
int clientIndex = IndexOfEntity ( ent ) - 1 ;
2014-07-30 14:17:46 +04:00
if ( menu ! = NULL )
{
String tempText = String ( menu - > menuText ) ;
tempText . Replace ( " \v " , " \n " ) ;
2015-06-04 11:52:48 +03:00
char * text = g_localizer - > TranslateInput ( tempText . GetBuffer ( ) ) ;
2014-07-30 14:17:46 +04:00
tempText = String ( text ) ;
// make menu looks best
for ( int i = 0 ; i < = 9 ; i + + )
tempText . Replace ( FormatBuffer ( " %d. " , i ) , FormatBuffer ( " \\ r%d. \\ w " , i ) ) ;
2015-06-04 11:52:48 +03:00
text = ( char * ) tempText . GetBuffer ( ) ;
2014-07-30 14:17:46 +04:00
while ( strlen ( text ) > = 64 )
{
MESSAGE_BEGIN ( MSG_ONE_UNRELIABLE , g_netMsg - > GetId ( NETMSG_SHOWMENU ) , NULL , ent ) ;
WRITE_SHORT ( menu - > validSlots ) ;
WRITE_CHAR ( - 1 ) ;
WRITE_BYTE ( 1 ) ;
for ( int i = 0 ; i < = 63 ; i + + )
WRITE_CHAR ( text [ i ] ) ;
MESSAGE_END ( ) ;
text + = 64 ;
}
MESSAGE_BEGIN ( MSG_ONE_UNRELIABLE , g_netMsg - > GetId ( NETMSG_SHOWMENU ) , NULL , ent ) ;
WRITE_SHORT ( menu - > validSlots ) ;
WRITE_CHAR ( - 1 ) ;
WRITE_BYTE ( 0 ) ;
WRITE_STRING ( text ) ;
MESSAGE_END ( ) ;
g_clients [ clientIndex ] . menu = menu ;
}
else
{
MESSAGE_BEGIN ( MSG_ONE_UNRELIABLE , g_netMsg - > GetId ( NETMSG_SHOWMENU ) , NULL , ent ) ;
WRITE_SHORT ( 0 ) ;
WRITE_CHAR ( 0 ) ;
WRITE_BYTE ( 0 ) ;
WRITE_STRING ( " " ) ;
MESSAGE_END ( ) ;
g_clients [ clientIndex ] . menu = NULL ;
}
CLIENT_COMMAND ( ent , " speak \" player/geiger1 \" \n " ) ; // Stops others from hearing menu sounds..
}
void DecalTrace ( entvars_t * pev , TraceResult * trace , int logotypeIndex )
{
// this function draw spraypaint depending on the tracing results.
static Array < String > logotypes ;
if ( logotypes . IsEmpty ( ) )
2015-06-14 23:13:09 +03:00
logotypes = String ( " {biohaz;{graf003;{graf004;{graf005;{lambda06;{target;{hand1;{spit2;{bloodhand6;{foot_l;{foot_r " ) . Split ( " ; " ) ;
2014-07-30 14:17:46 +04:00
int entityIndex = - 1 , message = TE_DECAL ;
2015-06-04 11:52:48 +03:00
int decalIndex = ( * g_engfuncs . pfnDecalIndex ) ( logotypes [ logotypeIndex ] . GetBuffer ( ) ) ;
2014-07-30 14:17:46 +04:00
if ( decalIndex < 0 )
decalIndex = ( * g_engfuncs . pfnDecalIndex ) ( " {lambda06 " ) ;
if ( trace - > flFraction = = 1.0 )
return ;
2015-06-04 11:52:48 +03:00
if ( ! IsEntityNull ( trace - > pHit ) )
2014-07-30 14:17:46 +04:00
{
if ( trace - > pHit - > v . solid = = SOLID_BSP | | trace - > pHit - > v . movetype = = MOVETYPE_PUSHSTEP )
2014-09-17 20:36:42 +04:00
entityIndex = IndexOfEntity ( trace - > pHit ) ;
2014-07-30 14:17:46 +04:00
else
return ;
}
else
entityIndex = 0 ;
if ( entityIndex ! = 0 )
{
if ( decalIndex > 255 )
{
message = TE_DECALHIGH ;
decalIndex - = 256 ;
}
}
else
{
message = TE_WORLDDECAL ;
if ( decalIndex > 255 )
{
message = TE_WORLDDECALHIGH ;
decalIndex - = 256 ;
}
}
if ( logotypes [ logotypeIndex ] . Contains ( " { " ) )
{
MESSAGE_BEGIN ( MSG_BROADCAST , SVC_TEMPENTITY ) ;
WRITE_BYTE ( TE_PLAYERDECAL ) ;
2014-09-17 20:36:42 +04:00
WRITE_BYTE ( IndexOfEntity ( ENT ( pev ) ) ) ;
2014-07-30 14:17:46 +04:00
WRITE_COORD ( trace - > vecEndPos . x ) ;
WRITE_COORD ( trace - > vecEndPos . y ) ;
WRITE_COORD ( trace - > vecEndPos . z ) ;
2014-09-17 20:36:42 +04:00
WRITE_SHORT ( static_cast < short > ( IndexOfEntity ( trace - > pHit ) ) ) ;
2014-07-30 14:17:46 +04:00
WRITE_BYTE ( decalIndex ) ;
MESSAGE_END ( ) ;
}
else
{
MESSAGE_BEGIN ( MSG_BROADCAST , SVC_TEMPENTITY ) ;
WRITE_BYTE ( message ) ;
WRITE_COORD ( trace - > vecEndPos . x ) ;
WRITE_COORD ( trace - > vecEndPos . y ) ;
WRITE_COORD ( trace - > vecEndPos . z ) ;
WRITE_BYTE ( decalIndex ) ;
if ( entityIndex )
WRITE_SHORT ( entityIndex ) ;
MESSAGE_END ( ) ;
}
}
void FreeLibraryMemory ( void )
{
// this function free's all allocated memory
g_waypoint - > Init ( ) ; // frees waypoint data
2015-06-28 19:43:31 +03:00
FOR_EACH_AE ( g_localizer - > m_langTab , it )
2015-06-18 19:29:40 +03:00
{
delete [ ] g_localizer - > m_langTab [ it ] . original ;
delete [ ] g_localizer - > m_langTab [ it ] . translated ;
}
g_localizer - > m_langTab . RemoveAll ( ) ;
2015-06-04 11:52:48 +03:00
delete [ ] g_experienceData ;
2014-07-30 14:17:46 +04:00
g_experienceData = NULL ;
}
void FakeClientCommand ( edict_t * fakeClient , const char * format , . . . )
{
// the purpose of this function is to provide fakeclients (bots) with the same client
// command-scripting advantages (putting multiple commands in one line between semicolons)
// as real players. It is an improved version of botman's FakeClientCommand, in which you
// supply directly the whole string as if you were typing it in the bot's "console". It
// is supposed to work exactly like the pfnClientCommand (server-sided client command).
va_list ap ;
static char command [ 256 ] ;
2015-06-04 11:52:48 +03:00
int stop , i , stringIndex = 0 ;
2014-07-30 14:17:46 +04:00
2015-06-04 11:52:48 +03:00
if ( IsEntityNull ( fakeClient ) )
2014-07-30 14:17:46 +04:00
return ; // reliability check
// concatenate all the arguments in one string
va_start ( ap , format ) ;
_vsnprintf ( command , sizeof ( command ) , format , ap ) ;
va_end ( ap ) ;
if ( IsNullString ( command ) )
return ; // if nothing in the command buffer, return
g_isFakeCommand = true ; // set the "fakeclient command" flag
int length = strlen ( command ) ; // get the total length of the command string
// process all individual commands (separated by a semicolon) one each a time
while ( stringIndex < length )
{
2015-06-04 11:52:48 +03:00
int start = stringIndex ; // save field start position (first character)
2014-07-30 14:17:46 +04:00
while ( stringIndex < length & & command [ stringIndex ] ! = ' ; ' )
stringIndex + + ; // reach end of field
if ( command [ stringIndex - 1 ] = = ' \n ' )
stop = stringIndex - 2 ; // discard any trailing '\n' if needed
else
stop = stringIndex - 1 ; // save field stop position (last character before semicolon or end)
for ( i = start ; i < = stop ; i + + )
g_fakeArgv [ i - start ] = command [ i ] ; // store the field value in the g_fakeArgv global string
g_fakeArgv [ i - start ] = 0 ; // terminate the string
stringIndex + + ; // move the overall string index one step further to bypass the semicolon
2015-06-04 11:52:48 +03:00
int index = 0 ;
2014-07-30 14:17:46 +04:00
g_fakeArgc = 0 ; // let's now parse that command and count the different arguments
// count the number of arguments
while ( index < i - start )
{
while ( index < i - start & & g_fakeArgv [ index ] = = ' ' )
index + + ; // ignore spaces
// is this field a group of words between quotes or a single word ?
if ( g_fakeArgv [ index ] = = ' " ' )
{
index + + ; // move one step further to bypass the quote
while ( index < i - start & & g_fakeArgv [ index ] ! = ' " ' )
index + + ; // reach end of field
index + + ; // move one step further to bypass the quote
}
else
while ( index < i - start & & g_fakeArgv [ index ] ! = ' ' )
index + + ; // this is a single word, so reach the end of field
g_fakeArgc + + ; // we have processed one argument more
}
// tell now the MOD DLL to execute this ClientCommand...
MDLL_ClientCommand ( fakeClient ) ;
}
g_fakeArgv [ 0 ] = 0 ; // when it's done, reset the g_fakeArgv field
g_isFakeCommand = false ; // reset the "fakeclient command" flag
g_fakeArgc = 0 ; // and the argument count
}
const char * GetField ( const char * string , int fieldId , bool endLine )
{
// This function gets and returns a particuliar field in a string where several szFields are
// concatenated. Fields can be words, or groups of words between quotes ; separators may be
// white space or tabs. A purpose of this function is to provide bots with the same Cmd_Argv
// convenience the engine provides to real clients. This way the handling of real client
// commands and bot client commands is exactly the same, just have a look in engine.cpp
// for the hooking of pfnCmd_Argc, pfnCmd_Args and pfnCmd_Argv, which redirects the call
// either to the actual engine functions (when the caller is a real client), either on
// our function here, which does the same thing, when the caller is a bot.
static char field [ 256 ] ;
// reset the string
memset ( field , 0 , sizeof ( field ) ) ;
int length , i , index = 0 , fieldCount = 0 , start , stop ;
field [ 0 ] = 0 ; // reset field
length = strlen ( string ) ; // get length of string
// while we have not reached end of line
while ( index < length & & fieldCount < = fieldId )
{
while ( index < length & & ( string [ index ] = = ' ' | | string [ index ] = = ' \t ' ) )
index + + ; // ignore spaces or tabs
// is this field multi-word between quotes or single word ?
if ( string [ index ] = = ' " ' )
{
index + + ; // move one step further to bypass the quote
start = index ; // save field start position
while ( ( index < length ) & & ( string [ index ] ! = ' " ' ) )
index + + ; // reach end of field
stop = index - 1 ; // save field stop position
index + + ; // move one step further to bypass the quote
}
else
{
start = index ; // save field start position
while ( index < length & & ( string [ index ] ! = ' ' & & string [ index ] ! = ' \t ' ) )
index + + ; // reach end of field
stop = index - 1 ; // save field stop position
}
// is this field we just processed the wanted one ?
if ( fieldCount = = fieldId )
{
for ( i = start ; i < = stop ; i + + )
field [ i - start ] = string [ i ] ; // store the field value in a string
field [ i - start ] = 0 ; // terminate the string
break ; // and stop parsing
}
fieldCount + + ; // we have parsed one field more
}
if ( endLine )
field [ strlen ( field ) - 1 ] = 0 ;
strtrim ( field ) ;
return ( & field [ 0 ] ) ; // returns the wanted field
}
void strtrim ( char * string )
{
char * ptr = string ;
int length = 0 , toggleFlag = 0 , increment = 0 ;
int i = 0 ;
while ( * ptr + + )
length + + ;
for ( i = length - 1 ; i > = 0 ; i - - )
{
if ( ! isspace ( string [ i ] ) )
break ;
else
{
string [ i ] = 0 ;
length - - ;
}
}
for ( i = 0 ; i < length ; i + + )
{
if ( isspace ( string [ i ] ) & & ! toggleFlag )
{
increment + + ;
if ( increment + i < length )
string [ i ] = string [ increment + i ] ;
}
else
{
if ( ! toggleFlag )
toggleFlag = 1 ;
if ( increment )
string [ i ] = string [ increment + i ] ;
}
}
string [ length ] = 0 ;
}
const char * GetModName ( void )
{
static char modName [ 256 ] ;
GET_GAME_DIR ( modName ) ; // ask the engine for the MOD directory path
int length = strlen ( modName ) ; // get the length of the returned string
// format the returned string to get the last directory name
int stop = length - 1 ;
while ( ( modName [ stop ] = = ' \\ ' | | modName [ stop ] = = ' / ' ) & & stop > 0 )
stop - - ; // shift back any trailing separator
int start = stop ;
while ( modName [ start ] ! = ' \\ ' & & modName [ start ] ! = ' / ' & & start > 0 )
start - - ; // shift back to the start of the last subdirectory name
if ( modName [ start ] = = ' \\ ' | | modName [ start ] = = ' / ' )
start + + ; // if we reached a separator, step over it
// now copy the formatted string back onto itself character per character
for ( length = start ; length < = stop ; length + + )
modName [ length - start ] = modName [ length ] ;
modName [ length - start ] = 0 ; // terminate the string
return & modName [ 0 ] ;
}
// Create a directory tree
void CreatePath ( char * path )
{
for ( char * ofs = path + 1 ; * ofs ; ofs + + )
{
if ( * ofs = = ' / ' )
{
// create the directory
* ofs = 0 ;
# ifdef PLATFORM_WIN32
mkdir ( path ) ;
# else
mkdir ( path , 0777 ) ;
# endif
* ofs = ' / ' ;
}
}
# ifdef PLATFORM_WIN32
mkdir ( path ) ;
# else
mkdir ( path , 0777 ) ;
# endif
}
void DrawLine ( edict_t * ent , const Vector & start , const Vector & end , int width , int noise , int red , int green , int blue , int brightness , int speed , int life )
{
// this function draws a line visible from the client side of the player whose player entity
// is pointed to by ent, from the vector location start to the vector location end,
// which is supposed to last life tenths seconds, and having the color defined by RGB.
if ( ! IsValidPlayer ( ent ) )
return ; // reliability check
MESSAGE_BEGIN ( MSG_ONE_UNRELIABLE , SVC_TEMPENTITY , NULL , ent ) ;
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 ( g_modelIndexLaser ) ;
WRITE_BYTE ( 0 ) ; // 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 DrawArrow ( edict_t * ent , const Vector & start , const Vector & end , int width , int noise , int red , int green , int blue , int brightness , int speed , int life )
{
// this function draws a arrow visible from the client side of the player whose player entity
// is pointed to by ent, from the vector location start to the vector location end,
// which is supposed to last life tenths seconds, and having the color defined by RGB.
if ( ! IsValidPlayer ( ent ) )
return ; // reliability check
MESSAGE_BEGIN ( MSG_ONE_UNRELIABLE , SVC_TEMPENTITY , NULL , ent ) ;
WRITE_BYTE ( TE_BEAMPOINTS ) ;
WRITE_COORD ( end . x ) ;
WRITE_COORD ( end . y ) ;
WRITE_COORD ( end . z ) ;
WRITE_COORD ( start . x ) ;
WRITE_COORD ( start . y ) ;
WRITE_COORD ( start . z ) ;
WRITE_SHORT ( g_modelIndexArrow ) ;
WRITE_BYTE ( 0 ) ; // 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 UpdateGlobalExperienceData ( void )
{
// this function called after each end of the round to update knowledge about most dangerous waypoints for each team.
// no waypoints, no experience used or waypoints edited or being edited?
2014-08-05 21:04:43 +04:00
if ( g_numWaypoints < 1 | | g_waypointsChanged )
2014-07-30 14:17:46 +04:00
return ; // no action
unsigned short maxDamage ; // maximum damage
unsigned short actDamage ; // actual damage
int bestIndex ; // best index to store
bool recalcKills = false ;
// get the most dangerous waypoint for this position for terrorist team
for ( int i = 0 ; i < g_numWaypoints ; i + + )
{
maxDamage = 0 ;
bestIndex = - 1 ;
for ( int j = 0 ; j < g_numWaypoints ; j + + )
{
if ( i = = j )
continue ;
actDamage = ( g_experienceData + ( i * g_numWaypoints ) + j ) - > team0Damage ;
if ( actDamage > maxDamage )
{
maxDamage = actDamage ;
bestIndex = j ;
}
}
if ( maxDamage > MAX_DAMAGE_VALUE )
recalcKills = true ;
( g_experienceData + ( i * g_numWaypoints ) + i ) - > team0DangerIndex = static_cast < short > ( bestIndex ) ;
}
// get the most dangerous waypoint for this position for counter-terrorist team
for ( int i = 0 ; i < g_numWaypoints ; i + + )
{
maxDamage = 0 ;
bestIndex = - 1 ;
for ( int j = 0 ; j < g_numWaypoints ; j + + )
{
if ( i = = j )
continue ;
actDamage = ( g_experienceData + ( i * g_numWaypoints ) + j ) - > team1Damage ;
if ( actDamage > maxDamage )
{
maxDamage = actDamage ;
bestIndex = j ;
}
}
if ( maxDamage > MAX_DAMAGE_VALUE )
recalcKills = true ;
( g_experienceData + ( i * g_numWaypoints ) + i ) - > team1DangerIndex = static_cast < short > ( bestIndex ) ;
}
// adjust values if overflow is about to happen
if ( recalcKills )
{
for ( int i = 0 ; i < g_numWaypoints ; i + + )
{
for ( int j = 0 ; j < g_numWaypoints ; j + + )
{
if ( i = = j )
continue ;
int clip = ( g_experienceData + ( i * g_numWaypoints ) + j ) - > team0Damage ;
clip - = static_cast < int > ( MAX_DAMAGE_VALUE * 0.5 ) ;
if ( clip < 0 )
clip = 0 ;
( g_experienceData + ( i * g_numWaypoints ) + j ) - > team0Damage = static_cast < unsigned short > ( clip ) ;
clip = ( g_experienceData + ( i * g_numWaypoints ) + j ) - > team1Damage ;
clip - = static_cast < int > ( MAX_DAMAGE_VALUE * 0.5 ) ;
if ( clip < 0 )
clip = 0 ;
( g_experienceData + ( i * g_numWaypoints ) + j ) - > team1Damage = static_cast < unsigned short > ( clip ) ;
}
}
}
2014-08-05 21:04:43 +04:00
g_highestKills + + ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
int clip = g_highestDamageT - static_cast < int > ( MAX_DAMAGE_VALUE * 0.5 ) ;
if ( clip < 1 )
clip = 1 ;
g_highestDamageT = clip ;
clip = ( int ) g_highestDamageCT - static_cast < int > ( MAX_DAMAGE_VALUE * 0.5 ) ;
if ( clip < 1 )
clip = 1 ;
g_highestDamageCT = clip ;
if ( g_highestKills = = MAX_KILL_HISTORY )
2014-07-30 14:17:46 +04:00
{
for ( int i = 0 ; i < g_numWaypoints ; i + + )
{
( g_experienceData + ( i * g_numWaypoints ) + i ) - > team0Damage / = static_cast < unsigned short > ( GetMaxClients ( ) * 0.5 ) ;
( g_experienceData + ( i * g_numWaypoints ) + i ) - > team1Damage / = static_cast < unsigned short > ( GetMaxClients ( ) * 0.5 ) ;
}
2014-08-05 21:04:43 +04:00
g_highestKills = 1 ;
2014-07-30 14:17:46 +04:00
}
}
void RoundInit ( void )
{
// this is called at the start of each round
g_roundEnded = false ;
// check team economics
g_botManager - > CheckTeamEconomics ( TEAM_TF ) ;
g_botManager - > CheckTeamEconomics ( TEAM_CF ) ;
for ( int i = 0 ; i < GetMaxClients ( ) ; i + + )
{
if ( g_botManager - > GetBot ( i ) )
g_botManager - > GetBot ( i ) - > NewRound ( ) ;
g_radioSelect [ i ] = 0 ;
}
g_waypoint - > SetBombPosition ( true ) ;
g_waypoint - > ClearGoalScore ( ) ;
g_bombSayString = false ;
g_timeBombPlanted = 0.0 ;
g_timeNextBombUpdate = 0.0 ;
g_leaderChoosen [ TEAM_CF ] = false ;
g_leaderChoosen [ TEAM_TF ] = false ;
g_lastRadioTime [ 0 ] = 0.0 ;
g_lastRadioTime [ 1 ] = 0.0 ;
g_botsCanPause = false ;
2015-06-04 11:52:48 +03:00
for ( int i = 0 ; i < TASK_MAX ; i + + )
g_taskFilters [ i ] . time = 0.0f ;
2014-07-30 14:17:46 +04:00
UpdateGlobalExperienceData ( ) ; // update experience data on round start
// calculate the round mid/end in world time
g_timeRoundStart = GetWorldTime ( ) + mp_freezetime . GetFloat ( ) ;
2015-06-11 16:53:21 +03:00
g_timeRoundMid = g_timeRoundStart + mp_roundtime . GetFloat ( ) * 60 * 0.5f ;
2014-07-30 14:17:46 +04:00
g_timeRoundEnd = g_timeRoundStart + mp_roundtime . GetFloat ( ) * 60 ;
}
2015-06-04 11:52:48 +03:00
int GetWeaponPenetrationPower ( int id )
2014-07-30 14:17:46 +04:00
{
// returns if weapon can pierce through a wall
int i = 0 ;
while ( g_weaponSelect [ i ] . id )
{
if ( g_weaponSelect [ i ] . id = = id )
2015-06-04 11:52:48 +03:00
return g_weaponSelect [ i ] . penetratePower ;
2014-07-30 14:17:46 +04:00
i + + ;
}
2015-06-04 11:52:48 +03:00
return 0 ;
2014-07-30 14:17:46 +04:00
}
bool IsValidPlayer ( edict_t * ent )
{
2015-06-04 11:52:48 +03:00
if ( IsEntityNull ( ent ) )
2014-07-30 14:17:46 +04:00
return false ;
if ( ent - > v . flags & FL_PROXY )
return false ;
if ( ( ent - > v . flags & ( FL_CLIENT | FL_FAKECLIENT ) ) | | g_botManager - > GetBot ( ent ) ! = NULL )
return ! IsNullString ( STRING ( ent - > v . netname ) ) ;
return false ;
}
2015-06-28 19:43:31 +03:00
bool IsPlayerVIP ( edict_t * ent )
{
if ( ! ( g_mapType & MAP_AS ) )
return false ;
if ( ! IsValidPlayer ( ent ) )
return false ;
return * ( INFOKEY_VALUE ( GET_INFOKEYBUFFER ( ent ) , " model " ) ) = = ' v ' ;
}
2014-07-30 14:17:46 +04:00
bool IsValidBot ( edict_t * ent )
{
2015-06-04 11:52:48 +03:00
if ( g_botManager - > GetBot ( ent ) ! = NULL | | ( ! IsEntityNull ( ent ) & & ( ent - > v . flags & FL_FAKECLIENT ) ) )
2014-07-30 14:17:46 +04:00
return true ;
return false ;
}
bool IsDedicatedServer ( void )
{
// return true if server is dedicated server, false otherwise
return ( IS_DEDICATED_SERVER ( ) > 0 ) ; // ask engine for this
}
2015-06-06 16:19:20 +03:00
bool TryFileOpen ( const char * fileName )
2014-07-30 14:17:46 +04:00
{
// this function tests if a file exists by attempting to open it
File fp ;
// check if got valid handle
if ( fp . Open ( fileName , " rb " ) )
{
fp . Close ( ) ;
return true ;
}
return false ;
}
void ServerPrint ( const char * format , . . . )
{
va_list ap ;
char string [ 3072 ] ;
va_start ( ap , format ) ;
vsprintf ( string , g_localizer - > TranslateInput ( format ) , ap ) ;
va_end ( ap ) ;
2015-06-11 14:19:52 +03:00
SERVER_PRINT ( string ) ;
SERVER_PRINT ( " \n " ) ;
2014-07-30 14:17:46 +04:00
}
void CenterPrint ( const char * format , . . . )
{
va_list ap ;
char string [ 2048 ] ;
va_start ( ap , format ) ;
vsprintf ( string , g_localizer - > TranslateInput ( format ) , ap ) ;
va_end ( ap ) ;
if ( IsDedicatedServer ( ) )
{
ServerPrint ( string ) ;
return ;
}
MESSAGE_BEGIN ( MSG_BROADCAST , g_netMsg - > GetId ( NETMSG_TEXTMSG ) ) ;
WRITE_BYTE ( HUD_PRINTCENTER ) ;
WRITE_STRING ( FormatBuffer ( " %s \n " , string ) ) ;
MESSAGE_END ( ) ;
}
void ChartPrint ( const char * format , . . . )
{
va_list ap ;
char string [ 2048 ] ;
va_start ( ap , format ) ;
vsprintf ( string , g_localizer - > TranslateInput ( format ) , ap ) ;
va_end ( ap ) ;
if ( IsDedicatedServer ( ) )
{
ServerPrint ( string ) ;
return ;
}
strcat ( string , " \n " ) ;
MESSAGE_BEGIN ( MSG_BROADCAST , g_netMsg - > GetId ( NETMSG_TEXTMSG ) ) ;
WRITE_BYTE ( HUD_PRINTTALK ) ;
WRITE_STRING ( string ) ;
MESSAGE_END ( ) ;
}
void ClientPrint ( edict_t * ent , int dest , const char * format , . . . )
{
va_list ap ;
char string [ 2048 ] ;
va_start ( ap , format ) ;
vsprintf ( string , g_localizer - > TranslateInput ( format ) , ap ) ;
va_end ( ap ) ;
2015-06-04 11:52:48 +03:00
if ( IsEntityNull ( ent ) | | ent = = g_hostEntity )
2014-07-30 14:17:46 +04:00
{
2015-06-24 15:38:48 +03:00
ServerPrint ( string ) ;
2014-07-30 14:17:46 +04:00
return ;
}
strcat ( string , " \n " ) ;
2015-06-24 15:38:48 +03:00
( * g_engfuncs . pfnClientPrintf ) ( ent , static_cast < PRINT_TYPE > ( dest ) , string ) ;
2014-07-30 14:17:46 +04:00
}
void ServerCommand ( const char * format , . . . )
{
// this function asks the engine to execute a server command
va_list ap ;
static char string [ 1024 ] ;
// concatenate all the arguments in one string
va_start ( ap , format ) ;
vsprintf ( string , format , ap ) ;
va_end ( ap ) ;
2015-06-06 16:19:20 +03:00
SERVER_COMMAND ( const_cast < char * > ( FormatBuffer ( " %s \n " , string ) ) ) ; // execute command
2014-07-30 14:17:46 +04:00
}
const char * GetMapName ( void )
{
// this function gets the map name and store it in the map_name global string variable.
static char mapName [ 256 ] ;
2015-06-29 21:49:52 +03:00
strncpy ( mapName , const_cast < const char * > ( g_pGlobals - > pStringBase + static_cast < int > ( g_pGlobals - > mapname ) ) , SIZEOF_CHAR ( mapName ) ) ;
2014-07-30 14:17:46 +04:00
return & mapName [ 0 ] ; // and return a pointer to it
}
2015-06-28 19:43:31 +03:00
extern bool OpenConfig ( const char * fileName , const char * errorIfNotExists , File * outFile , bool languageDependant /*= false*/ )
2014-07-30 14:17:46 +04:00
{
if ( outFile - > IsValid ( ) )
outFile - > Close ( ) ;
if ( languageDependant )
{
extern ConVar yb_language ;
if ( strcmp ( fileName , " lang.cfg " ) = = 0 & & strcmp ( yb_language . GetString ( ) , " en " ) = = 0 )
return false ;
2015-06-25 22:56:42 +03:00
const char * languageDependantConfigFile = FormatBuffer ( " %s/addons/yapb/conf/lang/%s_%s " , GetModName ( ) , yb_language . GetString ( ) , fileName ) ;
2014-07-30 14:17:46 +04:00
// check is file is exists for this language
if ( TryFileOpen ( languageDependantConfigFile ) )
outFile - > Open ( languageDependantConfigFile , " rt " ) ;
else
2015-06-25 22:56:42 +03:00
outFile - > Open ( FormatBuffer ( " %s/addons/yapb/conf/lang/en_%s " , GetModName ( ) , fileName ) , " rt " ) ;
2014-07-30 14:17:46 +04:00
}
else
2015-06-25 22:56:42 +03:00
outFile - > Open ( FormatBuffer ( " %s/addons/yapb/conf/%s " , GetModName ( ) , fileName ) , " rt " ) ;
2014-07-30 14:17:46 +04:00
if ( ! outFile - > IsValid ( ) )
{
AddLogEntry ( true , LL_ERROR , errorIfNotExists ) ;
return false ;
}
return true ;
}
const char * GetWaypointDir ( void )
{
2015-06-25 22:56:42 +03:00
return FormatBuffer ( " %s/addons/yapb/data/ " , GetModName ( ) ) ;
2014-07-30 14:17:46 +04:00
}
2015-06-28 19:43:31 +03:00
extern void RegisterCommand ( const char * command , void funcPtr ( void ) )
2014-07-30 14:17:46 +04:00
{
// this function tells the engine that a new server command is being declared, in addition
// to the standard ones, whose name is command_name. The engine is thus supposed to be aware
// that for every "command_name" server command it receives, it should call the function
// pointed to by "function" in order to handle it.
if ( IsNullString ( command ) | | funcPtr = = NULL )
return ; // reliability check
2015-06-28 19:43:31 +03:00
REG_SVR_COMMAND ( const_cast < char * > ( command ) , funcPtr ) ; // ask the engine to register this new command
2014-07-30 14:17:46 +04:00
}
void CheckWelcomeMessage ( void )
{
// the purpose of this function, is to send quick welcome message, to the listenserver entity.
static bool isReceived = false ;
static float receiveTime = 0.0 ;
if ( isReceived | | ! yb_listenserver_welcome . GetBool ( ) )
return ;
Array < String > sentences ;
// add default messages
sentences . Push ( " hello user,communication is acquired " ) ;
sentences . Push ( " your presence is acknowledged " ) ;
sentences . Push ( " high man, your in command now " ) ;
sentences . Push ( " blast your hostile for good " ) ;
sentences . Push ( " high man, kill some idiot here " ) ;
sentences . Push ( " is there a doctor in the area " ) ;
sentences . Push ( " warning, experimental materials detected " ) ;
sentences . Push ( " high amigo, shoot some but " ) ;
sentences . Push ( " attention, hours of work software, detected " ) ;
sentences . Push ( " time for some bad ass explosion " ) ;
sentences . Push ( " bad ass son of a breach device activated " ) ;
sentences . Push ( " high, do not question this great service " ) ;
sentences . Push ( " engine is operative, hello and goodbye " ) ;
sentences . Push ( " high amigo, your administration has been great last day " ) ;
sentences . Push ( " attention, expect experimental armed hostile presence " ) ;
sentences . Push ( " warning, medical attention required " ) ;
if ( IsAlive ( g_hostEntity ) & & ! isReceived & & receiveTime < 1.0 & & ( g_numWaypoints > 0 ? g_isCommencing : true ) )
receiveTime = GetWorldTime ( ) + 4.0 ; // receive welcome message in four seconds after game has commencing
if ( receiveTime > 0.0 & & receiveTime < GetWorldTime ( ) & & ! isReceived & & ( g_numWaypoints > 0 ? g_isCommencing : true ) )
{
2015-06-04 11:52:48 +03:00
ServerCommand ( " speak \" %s \" " , const_cast < char * > ( sentences . GetRandomElement ( ) . GetBuffer ( ) ) ) ;
2014-07-30 14:17:46 +04:00
2015-06-04 11:52:48 +03:00
ChartPrint ( " ----- YaPB v%s (Build: %u), {%s}, (c) 2015, by %s ----- " , PRODUCT_VERSION , GenerateBuildNumber ( ) , PRODUCT_DATE , PRODUCT_AUTHOR ) ;
2015-06-24 15:38:48 +03:00
MESSAGE_BEGIN ( MSG_ONE , SVC_TEMPENTITY , NULL , g_hostEntity ) ;
WRITE_BYTE ( TE_TEXTMESSAGE ) ;
WRITE_BYTE ( 1 ) ;
WRITE_SHORT ( FixedSigned16 ( - 1 , 1 < < 13 ) ) ;
WRITE_SHORT ( FixedSigned16 ( - 1 , 1 < < 13 ) ) ;
WRITE_BYTE ( 2 ) ;
WRITE_BYTE ( Random . Long ( 33 , 255 ) ) ;
WRITE_BYTE ( Random . Long ( 33 , 255 ) ) ;
WRITE_BYTE ( Random . Long ( 33 , 255 ) ) ;
WRITE_BYTE ( 0 ) ;
WRITE_BYTE ( Random . Long ( 230 , 255 ) ) ;
WRITE_BYTE ( Random . Long ( 230 , 255 ) ) ;
WRITE_BYTE ( Random . Long ( 230 , 255 ) ) ;
WRITE_BYTE ( 200 ) ;
WRITE_SHORT ( FixedUnsigned16 ( 0.0078125 , 1 < < 8 ) ) ;
WRITE_SHORT ( FixedUnsigned16 ( 2 , 1 < < 8 ) ) ;
WRITE_SHORT ( FixedUnsigned16 ( 6 , 1 < < 8 ) ) ;
WRITE_SHORT ( FixedUnsigned16 ( 0.1 , 1 < < 8 ) ) ;
WRITE_STRING ( FormatBuffer ( " \n Server is running YaPB v%s (Build: %u) \n Developed by %s \n \n %s " , PRODUCT_VERSION , GenerateBuildNumber ( ) , PRODUCT_AUTHOR , g_waypoint - > GetInfo ( ) ) ) ;
MESSAGE_END ( ) ;
2014-07-30 14:17:46 +04:00
receiveTime = 0.0 ;
isReceived = true ;
}
}
void DetectCSVersion ( void )
{
2015-06-25 22:56:42 +03:00
if ( g_gameVersion = = CSV_OLD | | g_gameVersion = = CSV_CZERO )
return ;
2014-07-30 14:17:46 +04:00
// counter-strike 1.6 or higher (plus detects for non-steam versions of 1.5)
2015-06-25 22:56:42 +03:00
byte * detection = ( * g_engfuncs . pfnLoadFileForMe ) ( " events/galil.sc " , NULL ) ;
2014-07-30 14:17:46 +04:00
2015-06-25 22:56:42 +03:00
if ( detection ! = NULL )
g_gameVersion = CSV_STEAM ; // just to be sure
else if ( detection = = NULL )
g_gameVersion = CSV_OLD ; // reset it to WON
2014-07-30 14:17:46 +04:00
2015-06-25 22:56:42 +03:00
// if we have loaded the file free it
if ( detection ! = NULL )
( * g_engfuncs . pfnFreeFile ) ( detection ) ;
2014-07-30 14:17:46 +04:00
}
void PlaySound ( edict_t * ent , const char * name )
{
// TODO: make this obsolete
EMIT_SOUND_DYN2 ( ent , CHAN_WEAPON , name , 1.0 , ATTN_NORM , 0 , 100 ) ;
return ;
}
float GetWaveLength ( const char * fileName )
{
WavHeader waveHdr ;
memset ( & waveHdr , 0 , sizeof ( waveHdr ) ) ;
extern ConVar yb_chatter_path ;
File fp ( FormatBuffer ( " %s/%s/%s.wav " , GetModName ( ) , yb_chatter_path . GetString ( ) , fileName ) , " rb " ) ;
// we're got valid handle?
if ( ! fp . IsValid ( ) )
return 0 ;
if ( fp . Read ( & waveHdr , sizeof ( WavHeader ) ) = = 0 )
{
AddLogEntry ( true , LL_ERROR , " Wave File %s - has wrong or unsupported format " , fileName ) ;
return 0 ;
}
if ( strncmp ( waveHdr . chunkID , " WAVE " , 4 ) ! = 0 )
{
AddLogEntry ( true , LL_ERROR , " Wave File %s - has wrong wave chunk id " , fileName ) ;
return 0 ;
}
fp . Close ( ) ;
if ( waveHdr . dataChunkLength = = 0 )
{
AddLogEntry ( true , LL_ERROR , " Wave File %s - has zero length! " , fileName ) ;
return 0 ;
}
2015-07-05 21:32:56 +03:00
return static_cast < float > ( waveHdr . dataChunkLength ) / static_cast < float > ( waveHdr . bytesPerSecond ) ;
2014-07-30 14:17:46 +04:00
}
void AddLogEntry ( bool outputToConsole , int logLevel , const char * format , . . . )
{
// this function logs a message to the message log file root directory.
va_list ap ;
char buffer [ 512 ] = { 0 , } , levelString [ 32 ] = { 0 , } , logLine [ 1024 ] = { 0 , } ;
va_start ( ap , format ) ;
vsprintf ( buffer , g_localizer - > TranslateInput ( format ) , ap ) ;
va_end ( ap ) ;
switch ( logLevel )
{
case LL_DEFAULT :
strcpy ( levelString , " Log: " ) ;
break ;
case LL_WARNING :
strcpy ( levelString , " Warning: " ) ;
break ;
case LL_ERROR :
strcpy ( levelString , " Error: " ) ;
break ;
case LL_FATAL :
strcpy ( levelString , " Critical: " ) ;
break ;
}
if ( outputToConsole )
2015-06-11 14:19:52 +03:00
ServerPrint ( " %s%s " , levelString , buffer ) ;
2014-07-30 14:17:46 +04:00
// now check if logging disabled
if ( ! ( logLevel & LL_IGNORE ) )
{
extern ConVar yb_debug ;
if ( logLevel = = LL_DEFAULT & & yb_debug . GetInt ( ) < 3 )
return ; // no log, default logging is disabled
if ( logLevel = = LL_WARNING & & yb_debug . GetInt ( ) < 2 )
return ; // no log, warning logging is disabled
if ( logLevel = = LL_ERROR & & yb_debug . GetInt ( ) < 1 )
return ; // no log, error logging is disabled
}
// open file in a standard stream
File fp ( " yapb.txt " , " at " ) ;
// check if we got a valid handle
if ( ! fp . IsValid ( ) )
return ;
time_t tickTime = time ( & tickTime ) ;
tm * time = localtime ( & tickTime ) ;
sprintf ( logLine , " [%02d:%02d:%02d] %s%s " , time - > tm_hour , time - > tm_min , time - > tm_sec , levelString , buffer ) ;
fp . Printf ( " %s \n " , logLine ) ;
fp . Close ( ) ;
if ( logLevel = = LL_FATAL )
{
# if defined (PLATFORM_WIN32)
MessageBoxA ( GetActiveWindow ( ) , buffer , " YaPB Error " , MB_ICONSTOP ) ;
# else
2015-06-06 16:37:15 +03:00
printf ( " %s " , buffer ) ;
2014-07-30 14:17:46 +04:00
# endif
FreeLibraryMemory ( ) ;
# if defined (PLATFORM_WIN32)
_exit ( 1 ) ;
# else
exit ( 1 ) ;
# endif
}
}
char * Localizer : : TranslateInput ( const char * input )
{
if ( IsDedicatedServer ( ) )
return const_cast < char * > ( & input [ 0 ] ) ;
static char string [ 1024 ] ;
const char * ptr = input + strlen ( input ) - 1 ;
while ( ptr > input & & * ptr = = ' \n ' )
ptr - - ;
if ( ptr ! = input )
ptr + + ;
2015-06-29 22:06:55 +03:00
strncpy ( string , input , SIZEOF_CHAR ( string ) ) ;
2014-07-30 14:17:46 +04:00
strtrim ( string ) ;
2015-06-28 19:43:31 +03:00
FOR_EACH_AE ( m_langTab , i )
2014-07-30 14:17:46 +04:00
{
if ( strcmp ( string , m_langTab [ i ] . original ) = = 0 )
{
2015-06-28 19:43:31 +03:00
strncpy ( string , m_langTab [ i ] . translated , 1023 ) ;
2014-07-30 14:17:46 +04:00
if ( ptr ! = input )
strncat ( string , ptr , 1024 - 1 - strlen ( string ) ) ;
return & string [ 0 ] ;
}
}
return const_cast < char * > ( & input [ 0 ] ) ; // nothing found
}
bool FindNearestPlayer ( void * * pvHolder , edict_t * to , float searchDistance , bool sameTeam , bool needBot , bool isAlive , bool needDrawn )
{
// this function finds nearest to to, player with set of parameters, like his
// team, live status, search distance etc. if needBot is true, then pvHolder, will
// be filled with bot pointer, else with edict pointer(!).
2015-06-08 16:18:55 +03:00
edict_t * survive = NULL ; // pointer to temporaly & survive entity
2014-07-30 14:17:46 +04:00
float nearestPlayer = 4096.0 ; // nearest player
2015-06-09 15:45:34 +03:00
int toTeam = GetTeam ( to ) ;
2015-06-08 16:18:55 +03:00
for ( int i = 0 ; i < GetMaxClients ( ) ; i + + )
2014-07-30 14:17:46 +04:00
{
2015-06-08 16:18:55 +03:00
edict_t * ent = g_clients [ i ] . ent ;
if ( ! ( g_clients [ i ] . flags & CF_USED ) | | ent = = to )
continue ;
2014-07-30 14:17:46 +04:00
2015-06-09 15:45:34 +03:00
if ( ( sameTeam & & g_clients [ i ] . team ! = toTeam ) | | ( isAlive & & ! ( g_clients [ i ] . flags & CF_ALIVE ) ) | | ( needBot & & ! IsValidBot ( ent ) ) | | ( needDrawn & & ( ent - > v . effects & EF_NODRAW ) ) )
2014-07-30 14:17:46 +04:00
continue ; // filter players with parameters
2015-06-28 19:43:31 +03:00
float distance = ( ent - > v . origin - to - > v . origin ) . GetLength ( ) ;
2014-07-30 14:17:46 +04:00
2015-06-28 19:43:31 +03:00
if ( distance < nearestPlayer & & distance < searchDistance )
2014-07-30 14:17:46 +04:00
{
nearestPlayer = distance ;
survive = ent ;
}
}
2015-06-04 11:52:48 +03:00
if ( IsEntityNull ( survive ) )
2014-07-30 14:17:46 +04:00
return false ; // nothing found
// fill the holder
if ( needBot )
* pvHolder = reinterpret_cast < void * > ( g_botManager - > GetBot ( survive ) ) ;
else
* pvHolder = reinterpret_cast < void * > ( survive ) ;
return true ;
}
void SoundAttachToThreat ( edict_t * ent , const char * sample , float volume )
{
// this function called by the sound hooking code (in emit_sound) enters the played sound into
// the array associated with the entity
2015-06-04 11:52:48 +03:00
if ( IsEntityNull ( ent ) | | IsNullString ( sample ) )
2014-07-30 14:17:46 +04:00
return ; // reliability check
2015-06-28 19:43:31 +03:00
const Vector & origin = GetEntityOrigin ( ent ) ;
2014-09-17 20:36:42 +04:00
int index = IndexOfEntity ( ent ) - 1 ;
2014-07-30 14:17:46 +04:00
if ( index < 0 | | index > = GetMaxClients ( ) )
{
float nearestDistance = FLT_MAX ;
// loop through all players
for ( int i = 0 ; i < GetMaxClients ( ) ; i + + )
{
if ( ! ( g_clients [ i ] . flags & CF_USED ) | | ! ( g_clients [ i ] . flags & CF_ALIVE ) )
continue ;
float distance = ( g_clients [ i ] . ent - > v . origin - origin ) . GetLengthSquared ( ) ;
// now find nearest player
if ( distance < nearestDistance )
{
index = i ;
nearestDistance = distance ;
}
}
}
if ( strncmp ( " player/bhit_flesh " , sample , 17 ) = = 0 | | strncmp ( " player/headshot " , sample , 15 ) = = 0 )
{
// hit/fall sound?
g_clients [ index ] . hearingDistance = 768.0 * volume ;
g_clients [ index ] . timeSoundLasting = GetWorldTime ( ) + 0.5 ;
g_clients [ index ] . maxTimeSoundLasting = 0.5 ;
g_clients [ index ] . soundPosition = origin ;
}
else if ( strncmp ( " items/gunpickup " , sample , 15 ) = = 0 )
{
// weapon pickup?
g_clients [ index ] . hearingDistance = 768.0 * volume ;
g_clients [ index ] . timeSoundLasting = GetWorldTime ( ) + 0.5 ;
g_clients [ index ] . maxTimeSoundLasting = 0.5 ;
g_clients [ index ] . soundPosition = origin ;
}
else if ( strncmp ( " weapons/zoom " , sample , 12 ) = = 0 )
{
// sniper zooming?
g_clients [ index ] . hearingDistance = 512.0 * volume ;
g_clients [ index ] . timeSoundLasting = GetWorldTime ( ) + 0.1 ;
g_clients [ index ] . maxTimeSoundLasting = 0.1 ;
g_clients [ index ] . soundPosition = origin ;
}
else if ( strncmp ( " items/9mmclip " , sample , 13 ) = = 0 )
{
// ammo pickup?
g_clients [ index ] . hearingDistance = 512.0 * volume ;
g_clients [ index ] . timeSoundLasting = GetWorldTime ( ) + 0.1 ;
g_clients [ index ] . maxTimeSoundLasting = 0.1 ;
g_clients [ index ] . soundPosition = origin ;
}
else if ( strncmp ( " hostage/hos " , sample , 11 ) = = 0 )
{
// CT used hostage?
g_clients [ index ] . hearingDistance = 1024.0 * volume ;
g_clients [ index ] . timeSoundLasting = GetWorldTime ( ) + 5.0 ;
g_clients [ index ] . maxTimeSoundLasting = 0.5 ;
g_clients [ index ] . soundPosition = origin ;
}
else if ( strncmp ( " debris/bustmetal " , sample , 16 ) = = 0 | | strncmp ( " debris/bustglass " , sample , 16 ) = = 0 )
{
// broke something?
g_clients [ index ] . hearingDistance = 1024.0 * volume ;
g_clients [ index ] . timeSoundLasting = GetWorldTime ( ) + 2.0 ;
g_clients [ index ] . maxTimeSoundLasting = 2.0 ;
g_clients [ index ] . soundPosition = origin ;
}
else if ( strncmp ( " doors/doormove " , sample , 14 ) = = 0 )
{
// someone opened a door
g_clients [ index ] . hearingDistance = 1024.0 * volume ;
g_clients [ index ] . timeSoundLasting = GetWorldTime ( ) + 3.0 ;
g_clients [ index ] . maxTimeSoundLasting = 3.0 ;
g_clients [ index ] . soundPosition = origin ;
}
#if 0
else if ( strncmp ( " weapons/reload " , sample , 14 ) = = 0 )
{
// reloading ?
g_clients [ index ] . hearingDistance = 512.0 * volume ;
g_clients [ index ] . timeSoundLasting = GetWorldTime ( ) + 0.5 ;
g_clients [ index ] . maxTimeSoundLasting = 0.5 ;
g_clients [ index ] . soundPosition = origin ;
}
# endif
}
void SoundSimulateUpdate ( int playerIndex )
{
// this function tries to simulate playing of sounds to let the bots hear sounds which aren't
// captured through server sound hooking
InternalAssert ( playerIndex > = 0 ) ;
InternalAssert ( playerIndex < GetMaxClients ( ) ) ;
if ( playerIndex < 0 | | playerIndex > = GetMaxClients ( ) )
return ; // reliability check
edict_t * player = g_clients [ playerIndex ] . ent ;
float velocity = player - > v . velocity . GetLength2D ( ) ;
float hearDistance = 0.0 ;
float timeSound = 0.0 ;
float timeMaxSound = 0.5 ;
if ( player - > v . oldbuttons & IN_ATTACK ) // pressed attack button?
{
hearDistance = 3072.0 ;
timeSound = GetWorldTime ( ) + 0.3 ;
timeMaxSound = 0.3 ;
}
else if ( player - > v . oldbuttons & IN_USE ) // pressed used button?
{
hearDistance = 512.0 ;
timeSound = GetWorldTime ( ) + 0.5 ;
timeMaxSound = 0.5 ;
}
else if ( player - > v . oldbuttons & IN_RELOAD ) // pressed reload button?
{
hearDistance = 512.0 ;
timeSound = GetWorldTime ( ) + 0.5 ;
timeMaxSound = 0.5 ;
}
else if ( player - > v . movetype = = MOVETYPE_FLY ) // uses ladder?
{
if ( fabs ( player - > v . velocity . z ) > 50.0 )
{
hearDistance = 1024.0 ;
timeSound = GetWorldTime ( ) + 0.3 ;
timeMaxSound = 0.3 ;
}
}
else
{
extern ConVar mp_footsteps ;
if ( mp_footsteps . GetBool ( ) )
{
// moves fast enough?
hearDistance = 1280.0 * ( velocity / 240 ) ;
timeSound = GetWorldTime ( ) + 0.3 ;
timeMaxSound = 0.3 ;
}
}
if ( hearDistance < = 0.0 )
return ; // didn't issue sound?
// some sound already associated
if ( g_clients [ playerIndex ] . timeSoundLasting > GetWorldTime ( ) )
{
// new sound louder (bigger range) than old one ?
if ( g_clients [ playerIndex ] . maxTimeSoundLasting < = 0.0 )
g_clients [ playerIndex ] . maxTimeSoundLasting = 0.5 ;
if ( g_clients [ playerIndex ] . hearingDistance * ( g_clients [ playerIndex ] . timeSoundLasting - GetWorldTime ( ) ) / g_clients [ playerIndex ] . maxTimeSoundLasting < = hearDistance )
{
// override it with new
g_clients [ playerIndex ] . hearingDistance = hearDistance ;
g_clients [ playerIndex ] . timeSoundLasting = timeSound ;
g_clients [ playerIndex ] . maxTimeSoundLasting = timeMaxSound ;
g_clients [ playerIndex ] . soundPosition = player - > v . origin ;
}
}
else
{
// just remember it
g_clients [ playerIndex ] . hearingDistance = hearDistance ;
g_clients [ playerIndex ] . timeSoundLasting = timeSound ;
g_clients [ playerIndex ] . maxTimeSoundLasting = timeMaxSound ;
g_clients [ playerIndex ] . soundPosition = player - > v . origin ;
}
}
uint16 GenerateBuildNumber ( void )
{
// this function generates build number from the compiler date macros
2015-07-05 21:32:56 +03:00
static uint16 buildNumber = 0 ;
if ( buildNumber ! = 0 )
return buildNumber ;
2014-07-30 14:17:46 +04:00
// get compiling date using compiler macros
const char * date = __DATE__ ;
// array of the month names
const char * months [ 12 ] = { " Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " , " Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec " } ;
// array of the month days
byte monthDays [ 12 ] = { 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 } ;
int day = 0 ; // day of the year
int year = 0 ; // year
int i = 0 ;
2015-07-05 21:32:56 +03:00
// go through all months, and calculate, days since year start
2014-07-30 14:17:46 +04:00
for ( i = 0 ; i < 11 ; i + + )
{
if ( strncmp ( & date [ 0 ] , months [ i ] , 3 ) = = 0 )
break ; // found current month break
day + = monthDays [ i ] ; // add month days
}
day + = atoi ( & date [ 4 ] ) - 1 ; // finally calculate day
year = atoi ( & date [ 7 ] ) - 2000 ; // get years since year 2000
2015-07-05 21:32:56 +03:00
buildNumber = day + static_cast < int > ( ( year - 1 ) * 365.25 ) ;
2014-07-30 14:17:46 +04:00
// if the year is a leap year?
if ( ( year % 4 ) = = 0 & & i > 1 )
buildNumber + = 1 ; // add one year more
2015-07-05 21:32:56 +03:00
buildNumber - = 1114 ;
return buildNumber ;
2014-07-30 14:17:46 +04:00
}
int GetWeaponReturn ( bool needString , const char * weaponAlias , int weaponIndex )
{
// this function returning weapon id from the weapon alias and vice versa.
// structure definition for weapon tab
struct WeaponTab_t
{
Weapon weaponIndex ; // weapon id
const char * alias ; // weapon alias
} ;
// weapon enumeration
WeaponTab_t weaponTab [ ] =
{
{ WEAPON_USP , " usp " } , // HK USP .45 Tactical
{ WEAPON_GLOCK , " glock " } , // Glock18 Select Fire
{ WEAPON_DEAGLE , " deagle " } , // Desert Eagle .50AE
{ WEAPON_P228 , " p228 " } , // SIG P228
{ WEAPON_ELITE , " elite " } , // Dual Beretta 96G Elite
{ WEAPON_FIVESEVEN , " fn57 " } , // FN Five-Seven
{ WEAPON_M3 , " m3 " } , // Benelli M3 Super90
{ WEAPON_XM1014 , " xm1014 " } , // Benelli XM1014
{ WEAPON_MP5 , " mp5 " } , // HK MP5-Navy
{ WEAPON_TMP , " tmp " } , // Steyr Tactical Machine Pistol
{ WEAPON_P90 , " p90 " } , // FN P90
{ WEAPON_MAC10 , " mac10 " } , // Ingram MAC-10
{ WEAPON_UMP45 , " ump45 " } , // HK UMP45
{ WEAPON_AK47 , " ak47 " } , // Automat Kalashnikov AK-47
{ WEAPON_GALIL , " galil " } , // IMI Galil
{ WEAPON_FAMAS , " famas " } , // GIAT FAMAS
{ WEAPON_SG552 , " sg552 " } , // Sig SG-552 Commando
{ WEAPON_M4A1 , " m4a1 " } , // Colt M4A1 Carbine
{ WEAPON_AUG , " aug " } , // Steyr Aug
{ WEAPON_SCOUT , " scout " } , // Steyr Scout
{ WEAPON_AWP , " awp " } , // AI Arctic Warfare/Magnum
{ WEAPON_G3SG1 , " g3sg1 " } , // HK G3/SG-1 Sniper Rifle
{ WEAPON_SG550 , " sg550 " } , // Sig SG-550 Sniper
{ WEAPON_M249 , " m249 " } , // FN M249 Para
{ WEAPON_FLASHBANG , " flash " } , // Concussion Grenade
{ WEAPON_EXPLOSIVE , " hegren " } , // High-Explosive Grenade
{ WEAPON_SMOKE , " sgren " } , // Smoke Grenade
{ WEAPON_ARMOR , " vest " } , // Kevlar Vest
{ WEAPON_ARMORHELM , " vesthelm " } , // Kevlar Vest and Helmet
{ WEAPON_DEFUSER , " defuser " } , // Defuser Kit
{ WEAPON_SHIELD , " shield " } , // Tactical Shield
} ;
// if we need to return the string, find by weapon id
if ( needString & & weaponIndex ! = - 1 )
{
for ( int i = 0 ; i < ARRAYSIZE_HLSDK ( weaponTab ) ; i + + )
{
if ( weaponTab [ i ] . weaponIndex = = weaponIndex ) // is weapon id found?
return MAKE_STRING ( weaponTab [ i ] . alias ) ;
}
return MAKE_STRING ( " (none) " ) ; // return none
}
// else search weapon by name and return weapon id
for ( int i = 0 ; i < ARRAYSIZE_HLSDK ( weaponTab ) ; i + + )
{
if ( strncmp ( weaponTab [ i ] . alias , weaponAlias , strlen ( weaponTab [ i ] . alias ) ) = = 0 )
return weaponTab [ i ] . weaponIndex ;
}
return - 1 ; // no weapon was found return -1
}