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
2016-02-06 23:37:58 +03:00
ConVar yb_display_menu_text ( " yb_display_menu_text " , " 1 " ) ;
2014-07-30 14:17:46 +04:00
ConVar mp_roundtime ( " mp_roundtime " , NULL , VT_NOREGISTER ) ;
2015-12-26 17:19:20 +03:00
# ifndef XASH_CSDM
2014-07-30 14:17:46 +04:00
ConVar mp_freezetime ( " mp_freezetime " , NULL , VT_NOREGISTER ) ;
2015-12-26 17:19:20 +03:00
# else
ConVar mp_freezetime ( " mp_freezetime " , " 0 " , VT_NOSERVER ) ;
# endif
2014-07-30 14:17:46 +04:00
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 ;
2016-03-01 13:37:10 +03:00
engine . TestLine ( ent - > v . origin + ent - > v . view_ofs , origin , TRACE_IGNORE_EVERYTHING , ent , & tr ) ;
2014-07-30 14:17:46 +04:00
2016-01-04 18:26:06 +03:00
if ( tr . flFraction ! = 1.0f )
2016-02-11 21:50:05 +03:00
return false ;
2014-07-30 14:17:46 +04:00
2016-02-11 21:50:05 +03:00
return true ;
2014-07-30 14:17:46 +04:00
}
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-07-24 14:39:11 +03:00
char * text = locale . 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 ) ) ;
2016-02-11 21:50:05 +03:00
if ( ( g_gameFlags & ( GAME_XASH | GAME_MOBILITY ) ) & & ! yb_display_menu_text . GetBool ( ) )
2016-02-06 23:37:58 +03:00
text = " " ;
else
text = ( char * ) tempText . GetBuffer ( ) ;
2014-07-30 14:17:46 +04:00
while ( strlen ( text ) > = 64 )
{
2015-07-24 14:39:11 +03:00
MESSAGE_BEGIN ( MSG_ONE_UNRELIABLE , netmsg . GetId ( NETMSG_SHOWMENU ) , NULL , ent ) ;
2014-07-30 14:17:46 +04:00
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 ;
}
2015-07-24 14:39:11 +03:00
MESSAGE_BEGIN ( MSG_ONE_UNRELIABLE , netmsg . GetId ( NETMSG_SHOWMENU ) , NULL , ent ) ;
2014-07-30 14:17:46 +04:00
WRITE_SHORT ( menu - > validSlots ) ;
WRITE_CHAR ( - 1 ) ;
WRITE_BYTE ( 0 ) ;
WRITE_STRING ( text ) ;
MESSAGE_END ( ) ;
g_clients [ clientIndex ] . menu = menu ;
}
else
{
2015-07-24 14:39:11 +03:00
MESSAGE_BEGIN ( MSG_ONE_UNRELIABLE , netmsg . GetId ( NETMSG_SHOWMENU ) , NULL , ent ) ;
2014-07-30 14:17:46 +04:00
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 " ) ;
2016-01-04 18:26:06 +03:00
if ( trace - > flFraction = = 1.0f )
2014-07-30 14:17:46 +04:00
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
2015-07-24 15:10:51 +03:00
waypoints . Init ( ) ; // frees waypoint data
2015-07-24 14:39:11 +03:00
locale . Destroy ( ) ; // clear language
2015-06-18 19:29:40 +03:00
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 ;
}
// 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 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 + + )
{
2016-03-01 13:37:10 +03:00
( g_experienceData + ( i * g_numWaypoints ) + i ) - > team0Damage / = static_cast < unsigned short > ( engine . MaxClients ( ) * 0.5 ) ;
( g_experienceData + ( i * g_numWaypoints ) + i ) - > team1Damage / = static_cast < unsigned short > ( engine . MaxClients ( ) * 0.5 ) ;
2014-07-30 14:17:46 +04:00
}
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
2016-01-30 13:15:50 +03:00
bots . CheckTeamEconomics ( TERRORIST ) ;
bots . CheckTeamEconomics ( CT ) ;
2014-07-30 14:17:46 +04:00
2016-03-01 13:37:10 +03:00
for ( int i = 0 ; i < engine . MaxClients ( ) ; i + + )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
if ( bots . GetBot ( i ) )
bots . GetBot ( i ) - > NewRound ( ) ;
2014-07-30 14:17:46 +04:00
g_radioSelect [ i ] = 0 ;
}
2015-07-24 15:10:51 +03:00
waypoints . SetBombPosition ( true ) ;
2016-01-07 18:49:55 +03:00
waypoints . ClearVisitedGoals ( ) ;
2014-07-30 14:17:46 +04:00
g_bombSayString = false ;
2015-08-15 18:09:15 +03:00
g_timeBombPlanted = 0.0f ;
g_timeNextBombUpdate = 0.0f ;
2014-07-30 14:17:46 +04:00
2016-01-30 13:15:50 +03:00
g_leaderChoosen [ CT ] = false ;
g_leaderChoosen [ TERRORIST ] = false ;
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
g_lastRadioTime [ 0 ] = 0.0f ;
g_lastRadioTime [ 1 ] = 0.0f ;
2014-07-30 14:17:46 +04:00
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
2016-03-01 13:37:10 +03:00
g_timeRoundStart = engine . Time ( ) + mp_freezetime . GetFloat ( ) ;
2015-08-15 18:09:15 +03:00
g_timeRoundMid = g_timeRoundStart + mp_roundtime . GetFloat ( ) * 60.0f * 0.5f ;
g_timeRoundEnd = g_timeRoundStart + mp_roundtime . GetFloat ( ) * 60.0f ;
2014-07-30 14:17:46 +04:00
}
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 ;
2015-07-24 15:10:51 +03:00
if ( ( ent - > v . flags & ( FL_CLIENT | FL_FAKECLIENT ) ) | | bots . GetBot ( ent ) ! = NULL )
2014-07-30 14:17:46 +04:00
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-07-24 15:10:51 +03:00
if ( bots . GetBot ( ent ) ! = NULL | | ( ! IsEntityNull ( ent ) & & ( ent - > v . flags & FL_FAKECLIENT ) ) )
2014-07-30 14:17:46 +04:00
return true ;
return false ;
}
2016-03-01 13:37:10 +03:00
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 )
{
2016-03-01 13:37:10 +03:00
const char * mod = engine . GetModName ( ) ;
2014-07-30 14:17:46 +04:00
extern ConVar yb_language ;
if ( strcmp ( fileName , " lang.cfg " ) = = 0 & & strcmp ( yb_language . GetString ( ) , " en " ) = = 0 )
return false ;
2016-03-01 13:37:10 +03:00
const char * languageDependantConfigFile = FormatBuffer ( " %s/addons/yapb/conf/lang/%s_%s " , mod , yb_language . GetString ( ) , fileName ) ;
2014-07-30 14:17:46 +04:00
// check is file is exists for this language
2015-07-11 19:54:46 +03:00
if ( File : : Accessible ( languageDependantConfigFile ) )
2014-07-30 14:17:46 +04:00
outFile - > Open ( languageDependantConfigFile , " rt " ) ;
else
2016-03-01 13:37:10 +03:00
outFile - > Open ( FormatBuffer ( " %s/addons/yapb/conf/lang/en_%s " , mod , fileName ) , " rt " ) ;
2014-07-30 14:17:46 +04:00
}
else
2016-03-01 13:37:10 +03:00
outFile - > Open ( FormatBuffer ( " %s/addons/yapb/conf/%s " , engine . 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 )
2016-01-03 22:03:02 +03:00
{
2016-03-01 13:37:10 +03:00
return FormatBuffer ( " %s/addons/yapb/data/ " , engine . GetModName ( ) ) ;
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.
2016-02-06 23:37:58 +03:00
static bool alreadyReceived = false ;
2015-08-15 18:09:15 +03:00
static float receiveTime = 0.0f ;
2014-07-30 14:17:46 +04:00
2015-08-02 20:31:14 +03:00
if ( alreadyReceived )
2014-07-30 14:17:46 +04:00
return ;
Array < String > sentences ;
2016-02-11 21:50:05 +03:00
if ( ! ( g_gameFlags & ( GAME_MOBILITY | GAME_XASH ) ) )
2016-02-06 23:37:58 +03:00
{
// 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 " ) ;
}
2014-07-30 14:17:46 +04:00
2015-08-02 20:31:14 +03:00
if ( IsAlive ( g_hostEntity ) & & ! alreadyReceived & & receiveTime < 1.0 & & ( g_numWaypoints > 0 ? g_isCommencing : true ) )
2016-03-01 13:37:10 +03:00
receiveTime = engine . Time ( ) + 4.0f ; // receive welcome message in four seconds after game has commencing
2014-07-30 14:17:46 +04:00
2016-03-01 13:37:10 +03:00
if ( receiveTime > 0.0f & & receiveTime < engine . Time ( ) & & ! alreadyReceived & & ( g_numWaypoints > 0 ? g_isCommencing : true ) )
2014-07-30 14:17:46 +04:00
{
2016-02-11 21:50:05 +03:00
if ( ! ( g_gameFlags & ( GAME_MOBILITY | GAME_XASH ) ) )
2016-03-01 13:37:10 +03:00
engine . IssueCmd ( " speak \" %s \" " , const_cast < char * > ( sentences . GetRandomElement ( ) . GetBuffer ( ) ) ) ;
2016-02-06 23:37:58 +03:00
2016-03-01 13:37:10 +03:00
engine . ChatPrintf ( " ----- %s v%s (Build: %u), {%s}, (c) 2016, by %s (%s)----- " , PRODUCT_NAME , PRODUCT_VERSION , GenerateBuildNumber ( ) , PRODUCT_DATE , PRODUCT_AUTHOR , PRODUCT_URL ) ;
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 ) ;
2015-08-15 18:09:15 +03:00
WRITE_SHORT ( FixedUnsigned16 ( 0.0078125f , 1 < < 8 ) ) ;
WRITE_SHORT ( FixedUnsigned16 ( 2.0f , 1 < < 8 ) ) ;
WRITE_SHORT ( FixedUnsigned16 ( 6.0f , 1 < < 8 ) ) ;
WRITE_SHORT ( FixedUnsigned16 ( 0.1f , 1 < < 8 ) ) ;
2015-07-24 15:10:51 +03:00
WRITE_STRING ( FormatBuffer ( " \n Server is running YaPB v%s (Build: %u) \n Developed by %s \n \n %s " , PRODUCT_VERSION , GenerateBuildNumber ( ) , PRODUCT_AUTHOR , waypoints . GetInfo ( ) ) ) ;
2015-06-24 15:38:48 +03:00
MESSAGE_END ( ) ;
2014-07-30 14:17:46 +04:00
receiveTime = 0.0 ;
2015-08-02 20:31:14 +03:00
alreadyReceived = true ;
2014-07-30 14:17:46 +04:00
}
}
void DetectCSVersion ( void )
{
2016-02-11 21:50:05 +03:00
if ( g_gameFlags & GAME_CZERO )
2015-06-25 22:56:42 +03:00
return ;
2014-07-30 14:17:46 +04:00
2016-01-30 22:22:37 +03:00
// detect xash engine
if ( g_engfuncs . pfnCVarGetPointer ( " build " ) ! = NULL )
{
2016-02-11 21:50:05 +03:00
g_gameFlags | = ( GAME_LEGACY | GAME_XASH ) ;
2016-01-30 22:22:37 +03:00
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 )
2016-02-11 21:50:05 +03:00
g_gameFlags | = GAME_CSTRIKE16 ; // just to be sure
2015-06-25 22:56:42 +03:00
else if ( detection = = NULL )
2016-02-11 21:50:05 +03:00
g_gameFlags | = GAME_LEGACY ; // 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 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 ) ;
2015-07-24 14:39:11 +03:00
vsprintf ( buffer , locale . TranslateInput ( format ) , ap ) ;
2014-07-30 14:17:46 +04:00
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 )
2016-03-01 13:37:10 +03:00
engine . Printf ( " %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 )
{
2015-08-15 18:09:15 +03:00
bots . RemoveAll ( ) ;
FreeLibraryMemory ( ) ;
2014-07-30 14:17:46 +04:00
# if defined (PLATFORM_WIN32)
2015-08-15 18:09:15 +03:00
DestroyWindow ( GetForegroundWindow ( ) ) ;
2014-07-30 14:17:46 +04:00
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
2015-08-15 18:09:15 +03:00
2014-07-30 14:17:46 +04:00
# if defined (PLATFORM_WIN32)
_exit ( 1 ) ;
# else
exit ( 1 ) ;
# endif
}
}
char * Localizer : : TranslateInput ( const char * input )
{
2016-03-01 13:37:10 +03:00
if ( engine . IsDedicatedServer ( ) )
2014-07-30 14:17:46 +04:00
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 )
{
2016-02-29 23:50:16 +03:00
strncpy ( string , m_langTab [ i ] . translated , SIZEOF_CHAR ( string ) ) ;
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
}
2015-07-24 14:39:11 +03:00
void Localizer : : Destroy ( void )
{
FOR_EACH_AE ( m_langTab , it )
{
delete [ ] m_langTab [ it ] . original ;
delete [ ] m_langTab [ it ] . translated ;
}
m_langTab . RemoveAll ( ) ;
}
2014-07-30 14:17:46 +04:00
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
2015-08-15 18:09:15 +03:00
float nearestPlayer = 4096.0f ; // nearest player
2014-07-30 14:17:46 +04:00
2015-06-09 15:45:34 +03:00
int toTeam = GetTeam ( to ) ;
2016-03-01 13:37:10 +03:00
for ( int i = 0 ; i < engine . MaxClients ( ) ; 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 )
2015-07-24 15:10:51 +03:00
* pvHolder = reinterpret_cast < void * > ( bots . GetBot ( survive ) ) ;
2014-07-30 14:17:46 +04:00
else
* pvHolder = reinterpret_cast < void * > ( survive ) ;
return true ;
}
2015-07-19 13:39:00 +03:00
void SoundAttachToClients ( edict_t * ent , const char * sample , float volume )
2014-07-30 14:17:46 +04:00
{
// 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
2016-03-01 13:37:10 +03:00
const Vector & origin = engine . GetAbsOrigin ( ent ) ;
2014-09-17 20:36:42 +04:00
int index = IndexOfEntity ( ent ) - 1 ;
2014-07-30 14:17:46 +04:00
2016-03-01 13:37:10 +03:00
if ( index < 0 | | index > = engine . MaxClients ( ) )
2014-07-30 14:17:46 +04:00
{
2015-07-12 17:18:20 +03:00
float nearestDistance = 99999.0f ;
2014-07-30 14:17:46 +04:00
// loop through all players
2016-03-01 13:37:10 +03:00
for ( int i = 0 ; i < engine . MaxClients ( ) ; i + + )
2014-07-30 14:17:46 +04:00
{
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 ;
}
}
}
2015-07-19 13:39:00 +03:00
Client * client = & g_clients [ index ] ;
2014-07-30 14:17:46 +04:00
2016-01-30 13:15:50 +03:00
if ( client = = NULL )
return ;
2014-07-30 14:17:46 +04:00
if ( strncmp ( " player/bhit_flesh " , sample , 17 ) = = 0 | | strncmp ( " player/headshot " , sample , 15 ) = = 0 )
{
// hit/fall sound?
2015-08-15 18:09:15 +03:00
client - > hearingDistance = 768.0f * volume ;
2016-03-01 13:37:10 +03:00
client - > timeSoundLasting = engine . Time ( ) + 0.5f ;
2015-07-19 13:39:00 +03:00
client - > soundPosition = origin ;
2014-07-30 14:17:46 +04:00
}
else if ( strncmp ( " items/gunpickup " , sample , 15 ) = = 0 )
{
// weapon pickup?
2015-08-15 18:09:15 +03:00
client - > hearingDistance = 768.0f * volume ;
2016-03-01 13:37:10 +03:00
client - > timeSoundLasting = engine . Time ( ) + 0.5f ;
2015-07-19 13:39:00 +03:00
client - > soundPosition = origin ;
2014-07-30 14:17:46 +04:00
}
else if ( strncmp ( " weapons/zoom " , sample , 12 ) = = 0 )
{
// sniper zooming?
2015-08-15 18:09:15 +03:00
client - > hearingDistance = 512.0f * volume ;
2016-03-01 13:37:10 +03:00
client - > timeSoundLasting = engine . Time ( ) + 0.1f ;
2015-07-19 13:39:00 +03:00
client - > soundPosition = origin ;
2014-07-30 14:17:46 +04:00
}
else if ( strncmp ( " items/9mmclip " , sample , 13 ) = = 0 )
{
// ammo pickup?
2015-08-15 18:09:15 +03:00
client - > hearingDistance = 512.0f * volume ;
2016-03-01 13:37:10 +03:00
client - > timeSoundLasting = engine . Time ( ) + 0.1f ;
2015-07-19 13:39:00 +03:00
client - > soundPosition = origin ;
2014-07-30 14:17:46 +04:00
}
else if ( strncmp ( " hostage/hos " , sample , 11 ) = = 0 )
{
// CT used hostage?
2015-08-15 18:09:15 +03:00
client - > hearingDistance = 1024.0f * volume ;
2016-03-01 13:37:10 +03:00
client - > timeSoundLasting = engine . Time ( ) + 5.0f ;
2015-07-19 13:39:00 +03:00
client - > soundPosition = origin ;
2014-07-30 14:17:46 +04:00
}
else if ( strncmp ( " debris/bustmetal " , sample , 16 ) = = 0 | | strncmp ( " debris/bustglass " , sample , 16 ) = = 0 )
{
// broke something?
2015-08-15 18:09:15 +03:00
client - > hearingDistance = 1024.0f * volume ;
2016-03-01 13:37:10 +03:00
client - > timeSoundLasting = engine . Time ( ) + 2.0f ;
2015-07-19 13:39:00 +03:00
client - > soundPosition = origin ;
2014-07-30 14:17:46 +04:00
}
else if ( strncmp ( " doors/doormove " , sample , 14 ) = = 0 )
{
// someone opened a door
2015-08-15 18:09:15 +03:00
client - > hearingDistance = 1024.0f * volume ;
2016-03-01 13:37:10 +03:00
client - > timeSoundLasting = engine . Time ( ) + 3.0f ;
2015-07-19 13:39:00 +03:00
client - > soundPosition = origin ;
2014-07-30 14:17:46 +04:00
}
}
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
2016-03-01 13:37:10 +03:00
if ( playerIndex < 0 | | playerIndex > = engine . MaxClients ( ) )
2014-07-30 14:17:46 +04:00
return ; // reliability check
2015-07-19 13:39:00 +03:00
Client * client = & g_clients [ playerIndex ] ;
2014-07-30 14:17:46 +04:00
2015-07-19 13:39:00 +03:00
float hearDistance = 0.0f ;
float timeSound = 0.0f ;
2014-07-30 14:17:46 +04:00
2015-07-19 13:39:00 +03:00
if ( client - > ent - > v . oldbuttons & IN_ATTACK ) // pressed attack button?
2014-07-30 14:17:46 +04:00
{
2016-01-30 13:15:50 +03:00
hearDistance = 2048.0f ;
2016-03-01 13:37:10 +03:00
timeSound = engine . Time ( ) + 0.3f ;
2014-07-30 14:17:46 +04:00
}
2015-07-19 13:39:00 +03:00
else if ( client - > ent - > v . oldbuttons & IN_USE ) // pressed used button?
2014-07-30 14:17:46 +04:00
{
2016-01-30 13:15:50 +03:00
hearDistance = 512.0f ;
2016-03-01 13:37:10 +03:00
timeSound = engine . Time ( ) + 0.5f ;
2014-07-30 14:17:46 +04:00
}
2015-07-19 13:39:00 +03:00
else if ( client - > ent - > v . oldbuttons & IN_RELOAD ) // pressed reload button?
2014-07-30 14:17:46 +04:00
{
2016-01-30 13:15:50 +03:00
hearDistance = 512.0f ;
2016-03-01 13:37:10 +03:00
timeSound = engine . Time ( ) + 0.5f ;
2014-07-30 14:17:46 +04:00
}
2015-07-19 13:39:00 +03:00
else if ( client - > ent - > v . movetype = = MOVETYPE_FLY ) // uses ladder?
2014-07-30 14:17:46 +04:00
{
2015-07-19 13:39:00 +03:00
if ( fabsf ( client - > ent - > v . velocity . z ) > 50.0f )
2014-07-30 14:17:46 +04:00
{
2015-07-19 13:39:00 +03:00
hearDistance = 1024.0f ;
2016-03-01 13:37:10 +03:00
timeSound = engine . Time ( ) + 0.3f ;
2014-07-30 14:17:46 +04:00
}
}
else
{
extern ConVar mp_footsteps ;
if ( mp_footsteps . GetBool ( ) )
{
// moves fast enough?
2015-07-19 13:39:00 +03:00
hearDistance = 1280.0f * ( client - > ent - > v . velocity . GetLength2D ( ) / 260.0f ) ;
2016-03-01 13:37:10 +03:00
timeSound = engine . Time ( ) + 0.3f ;
2014-07-30 14:17:46 +04:00
}
}
if ( hearDistance < = 0.0 )
return ; // didn't issue sound?
// some sound already associated
2016-03-01 13:37:10 +03:00
if ( client - > timeSoundLasting > engine . Time ( ) )
2014-07-30 14:17:46 +04:00
{
2015-07-19 13:39:00 +03:00
if ( client - > hearingDistance < = hearDistance )
2014-07-30 14:17:46 +04:00
{
// override it with new
2015-07-19 13:39:00 +03:00
client - > hearingDistance = hearDistance ;
client - > timeSoundLasting = timeSound ;
client - > soundPosition = client - > ent - > v . origin ;
2014-07-30 14:17:46 +04:00
}
}
else
{
// just remember it
2015-07-19 13:39:00 +03:00
client - > hearingDistance = hearDistance ;
client - > timeSoundLasting = timeSound ;
client - > soundPosition = client - > ent - > v . origin ;
2014-07-30 14:17:46 +04:00
}
}
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
2016-01-07 18:49:55 +03:00
}