2016-03-12 14:35:44 +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:
2016-09-11 21:01:06 +03:00
// https://yapb.jeefo.net/license
2014-07-30 14:17:46 +04:00
//
# include <core.h>
// console vars
ConVar yb_password ( " yb_password " , " " , VT_PASSWORD ) ;
2016-01-04 15:28:38 +03:00
ConVar yb_password_key ( " yb_password_key " , " _ybpw " ) ;
2014-07-30 14:17:46 +04:00
ConVar yb_language ( " yb_language " , " en " ) ;
ConVar yb_version ( " yb_version " , PRODUCT_VERSION , VT_READONLY ) ;
2016-09-14 15:40:42 +03:00
ConVar mp_startmoney ( " mp_startmoney " , nullptr , VT_NOREGISTER , true , " 800 " ) ;
2014-07-30 14:17:46 +04:00
2015-06-12 00:28:43 +03:00
int BotCommandHandler ( edict_t * ent , const char * arg0 , const char * arg1 , const char * arg2 , const char * arg3 , const char * arg4 , const char * arg5 , const char * self )
2014-07-30 14:17:46 +04:00
{
// adding one bot with random parameters to random team
2016-09-13 22:40:06 +03:00
if ( A_stricmp ( arg0 , " addbot " ) = = 0 | | A_stricmp ( arg0 , " add " ) = = 0 )
2015-07-24 15:10:51 +03:00
bots . AddBot ( arg4 , arg1 , arg2 , arg3 , arg5 ) ;
2014-07-30 14:17:46 +04:00
2015-06-12 00:28:43 +03:00
// adding one bot with high difficulty parameters to random team
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " addbot_hs " ) = = 0 | | A_stricmp ( arg0 , " addhs " ) = = 0 )
2015-07-24 15:10:51 +03:00
bots . AddBot ( arg4 , " 4 " , " 1 " , arg3 , arg5 ) ;
2014-07-30 14:17:46 +04:00
// adding one bot with random parameters to terrorist team
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " addbot_t " ) = = 0 | | A_stricmp ( arg0 , " add_t " ) = = 0 )
2015-07-24 15:10:51 +03:00
bots . AddBot ( arg4 , arg1 , arg2 , " 1 " , arg5 ) ;
2014-07-30 14:17:46 +04:00
// adding one bot with random parameters to counter-terrorist team
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " addbot_ct " ) = = 0 | | A_stricmp ( arg0 , " add_ct " ) = = 0 )
2015-07-24 15:10:51 +03:00
bots . AddBot ( arg4 , arg1 , arg2 , " 2 " , arg5 ) ;
2014-07-30 14:17:46 +04:00
// kicking off one bot from the terrorist team
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " kickbot_t " ) = = 0 | | A_stricmp ( arg0 , " kick_t " ) = = 0 )
2016-01-30 13:15:50 +03:00
bots . RemoveFromTeam ( TERRORIST ) ;
2014-07-30 14:17:46 +04:00
// kicking off one bot from the counter-terrorist team
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " kickbot_ct " ) = = 0 | | A_stricmp ( arg0 , " kick_ct " ) = = 0 )
2016-01-30 13:15:50 +03:00
bots . RemoveFromTeam ( CT ) ;
2014-07-30 14:17:46 +04:00
// kills all bots on the terrorist team
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " killbots_t " ) = = 0 | | A_stricmp ( arg0 , " kill_t " ) = = 0 )
2016-01-30 13:15:50 +03:00
bots . KillAll ( TERRORIST ) ;
2014-07-30 14:17:46 +04:00
// kills all bots on the counter-terrorist team
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " killbots_ct " ) = = 0 | | A_stricmp ( arg0 , " kill_ct " ) = = 0 )
2016-01-30 13:15:50 +03:00
bots . KillAll ( CT ) ;
2014-07-30 14:17:46 +04:00
// list all bots playeing on the server
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " listbots " ) = = 0 | | A_stricmp ( arg0 , " list " ) = = 0 )
2015-07-24 15:10:51 +03:00
bots . ListBots ( ) ;
2014-07-30 14:17:46 +04:00
// kick off all bots from the played server
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " kickbots " ) = = 0 | | A_stricmp ( arg0 , " kickall " ) = = 0 )
2015-07-24 15:10:51 +03:00
bots . RemoveAll ( ) ;
2014-07-30 14:17:46 +04:00
// kill all bots on the played server
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " killbots " ) = = 0 | | A_stricmp ( arg0 , " killall " ) = = 0 )
2015-07-24 15:10:51 +03:00
bots . KillAll ( ) ;
2014-07-30 14:17:46 +04:00
// kick off one random bot from the played server
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " kickone " ) = = 0 | | A_stricmp ( arg0 , " kick " ) = = 0 )
2015-07-24 15:10:51 +03:00
bots . RemoveRandom ( ) ;
2014-07-30 14:17:46 +04:00
// fill played server with bots
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " fillserver " ) = = 0 | | A_stricmp ( arg0 , " fill " ) = = 0 )
2015-07-24 15:10:51 +03:00
bots . FillServer ( atoi ( arg1 ) , IsNullString ( arg2 ) ? - 1 : atoi ( arg2 ) , IsNullString ( arg3 ) ? - 1 : atoi ( arg3 ) , IsNullString ( arg4 ) ? - 1 : atoi ( arg4 ) ) ;
2014-07-30 14:17:46 +04:00
// select the weapon mode for bots
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " weaponmode " ) = = 0 | | A_stricmp ( arg0 , " wmode " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
int selection = atoi ( arg1 ) ;
// check is selected range valid
if ( selection > = 1 & & selection < = 7 )
2015-07-24 15:10:51 +03:00
bots . SetWeaponMode ( selection ) ;
2014-07-30 14:17:46 +04:00
else
2016-03-01 13:37:10 +03:00
engine . ClientPrintf ( ent , " Choose weapon from 1 to 7 range " ) ;
2014-07-30 14:17:46 +04:00
}
// force all bots to vote to specified map
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " votemap " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
if ( ! IsNullString ( arg1 ) )
{
int nominatedMap = atoi ( arg1 ) ;
// 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
{
2016-03-01 13:37:10 +03:00
Bot * bot = bots . GetBot ( i ) ;
2016-09-11 21:01:06 +03:00
if ( bot ! = nullptr )
2016-03-01 13:37:10 +03:00
bot - > m_voteMap = nominatedMap ;
2014-07-30 14:17:46 +04:00
}
2016-03-01 13:37:10 +03:00
engine . ClientPrintf ( ent , " All dead bots will vote for map #%d " , nominatedMap ) ;
2014-07-30 14:17:46 +04:00
}
}
// displays version information
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " version " ) = = 0 | | A_stricmp ( arg0 , " ver " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
char versionData [ ] =
" ------------------------------------------------ \n "
" Name: %s \n "
" Version: %s (Build: %u) \n "
2015-06-14 12:55:49 +03:00
" Compiled: %s, %s \n "
" Git Hash: %s \n "
" Git Commit Author: %s \n "
2014-07-30 14:17:46 +04:00
" ------------------------------------------------ " ;
2016-03-01 13:37:10 +03:00
engine . ClientPrintf ( ent , versionData , PRODUCT_NAME , PRODUCT_VERSION , GenerateBuildNumber ( ) , __DATE__ , __TIME__ , PRODUCT_GIT_HASH , PRODUCT_GIT_COMMIT_AUTHOR ) ;
2014-07-30 14:17:46 +04:00
}
// display some sort of help information
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " ? " ) = = 0 | | A_stricmp ( arg0 , " help " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-01 13:37:10 +03:00
engine . ClientPrintf ( ent , " Bot Commands: " ) ;
engine . ClientPrintf ( ent , " %s version \t - display version information. " , self ) ;
engine . ClientPrintf ( ent , " %s add \t - create a bot in current game. " , self ) ;
engine . ClientPrintf ( ent , " %s fill \t - fill the server with random bots. " , self ) ;
engine . ClientPrintf ( ent , " %s kickall \t - disconnects all bots from current game. " , self ) ;
engine . ClientPrintf ( ent , " %s killbots \t - kills all bots in current game. " , self ) ;
engine . ClientPrintf ( ent , " %s kick \t - disconnect one random bot from game. " , self ) ;
engine . ClientPrintf ( ent , " %s weaponmode \t - select bot weapon mode. " , self ) ;
engine . ClientPrintf ( ent , " %s votemap \t - allows dead bots to vote for specific map. " , self ) ;
engine . ClientPrintf ( ent , " %s cmenu \t - displaying bots command menu. " , self ) ;
2014-07-30 14:17:46 +04:00
2016-09-13 22:40:06 +03:00
if ( A_stricmp ( arg1 , " full " ) = = 0 | | A_stricmp ( arg1 , " f " ) = = 0 | | A_stricmp ( arg1 , " ? " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-01 13:37:10 +03:00
engine . ClientPrintf ( ent , " %s add_t \t - creates one random bot to terrorist team. " , self ) ;
engine . ClientPrintf ( ent , " %s add_ct \t - creates one random bot to ct team. " , self ) ;
engine . ClientPrintf ( ent , " %s kick_t \t - disconnect one random bot from terrorist team. " , self ) ;
engine . ClientPrintf ( ent , " %s kick_ct \t - disconnect one random bot from ct team. " , self ) ;
engine . ClientPrintf ( ent , " %s kill_t \t - kills all bots on terrorist team. " , self ) ;
engine . ClientPrintf ( ent , " %s kill_ct \t - kills all bots on ct team. " , self ) ;
engine . ClientPrintf ( ent , " %s list \t - display list of bots currently playing. " , self ) ;
engine . ClientPrintf ( ent , " %s order \t - execute specific command on specified bot. " , self ) ;
engine . ClientPrintf ( ent , " %s time \t - displays current time on server. " , self ) ;
engine . ClientPrintf ( ent , " %s deletewp \t - erase waypoint file from hard disk (permanently). " , self ) ;
if ( ! engine . IsDedicatedServer ( ) )
2014-07-30 14:17:46 +04:00
{
2016-03-01 13:37:10 +03:00
engine . Printf ( " %s autowp \t - toggle autowaypointing. " , self ) ;
engine . Printf ( " %s wp \t - toggle waypoint showing. " , self ) ;
engine . Printf ( " %s wp on noclip \t - enable noclip cheat " , self ) ;
engine . Printf ( " %s wp save nocheck \t - save waypoints without checking. " , self ) ;
engine . Printf ( " %s wp add \t - open menu for waypoint creation. " , self ) ;
engine . Printf ( " %s wp menu \t - open main waypoint menu. " , self ) ;
engine . Printf ( " %s wp addbasic \t - creates basic waypoints on map. " , self ) ;
engine . Printf ( " %s wp find \t - show direction to specified waypoint. " , self ) ;
engine . Printf ( " %s wp load \t - load the waypoint file from hard disk. " , self ) ;
engine . Printf ( " %s wp check \t - checks if all waypoints connections are valid. " , self ) ;
engine . Printf ( " %s wp cache \t - cache nearest waypoint. " , self ) ;
engine . Printf ( " %s wp teleport \t - teleport hostile to specified waypoint. " , self ) ;
engine . Printf ( " %s wp setradius \t - manually sets the wayzone radius for this waypoint. " , self ) ;
engine . Printf ( " %s path autodistance - opens menu for setting autopath maximum distance. " , self ) ;
engine . Printf ( " %s path cache \t - remember the nearest to player waypoint. " , self ) ;
engine . Printf ( " %s path create \t - opens menu for path creation. " , self ) ;
engine . Printf ( " %s path delete \t - delete path from cached to nearest waypoint. " , self ) ;
engine . Printf ( " %s path create_in \t - creating incoming path connection. " , self ) ;
engine . Printf ( " %s path create_out \t - creating outgoing path connection. " , self ) ;
engine . Printf ( " %s path create_both \t - creating both-ways path connection. " , self ) ;
engine . Printf ( " %s exp save \t - save the experience data. " , self ) ;
2014-07-30 14:17:46 +04:00
}
}
}
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " bot_takedamage " ) = = 0 & & ! IsNullString ( arg1 ) )
2016-01-03 22:03:02 +03:00
{
bool isOn = ! ! ( atoi ( arg1 ) = = 1 ) ;
2016-03-01 13:37:10 +03:00
for ( int i = 0 ; i < engine . MaxClients ( ) ; i + + )
2016-01-03 22:03:02 +03:00
{
Bot * bot = bots . GetBot ( i ) ;
2016-09-11 21:01:06 +03:00
if ( bot ! = nullptr )
2016-01-03 22:03:02 +03:00
{
bot - > pev - > takedamage = isOn ? 0.0f : 1.0f ;
}
}
}
2014-07-30 14:17:46 +04:00
// displays main bot menu
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " botmenu " ) = = 0 | | A_stricmp ( arg0 , " menu " ) = = 0 )
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_MAIN ) ;
2014-07-30 14:17:46 +04:00
// display command menu
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " cmdmenu " ) = = 0 | | A_stricmp ( arg0 , " cmenu " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
if ( IsAlive ( ent ) )
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_COMMANDS ) ;
2014-07-30 14:17:46 +04:00
else
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2016-03-01 13:37:10 +03:00
engine . CenterPrintf ( " You're dead, and have no access to this menu " ) ;
2014-07-30 14:17:46 +04:00
}
}
// waypoint manimupulation (really obsolete, can be edited through menu) (supported only on listen server)
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " waypoint " ) = = 0 | | A_stricmp ( arg0 , " wp " ) = = 0 | | A_stricmp ( arg0 , " wpt " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-05 23:08:07 +03:00
if ( engine . IsDedicatedServer ( ) | | engine . IsNullEntity ( g_hostEntity ) )
2014-07-30 14:17:46 +04:00
return 2 ;
// enables or disable waypoint displaying
2016-09-13 22:40:06 +03:00
if ( A_stricmp ( arg1 , " on " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
g_waypointOn = true ;
2016-03-01 13:37:10 +03:00
engine . Printf ( " Waypoint Editing Enabled " ) ;
2014-07-30 14:17:46 +04:00
// enables noclip cheat
2016-09-13 22:40:06 +03:00
if ( A_stricmp ( arg2 , " noclip " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
if ( g_editNoclip )
{
g_hostEntity - > v . movetype = MOVETYPE_WALK ;
2016-03-01 13:37:10 +03:00
engine . Printf ( " Noclip Cheat Disabled " ) ;
2014-07-30 14:17:46 +04:00
}
else
{
g_hostEntity - > v . movetype = MOVETYPE_NOCLIP ;
2016-03-01 13:37:10 +03:00
engine . Printf ( " Noclip Cheat Enabled " ) ;
2014-07-30 14:17:46 +04:00
}
2015-06-24 15:38:48 +03:00
g_editNoclip = ! g_editNoclip ; // switch on/off (XOR it!)
2014-07-30 14:17:46 +04:00
}
2016-03-01 13:37:10 +03:00
engine . IssueCmd ( " yapb wp mdl on " ) ;
2014-07-30 14:17:46 +04:00
}
// switching waypoint editing off
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " off " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
g_waypointOn = false ;
g_editNoclip = false ;
g_hostEntity - > v . movetype = MOVETYPE_WALK ;
2016-03-01 13:37:10 +03:00
engine . Printf ( " Waypoint Editing Disabled " ) ;
engine . IssueCmd ( " yapb wp mdl off " ) ;
2014-07-30 14:17:46 +04:00
}
// toggles displaying player models on spawn spots
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " mdl " ) = = 0 | | A_stricmp ( arg1 , " models " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-09-11 21:01:06 +03:00
edict_t * spawnEntity = nullptr ;
2014-07-30 14:17:46 +04:00
2016-09-13 22:40:06 +03:00
if ( A_stricmp ( arg2 , " on " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-05 23:08:07 +03:00
while ( ! engine . IsNullEntity ( spawnEntity = FIND_ENTITY_BY_CLASSNAME ( spawnEntity , " info_player_start " ) ) )
2014-07-30 14:17:46 +04:00
spawnEntity - > v . effects & = ~ EF_NODRAW ;
2016-03-05 23:08:07 +03:00
while ( ! engine . IsNullEntity ( spawnEntity = FIND_ENTITY_BY_CLASSNAME ( spawnEntity , " info_player_deathmatch " ) ) )
2014-07-30 14:17:46 +04:00
spawnEntity - > v . effects & = ~ EF_NODRAW ;
2016-03-05 23:08:07 +03:00
while ( ! engine . IsNullEntity ( spawnEntity = FIND_ENTITY_BY_CLASSNAME ( spawnEntity , " info_vip_start " ) ) )
2014-07-30 14:17:46 +04:00
spawnEntity - > v . effects & = ~ EF_NODRAW ;
2016-03-01 13:37:10 +03:00
engine . IssueCmd ( " mp_roundtime 9 " ) ; // reset round time to maximum
engine . IssueCmd ( " mp_timelimit 0 " ) ; // disable the time limit
engine . IssueCmd ( " mp_freezetime 0 " ) ; // disable freezetime
2014-07-30 14:17:46 +04:00
}
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg2 , " off " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-05 23:08:07 +03:00
while ( ! engine . IsNullEntity ( spawnEntity = FIND_ENTITY_BY_CLASSNAME ( spawnEntity , " info_player_start " ) ) )
2014-07-30 14:17:46 +04:00
spawnEntity - > v . effects | = EF_NODRAW ;
2016-03-05 23:08:07 +03:00
while ( ! engine . IsNullEntity ( spawnEntity = FIND_ENTITY_BY_CLASSNAME ( spawnEntity , " info_player_deathmatch " ) ) )
2014-07-30 14:17:46 +04:00
spawnEntity - > v . effects | = EF_NODRAW ;
2016-03-05 23:08:07 +03:00
while ( ! engine . IsNullEntity ( spawnEntity = FIND_ENTITY_BY_CLASSNAME ( spawnEntity , " info_vip_start " ) ) )
2014-07-30 14:17:46 +04:00
spawnEntity - > v . effects | = EF_NODRAW ;
}
}
// show direction to specified waypoint
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " find " ) = = 0 )
2015-07-24 15:10:51 +03:00
waypoints . SetFindIndex ( atoi ( arg2 ) ) ;
2014-07-30 14:17:46 +04:00
// opens adding waypoint menu
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " add " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
g_waypointOn = true ; // turn waypoints on
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( g_hostEntity , BOT_MENU_WAYPOINT_TYPE ) ;
2014-07-30 14:17:46 +04:00
}
// creates basic waypoints on the map (ladder/spawn points/goals)
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " addbasic " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
waypoints . CreateBasic ( ) ;
2016-03-01 13:37:10 +03:00
engine . CenterPrintf ( " Basic waypoints was Created " ) ;
2014-07-30 14:17:46 +04:00
}
// delete nearest to host edict waypoint
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " delete " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
g_waypointOn = true ; // turn waypoints on
2015-07-24 15:10:51 +03:00
waypoints . Delete ( ) ;
2014-07-30 14:17:46 +04:00
}
// save waypoint data into file on hard disk
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " save " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-12 14:35:44 +03:00
char * waypointSaveMessage = engine . TraslateMessage ( " Waypoints Saved " ) ;
2014-07-30 14:17:46 +04:00
if ( FStrEq ( arg2 , " nocheck " ) )
{
2015-07-24 15:10:51 +03:00
waypoints . Save ( ) ;
2016-03-01 13:37:10 +03:00
engine . Printf ( waypointSaveMessage ) ;
2014-07-30 14:17:46 +04:00
}
2015-07-24 15:10:51 +03:00
else if ( waypoints . NodesValid ( ) )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
waypoints . Save ( ) ;
2016-03-01 13:37:10 +03:00
engine . Printf ( waypointSaveMessage ) ;
2014-07-30 14:17:46 +04:00
}
}
// remove waypoint and all corresponding files from hard disk
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " erase " ) = = 0 )
2015-07-24 15:10:51 +03:00
waypoints . EraseFromHardDisk ( ) ;
2014-07-30 14:17:46 +04:00
// load all waypoints again (overrides all changes, that wasn't saved)
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " load " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
if ( waypoints . Load ( ) )
2016-03-01 13:37:10 +03:00
engine . Printf ( " Waypoints loaded " ) ;
2014-07-30 14:17:46 +04:00
}
// check all nodes for validation
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " check " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
if ( waypoints . NodesValid ( ) )
2016-03-01 13:37:10 +03:00
engine . CenterPrintf ( " Nodes work Fine " ) ;
2014-07-30 14:17:46 +04:00
}
// opens menu for setting (removing) waypoint flags
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " flags " ) = = 0 )
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( g_hostEntity , BOT_MENU_WAYPOINT_FLAG ) ;
2014-07-30 14:17:46 +04:00
// setting waypoint radius
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " setradius " ) = = 0 )
2015-07-24 15:10:51 +03:00
waypoints . SetRadius ( atoi ( arg2 ) ) ;
2014-07-30 14:17:46 +04:00
// remembers nearest waypoint
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " cache " ) = = 0 )
2015-07-24 15:10:51 +03:00
waypoints . CacheWaypoint ( ) ;
2014-07-30 14:17:46 +04:00
// teleport player to specified waypoint
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " teleport " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
int teleportPoint = atoi ( arg2 ) ;
if ( teleportPoint < g_numWaypoints )
{
2015-07-24 15:10:51 +03:00
Path * path = waypoints . GetPath ( teleportPoint ) ;
2014-07-30 14:17:46 +04:00
( * g_engfuncs . pfnSetOrigin ) ( g_hostEntity , path - > origin ) ;
g_waypointOn = true ;
2016-03-01 13:37:10 +03:00
engine . Printf ( " Player '%s' teleported to waypoint #%d (x:%.1f, y:%.1f, z:%.1f) " , STRING ( g_hostEntity - > v . netname ) , teleportPoint , path - > origin . x , path - > origin . y , path - > origin . z ) ; //-V807
2014-07-30 14:17:46 +04:00
g_editNoclip = true ;
}
}
// displays waypoint menu
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " menu " ) = = 0 )
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( g_hostEntity , BOT_MENU_WAYPOINT_MAIN_PAGE1 ) ;
2014-07-30 14:17:46 +04:00
// otherwise display waypoint current status
else
2016-03-01 13:37:10 +03:00
engine . Printf ( " Waypoints are %s " , g_waypointOn = = true ? " Enabled " : " Disabled " ) ;
2014-07-30 14:17:46 +04:00
}
// path waypoint editing system (supported only on listen server)
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " pathwaypoint " ) = = 0 | | A_stricmp ( arg0 , " path " ) = = 0 | | A_stricmp ( arg0 , " pwp " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-05 23:08:07 +03:00
if ( engine . IsDedicatedServer ( ) | | engine . IsNullEntity ( g_hostEntity ) )
2014-07-30 14:17:46 +04:00
return 2 ;
// opens path creation menu
2016-09-13 22:40:06 +03:00
if ( A_stricmp ( arg1 , " create " ) = = 0 )
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( g_hostEntity , BOT_MENU_WAYPOINT_PATH ) ;
2014-07-30 14:17:46 +04:00
// creates incoming path from the cached waypoint
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " create_in " ) = = 0 )
2015-07-24 15:10:51 +03:00
waypoints . CreatePath ( CONNECTION_INCOMING ) ;
2014-07-30 14:17:46 +04:00
// creates outgoing path from current waypoint
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " create_out " ) = = 0 )
2015-07-24 15:10:51 +03:00
waypoints . CreatePath ( CONNECTION_OUTGOING ) ;
2014-07-30 14:17:46 +04:00
// creates bidirectional path from cahed to current waypoint
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " create_both " ) = = 0 )
2015-07-24 15:10:51 +03:00
waypoints . CreatePath ( CONNECTION_BOTHWAYS ) ;
2014-07-30 14:17:46 +04:00
// delete special path
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " delete " ) = = 0 )
2015-07-24 15:10:51 +03:00
waypoints . DeletePath ( ) ;
2014-07-30 14:17:46 +04:00
// sets auto path maximum distance
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " autodistance " ) = = 0 )
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( g_hostEntity , BOT_MENU_WAYPOINT_AUTOPATH ) ;
2014-07-30 14:17:46 +04:00
}
// automatic waypoint handling (supported only on listen server)
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " autowaypoint " ) = = 0 | | A_stricmp ( arg0 , " autowp " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-05 23:08:07 +03:00
if ( engine . IsDedicatedServer ( ) | | engine . IsNullEntity ( g_hostEntity ) )
2014-07-30 14:17:46 +04:00
return 2 ;
// enable autowaypointing
2016-09-13 22:40:06 +03:00
if ( A_stricmp ( arg1 , " on " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
g_autoWaypoint = true ;
g_waypointOn = true ; // turn this on just in case
}
// disable autowaypointing
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg1 , " off " ) = = 0 )
2014-07-30 14:17:46 +04:00
g_autoWaypoint = false ;
// display status
2016-03-01 13:37:10 +03:00
engine . Printf ( " Auto-Waypoint %s " , g_autoWaypoint ? " Enabled " : " Disabled " ) ;
2014-07-30 14:17:46 +04:00
}
// experience system handling (supported only on listen server)
2016-09-13 22:40:06 +03:00
else if ( A_stricmp ( arg0 , " experience " ) = = 0 | | A_stricmp ( arg0 , " exp " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-05 23:08:07 +03:00
if ( engine . IsDedicatedServer ( ) | | engine . IsNullEntity ( g_hostEntity ) )
2014-07-30 14:17:46 +04:00
return 2 ;
// write experience table (and visibility table) to hard disk
2016-09-13 22:40:06 +03:00
if ( A_stricmp ( arg1 , " save " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
waypoints . SaveExperienceTab ( ) ;
waypoints . SaveVisibilityTab ( ) ;
2014-07-30 14:17:46 +04:00
2016-03-01 13:37:10 +03:00
engine . Printf ( " Experience tab saved " ) ;
2014-07-30 14:17:46 +04:00
}
}
else
return 0 ; // command is not handled by bot
return 1 ; // command was handled by bot
}
void ParseVoiceEvent ( const String & base , int type , float timeToRepeat )
{
// this function does common work of parsing single line of voice chatter
Array < String > temp = String ( base ) . Split ( ' , ' ) ;
ChatterItem chatterItem ;
2015-06-28 19:43:31 +03:00
FOR_EACH_AE ( temp , i )
2014-07-30 14:17:46 +04:00
{
temp [ i ] . Trim ( ) . TrimQuotes ( ) ;
2016-09-14 11:51:58 +03:00
float duration = engine . GetWaveLength ( temp [ i ] ) ;
if ( duration < = 0.0f )
2014-07-30 14:17:46 +04:00
continue ;
chatterItem . name = temp [ i ] ;
2016-09-14 11:51:58 +03:00
chatterItem . repeat = timeToRepeat ;
chatterItem . duration = duration ;
2014-07-30 14:17:46 +04:00
g_chatterFactory [ type ] . Push ( chatterItem ) ;
}
temp . RemoveAll ( ) ;
}
2016-03-09 19:17:56 +03:00
// forwards for MemoryFile
2016-09-11 21:01:06 +03:00
MemoryFile : : MF_Loader MemoryFile : : Loader = nullptr ;
MemoryFile : : MF_Unloader MemoryFile : : Unloader = nullptr ;
2016-03-09 19:17:56 +03:00
2014-07-30 14:17:46 +04:00
void InitConfig ( void )
{
2016-03-13 19:20:25 +03:00
if ( ! MemoryFile : : Loader & & ! MemoryFile : : Unloader )
2016-03-09 19:17:56 +03:00
{
MemoryFile : : Loader = reinterpret_cast < MemoryFile : : MF_Loader > ( g_engfuncs . pfnLoadFileForMe ) ;
MemoryFile : : Unloader = reinterpret_cast < MemoryFile : : MF_Unloader > ( g_engfuncs . pfnFreeFile ) ;
}
2016-03-13 19:20:25 +03:00
2016-03-09 19:17:56 +03:00
MemoryFile fp ;
2015-06-15 23:51:13 +03:00
char line [ 512 ] ;
2014-07-30 14:17:46 +04:00
KeywordFactory replyKey ;
// fixes for crashing if configs couldn't be accessed
g_chatFactory . SetSize ( CHAT_TOTAL ) ;
g_chatterFactory . SetSize ( Chatter_Total ) ;
2015-06-18 19:29:40 +03:00
# define SKIP_COMMENTS() if (line[0] == ' / ' || line[0] == '\r' || line[0] == '\n' || line[0] == 0 || line[0] == ' ' || line[0] == '\t' || line[0] == ';') continue
2014-07-30 14:17:46 +04:00
// NAMING SYSTEM INITIALIZATION
if ( OpenConfig ( " names.cfg " , " Name configuration file not found. " , & fp , true ) )
{
2014-08-05 22:26:16 +04:00
g_botNames . RemoveAll ( ) ;
2014-07-30 14:17:46 +04:00
while ( fp . GetBuffer ( line , 255 ) )
{
SKIP_COMMENTS ( ) ;
2015-06-20 13:38:13 +03:00
Array < String > pair = String ( line ) . Split ( " \t \t " ) ;
if ( pair . GetElementNumber ( ) > 1 )
2015-06-29 21:49:52 +03:00
strncpy ( line , pair [ 0 ] . Trim ( ) . GetBuffer ( ) , SIZEOF_CHAR ( line ) ) ;
2015-06-20 13:38:13 +03:00
2016-03-01 22:52:17 +03:00
String : : TrimExternalBuffer ( line ) ;
2015-06-18 19:29:40 +03:00
line [ 32 ] = 0 ;
2014-07-30 14:17:46 +04:00
BotName item ;
memset ( & item , 0 , sizeof ( item ) ) ;
item . name = line ;
2016-09-15 13:26:13 +03:00
item . usedBy = 0 ;
2014-07-30 14:17:46 +04:00
2015-06-20 13:38:13 +03:00
if ( pair . GetElementNumber ( ) > 1 )
item . steamId = pair [ 1 ] . Trim ( ) ;
2014-07-30 14:17:46 +04:00
g_botNames . Push ( item ) ;
}
fp . Close ( ) ;
}
// CHAT SYSTEM CONFIG INITIALIZATION
if ( OpenConfig ( " chat.cfg " , " Chat file not found. " , & fp , true ) )
{
2015-06-04 11:52:48 +03:00
char section [ 80 ] ;
int chatType = - 1 ;
2014-07-30 14:17:46 +04:00
while ( fp . GetBuffer ( line , 255 ) )
{
SKIP_COMMENTS ( ) ;
2016-03-01 22:52:17 +03:00
strncpy ( section , Engine : : ExtractSingleField ( line , 0 , 1 ) , SIZEOF_CHAR ( section ) ) ;
2014-07-30 14:17:46 +04:00
2015-06-04 11:52:48 +03:00
if ( strcmp ( section , " [KILLED] " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
chatType = 0 ;
continue ;
}
2015-06-04 11:52:48 +03:00
else if ( strcmp ( section , " [BOMBPLANT] " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
chatType = 1 ;
continue ;
}
2015-06-04 11:52:48 +03:00
else if ( strcmp ( section , " [DEADCHAT] " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
chatType = 2 ;
continue ;
}
2015-06-04 11:52:48 +03:00
else if ( strcmp ( section , " [REPLIES] " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
chatType = 3 ;
continue ;
}
2015-06-04 11:52:48 +03:00
else if ( strcmp ( section , " [UNKNOWN] " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
chatType = 4 ;
continue ;
}
2015-06-04 11:52:48 +03:00
else if ( strcmp ( section , " [TEAMATTACK] " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
chatType = 5 ;
continue ;
}
2015-06-04 11:52:48 +03:00
else if ( strcmp ( section , " [WELCOME] " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
chatType = 6 ;
continue ;
}
2015-06-04 11:52:48 +03:00
else if ( strcmp ( section , " [TEAMKILL] " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
chatType = 7 ;
continue ;
}
if ( chatType ! = 3 )
line [ 79 ] = 0 ;
2016-03-01 22:52:17 +03:00
String : : TrimExternalBuffer ( line ) ;
2014-07-30 14:17:46 +04:00
switch ( chatType )
{
case 0 :
g_chatFactory [ CHAT_KILLING ] . Push ( line ) ;
break ;
case 1 :
g_chatFactory [ CHAT_BOMBPLANT ] . Push ( line ) ;
break ;
case 2 :
g_chatFactory [ CHAT_DEAD ] . Push ( line ) ;
break ;
case 3 :
2016-09-11 21:01:06 +03:00
if ( strstr ( line , " @KEY " ) ! = nullptr )
2014-07-30 14:17:46 +04:00
{
if ( ! replyKey . keywords . IsEmpty ( ) & & ! replyKey . replies . IsEmpty ( ) )
{
g_replyFactory . Push ( replyKey ) ;
replyKey . replies . RemoveAll ( ) ;
}
replyKey . keywords . RemoveAll ( ) ;
replyKey . keywords = String ( & line [ 4 ] ) . Split ( ' , ' ) ;
2015-06-28 19:43:31 +03:00
FOR_EACH_AE ( replyKey . keywords , i )
2014-07-30 14:17:46 +04:00
replyKey . keywords [ i ] . Trim ( ) . TrimQuotes ( ) ;
}
else if ( ! replyKey . keywords . IsEmpty ( ) )
replyKey . replies . Push ( line ) ;
break ;
case 4 :
g_chatFactory [ CHAT_NOKW ] . Push ( line ) ;
break ;
case 5 :
g_chatFactory [ CHAT_TEAMATTACK ] . Push ( line ) ;
break ;
case 6 :
g_chatFactory [ CHAT_WELCOME ] . Push ( line ) ;
break ;
case 7 :
g_chatFactory [ CHAT_TEAMKILL ] . Push ( line ) ;
break ;
}
}
fp . Close ( ) ;
}
else
{
extern ConVar yb_chat ;
yb_chat . SetInt ( 0 ) ;
}
// GENERAL DATA INITIALIZATION
if ( OpenConfig ( " general.cfg " , " General configuration file not found. Loading defaults " , & fp ) )
{
while ( fp . GetBuffer ( line , 255 ) )
{
SKIP_COMMENTS ( ) ;
Array < String > pair = String ( line ) . Split ( ' = ' ) ;
if ( pair . GetElementNumber ( ) ! = 2 )
continue ;
pair [ 0 ] . Trim ( ) . Trim ( ) ;
pair [ 1 ] . Trim ( ) . Trim ( ) ;
Array < String > splitted = pair [ 1 ] . Split ( ' , ' ) ;
if ( pair [ 0 ] = = " MapStandard " )
{
if ( splitted . GetElementNumber ( ) ! = NUM_WEAPONS )
AddLogEntry ( true , LL_FATAL , " %s entry in general config is not valid. " , pair [ 0 ] . GetBuffer ( ) ) ;
for ( int i = 0 ; i < NUM_WEAPONS ; i + + )
g_weaponSelect [ i ] . teamStandard = splitted [ i ] . ToInt ( ) ;
}
else if ( pair [ 0 ] = = " MapAS " )
{
if ( splitted . GetElementNumber ( ) ! = NUM_WEAPONS )
AddLogEntry ( true , LL_FATAL , " %s entry in general config is not valid. " , pair [ 0 ] . GetBuffer ( ) ) ;
for ( int i = 0 ; i < NUM_WEAPONS ; i + + )
g_weaponSelect [ i ] . teamAS = splitted [ i ] . ToInt ( ) ;
}
else if ( pair [ 0 ] = = " GrenadePercent " )
{
if ( splitted . GetElementNumber ( ) ! = 3 )
AddLogEntry ( true , LL_FATAL , " %s entry in general config is not valid. " , pair [ 0 ] . GetBuffer ( ) ) ;
for ( int i = 0 ; i < 3 ; i + + )
g_grenadeBuyPrecent [ i ] = splitted [ i ] . ToInt ( ) ;
}
else if ( pair [ 0 ] = = " Economics " )
{
if ( splitted . GetElementNumber ( ) ! = 11 )
AddLogEntry ( true , LL_FATAL , " %s entry in general config is not valid. " , pair [ 0 ] . GetBuffer ( ) ) ;
for ( int i = 0 ; i < 11 ; i + + )
g_botBuyEconomyTable [ i ] = splitted [ i ] . ToInt ( ) ;
}
else if ( pair [ 0 ] = = " PersonalityNormal " )
{
if ( splitted . GetElementNumber ( ) ! = NUM_WEAPONS )
AddLogEntry ( true , LL_FATAL , " %s entry in general config is not valid. " , pair [ 0 ] . GetBuffer ( ) ) ;
for ( int i = 0 ; i < NUM_WEAPONS ; i + + )
g_normalWeaponPrefs [ i ] = splitted [ i ] . ToInt ( ) ;
}
else if ( pair [ 0 ] = = " PersonalityRusher " )
{
if ( splitted . GetElementNumber ( ) ! = NUM_WEAPONS )
AddLogEntry ( true , LL_FATAL , " %s entry in general config is not valid. " , pair [ 0 ] . GetBuffer ( ) ) ;
for ( int i = 0 ; i < NUM_WEAPONS ; i + + )
g_rusherWeaponPrefs [ i ] = splitted [ i ] . ToInt ( ) ;
}
else if ( pair [ 0 ] = = " PersonalityCareful " )
{
if ( splitted . GetElementNumber ( ) ! = NUM_WEAPONS )
AddLogEntry ( true , LL_FATAL , " %s entry in general config is not valid. " , pair [ 0 ] . GetBuffer ( ) ) ;
for ( int i = 0 ; i < NUM_WEAPONS ; i + + )
g_carefulWeaponPrefs [ i ] = splitted [ i ] . ToInt ( ) ;
}
}
fp . Close ( ) ;
}
2015-07-01 23:04:36 +03:00
// CHATTER SYSTEM INITIALIZATION
2016-09-14 11:51:58 +03:00
if ( ( g_gameFlags & GAME_SUPPORT_BOT_VOICE ) & & yb_communication_type . GetInt ( ) = = 2 & & OpenConfig ( " chatter.cfg " , " Couldn't open chatter system configuration " , & fp ) )
2014-07-30 14:17:46 +04:00
{
Array < String > array ;
extern ConVar yb_chatter_path ;
while ( fp . GetBuffer ( line , 511 ) )
{
SKIP_COMMENTS ( ) ;
if ( strncmp ( line , " RewritePath " , 11 ) = = 0 )
yb_chatter_path . SetString ( String ( & line [ 12 ] ) . Trim ( ) ) ;
else if ( strncmp ( line , " Event " , 5 ) = = 0 )
{
array = String ( & line [ 6 ] ) . Split ( ' = ' ) ;
if ( array . GetElementNumber ( ) ! = 2 )
2016-09-14 11:51:58 +03:00
AddLogEntry ( true , LL_ERROR , " Error in chatter config file syntax... Please correct all Errors. " ) ;
2014-07-30 14:17:46 +04:00
2015-06-28 19:43:31 +03:00
FOR_EACH_AE ( array , i )
2014-07-30 14:17:46 +04:00
array [ i ] . Trim ( ) . Trim ( ) ; // double trim
// just to be more unique :)
array [ 1 ] . TrimLeft ( ' ( ' ) ;
array [ 1 ] . TrimRight ( ' ; ' ) ;
array [ 1 ] . TrimRight ( ' ) ' ) ;
2015-07-12 17:18:20 +03:00
# define PARSE_CHATTER_ITEM(type, timeToRepeatAgain) { if (strcmp (array[0], #type) == 0) ParseVoiceEvent (array[1], type, timeToRepeatAgain); }
# define PARSE_CHATTER_ITEM_NR(type) PARSE_CHATTER_ITEM(type, 99999.0f)
2014-07-30 14:17:46 +04:00
// radio system
2015-07-12 17:18:20 +03:00
PARSE_CHATTER_ITEM_NR ( Radio_CoverMe ) ;
PARSE_CHATTER_ITEM_NR ( Radio_YouTakePoint ) ;
PARSE_CHATTER_ITEM_NR ( Radio_HoldPosition ) ;
PARSE_CHATTER_ITEM_NR ( Radio_RegroupTeam ) ;
PARSE_CHATTER_ITEM_NR ( Radio_FollowMe ) ;
PARSE_CHATTER_ITEM_NR ( Radio_TakingFire ) ;
PARSE_CHATTER_ITEM_NR ( Radio_GoGoGo ) ;
PARSE_CHATTER_ITEM_NR ( Radio_Fallback ) ;
PARSE_CHATTER_ITEM_NR ( Radio_StickTogether ) ;
PARSE_CHATTER_ITEM_NR ( Radio_GetInPosition ) ;
PARSE_CHATTER_ITEM_NR ( Radio_StormTheFront ) ;
PARSE_CHATTER_ITEM_NR ( Radio_ReportTeam ) ;
PARSE_CHATTER_ITEM_NR ( Radio_Affirmative ) ;
PARSE_CHATTER_ITEM_NR ( Radio_EnemySpotted ) ;
PARSE_CHATTER_ITEM_NR ( Radio_NeedBackup ) ;
PARSE_CHATTER_ITEM_NR ( Radio_SectorClear ) ;
PARSE_CHATTER_ITEM_NR ( Radio_InPosition ) ;
PARSE_CHATTER_ITEM_NR ( Radio_ReportingIn ) ;
PARSE_CHATTER_ITEM_NR ( Radio_ShesGonnaBlow ) ;
PARSE_CHATTER_ITEM_NR ( Radio_Negative ) ;
PARSE_CHATTER_ITEM_NR ( Radio_EnemyDown ) ;
2014-07-30 14:17:46 +04:00
// voice system
2015-07-12 17:18:20 +03:00
PARSE_CHATTER_ITEM ( Chatter_SpotTheBomber , 4.3f ) ;
PARSE_CHATTER_ITEM ( Chatter_VIPSpotted , 5.3f ) ;
PARSE_CHATTER_ITEM ( Chatter_FriendlyFire , 2.1f ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_DiePain ) ;
PARSE_CHATTER_ITEM ( Chatter_GotBlinded , 5.0f ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_GoingToPlantBomb ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_GoingToGuardVIPSafety ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_RescuingHostages ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_GoingToCamp ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_TeamKill ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_ReportingIn ) ;
PARSE_CHATTER_ITEM ( Chatter_GuardDroppedC4 , 3.0f ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_Camp ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_GuardingVipSafety ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_PlantingC4 ) ;
PARSE_CHATTER_ITEM ( Chatter_DefusingC4 , 3.0f ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_InCombat ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_SeeksEnemy ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_Nothing ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_EnemyDown ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_UseHostage ) ;
PARSE_CHATTER_ITEM ( Chatter_FoundC4 , 5.5f ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_WonTheRound ) ;
PARSE_CHATTER_ITEM ( Chatter_ScaredEmotion , 6.1f ) ;
PARSE_CHATTER_ITEM ( Chatter_HeardEnemy , 12.2f ) ;
PARSE_CHATTER_ITEM ( Chatter_SniperWarning , 4.3f ) ;
PARSE_CHATTER_ITEM ( Chatter_SniperKilled , 2.1f ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_QuicklyWonTheRound ) ;
PARSE_CHATTER_ITEM ( Chatter_OneEnemyLeft , 2.5f ) ;
PARSE_CHATTER_ITEM ( Chatter_TwoEnemiesLeft , 2.5f ) ;
PARSE_CHATTER_ITEM ( Chatter_ThreeEnemiesLeft , 2.5f ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_NoEnemiesLeft ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_FoundBombPlace ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_WhereIsTheBomb ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_DefendingBombSite ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_BarelyDefused ) ;
PARSE_CHATTER_ITEM_NR ( Chatter_NiceshotCommander ) ;
PARSE_CHATTER_ITEM ( Chatter_NiceshotPall , 2.0 ) ;
PARSE_CHATTER_ITEM ( Chatter_GoingToGuardHostages , 3.0f ) ;
PARSE_CHATTER_ITEM ( Chatter_GoingToGuardDoppedBomb , 3.0f ) ;
PARSE_CHATTER_ITEM ( Chatter_OnMyWay , 1.5f ) ;
PARSE_CHATTER_ITEM ( Chatter_LeadOnSir , 5.0f ) ;
PARSE_CHATTER_ITEM ( Chatter_Pinned_Down , 5.0f ) ;
PARSE_CHATTER_ITEM ( Chatter_GottaFindTheBomb , 3.0f ) ;
PARSE_CHATTER_ITEM ( Chatter_You_Heard_The_Man , 3.0f ) ;
PARSE_CHATTER_ITEM ( Chatter_Lost_The_Commander , 4.5f ) ;
PARSE_CHATTER_ITEM ( Chatter_NewRound , 3.5f ) ;
PARSE_CHATTER_ITEM ( Chatter_CoverMe , 3.5f ) ;
PARSE_CHATTER_ITEM ( Chatter_BehindSmoke , 3.5f ) ;
PARSE_CHATTER_ITEM ( Chatter_BombSiteSecured , 3.5f ) ;
2015-06-15 23:51:13 +03:00
}
2014-07-30 14:17:46 +04:00
}
fp . Close ( ) ;
}
else
{
yb_communication_type . SetInt ( 1 ) ;
2015-06-25 22:56:42 +03:00
AddLogEntry ( true , LL_DEFAULT , " Chatter Communication disabled. " ) ;
2014-07-30 14:17:46 +04:00
}
// LOCALIZER INITITALIZATION
2016-02-11 21:50:05 +03:00
if ( OpenConfig ( " lang.cfg " , " Specified language not found " , & fp , true ) & & ! ( g_gameFlags & GAME_LEGACY ) )
2014-07-30 14:17:46 +04:00
{
2016-03-01 13:37:10 +03:00
if ( engine . IsDedicatedServer ( ) )
2014-07-30 14:17:46 +04:00
return ; // dedicated server will use only english translation
2015-06-24 15:38:48 +03:00
enum Lang { Lang_Original , Lang_Translate } langState = static_cast < Lang > ( 2 ) ;
2014-07-30 14:17:46 +04:00
char buffer [ 1024 ] ;
2016-03-12 19:56:09 +03:00
TranslatorPair temp = { " " , " " } ;
2014-07-30 14:17:46 +04:00
while ( fp . GetBuffer ( line , 255 ) )
{
if ( strncmp ( line , " [ORIGINAL] " , 10 ) = = 0 )
{
langState = Lang_Original ;
if ( ! IsNullString ( buffer ) )
{
2016-03-01 22:52:17 +03:00
String : : TrimExternalBuffer ( buffer ) ;
2016-09-13 22:40:06 +03:00
temp . translated = A_strdup ( buffer ) ;
2014-07-30 14:17:46 +04:00
buffer [ 0 ] = 0x0 ;
}
if ( ! IsNullString ( temp . translated ) & & ! IsNullString ( temp . original ) )
2016-03-12 14:35:44 +03:00
engine . PushTranslationPair ( temp ) ;
2014-07-30 14:17:46 +04:00
}
else if ( strncmp ( line , " [TRANSLATED] " , 12 ) = = 0 )
{
2016-03-01 22:52:17 +03:00
String : : TrimExternalBuffer ( buffer ) ;
2016-09-13 22:40:06 +03:00
temp . original = A_strdup ( buffer ) ;
2014-07-30 14:17:46 +04:00
buffer [ 0 ] = 0x0 ;
langState = Lang_Translate ;
}
else
{
switch ( langState )
{
case Lang_Original :
strncat ( buffer , line , 1024 - 1 - strlen ( buffer ) ) ;
break ;
case Lang_Translate :
strncat ( buffer , line , 1024 - 1 - strlen ( buffer ) ) ;
break ;
}
}
}
fp . Close ( ) ;
}
2016-02-11 21:50:05 +03:00
else if ( g_gameFlags & GAME_LEGACY )
2014-07-30 14:17:46 +04:00
AddLogEntry ( true , LL_DEFAULT , " Multilingual system disabled, due to your Counter-Strike Version! " ) ;
else if ( strcmp ( yb_language . GetString ( ) , " en " ) ! = 0 )
AddLogEntry ( true , LL_ERROR , " Couldn't load language configuration " ) ;
// set personality weapon pointers here
g_weaponPrefs [ PERSONALITY_NORMAL ] = reinterpret_cast < int * > ( & g_normalWeaponPrefs ) ;
g_weaponPrefs [ PERSONALITY_RUSHER ] = reinterpret_cast < int * > ( & g_rusherWeaponPrefs ) ;
g_weaponPrefs [ PERSONALITY_CAREFUL ] = reinterpret_cast < int * > ( & g_carefulWeaponPrefs ) ;
2015-06-04 11:52:48 +03:00
g_timePerSecondUpdate = 0.0f ;
2014-07-30 14:17:46 +04:00
}
void GameDLLInit ( void )
{
// this function is a one-time call, and appears to be the second function called in the
2014-08-05 22:26:16 +04:00
// DLL after GiveFntprsToDll() has been called. Its purpose is to tell the MOD DLL to
2014-07-30 14:17:46 +04:00
// initialize the game before the engine actually hooks into it with its video frames and
// clients connecting. Note that it is a different step than the *server* initialization.
// This one is called once, and only once, when the game process boots up before the first
// server is enabled. Here is a good place to do our own game session initialization, and
// to register by the engine side the server commands we need to administrate our bots.
2016-09-14 12:51:02 +03:00
auto CommandHandler = [ ] ( void )
{
if ( BotCommandHandler ( g_hostEntity , IsNullString ( CMD_ARGV ( 1 ) ) ? " help " : CMD_ARGV ( 1 ) , CMD_ARGV ( 2 ) , CMD_ARGV ( 3 ) , CMD_ARGV ( 4 ) , CMD_ARGV ( 5 ) , CMD_ARGV ( 6 ) , CMD_ARGV ( 0 ) ) = = 0 )
engine . Printf ( " Unknown command: %s " , CMD_ARGV ( 1 ) ) ;
} ;
2014-07-30 14:17:46 +04:00
// register server command(s)
2016-03-01 13:37:10 +03:00
engine . RegisterCmd ( " yapb " , CommandHandler ) ;
engine . RegisterCmd ( " yb " , CommandHandler ) ;
2014-07-30 14:17:46 +04:00
// execute main config
2016-03-01 13:37:10 +03:00
engine . IssueCmd ( " exec addons/yapb/conf/yapb.cfg " ) ;
2014-07-30 14:17:46 +04:00
2015-07-25 16:51:48 +03:00
// set correct version string
2016-09-11 21:01:06 +03:00
yb_version . SetString ( FormatBuffer ( " %d.%d.%d " , PRODUCT_VERSION_DWORD_INTERNAL , GenerateBuildNumber ( ) ) ) ;
2015-07-25 16:51:48 +03:00
2014-07-30 14:17:46 +04:00
// register fake metamod command handler if we not! under mm
2016-09-10 19:31:38 +03:00
if ( ! ( g_gameFlags & GAME_METAMOD ) )
{
engine . RegisterCmd ( " meta " , [ ] ( void )
{
engine . Printf ( " You're launched standalone version of yapb. Metamod is not installed or not enabled! " ) ;
} ) ;
}
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_functionTable . pfnGameInit ) ( ) ;
}
2015-06-09 15:45:34 +03:00
void Touch ( edict_t * pentTouched , edict_t * pentOther )
{
// this function is called when two entities' bounding boxes enter in collision. For example,
// when a player walks upon a gun, the player entity bounding box collides to the gun entity
// bounding box, and the result is that this function is called. It is used by the game for
// taking the appropriate action when such an event occurs (in our example, the player who
// is walking upon the gun will "pick it up"). Entities that "touch" others are usually
// entities having a velocity, as it is assumed that static entities (entities that don't
// move) will never touch anything. Hence, in our example, the pentTouched will be the gun
// (static entity), whereas the pentOther will be the player (as it is the one moving). When
// the two entities both have velocities, for example two players colliding, this function
// is called twice, once for each entity moving.
2016-03-05 23:08:07 +03:00
if ( ! engine . IsNullEntity ( pentOther ) & & ( pentOther - > v . flags & FL_FAKECLIENT ) )
2015-06-09 22:16:08 +03:00
{
2015-07-24 15:10:51 +03:00
Bot * bot = bots . GetBot ( pentOther ) ;
2015-06-09 15:45:34 +03:00
2016-09-11 21:01:06 +03:00
if ( bot ! = nullptr )
2015-06-10 23:30:48 +03:00
bot - > VerifyBreakable ( pentTouched ) ;
2015-06-09 22:16:08 +03:00
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2015-06-09 15:45:34 +03:00
RETURN_META ( MRES_IGNORED ) ;
( * g_functionTable . pfnTouch ) ( pentTouched , pentOther ) ;
}
2014-07-30 14:17:46 +04:00
int Spawn ( edict_t * ent )
{
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
// world, in other words to 'display') the entity pointed to by ent in the game. The
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
// and any MOD is supposed to implement one for each of its entities.
2016-01-03 23:18:47 +03:00
// for faster access
const char * entityClassname = STRING ( ent - > v . classname ) ;
if ( strcmp ( entityClassname , " worldspawn " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-05 23:08:07 +03:00
engine . Precache ( ent ) ;
2016-03-12 14:35:44 +03:00
engine . PushRegisteredConVarsToEngine ( true ) ;
2014-07-30 14:17:46 +04:00
PRECACHE_SOUND ( ENGINE_STR ( " weapons/xbow_hit1.wav " ) ) ; // waypoint add
PRECACHE_SOUND ( ENGINE_STR ( " weapons/mine_activate.wav " ) ) ; // waypoint delete
PRECACHE_SOUND ( ENGINE_STR ( " common/wpn_hudoff.wav " ) ) ; // path add/delete start
PRECACHE_SOUND ( ENGINE_STR ( " common/wpn_hudon.wav " ) ) ; // path add/delete done
PRECACHE_SOUND ( ENGINE_STR ( " common/wpn_moveselect.wav " ) ) ; // path add/delete cancel
PRECACHE_SOUND ( ENGINE_STR ( " common/wpn_denyselect.wav " ) ) ; // path add/delete error
2016-03-05 21:22:29 +03:00
RoundInit ( ) ;
2016-03-12 14:35:44 +03:00
g_mapType = 0 ; // reset map type as worldspawn is the first entity spawned
2016-02-11 21:50:05 +03:00
// detect official csbots here, as they causing crash in linkent code when active for some reason
2016-09-11 21:01:06 +03:00
if ( ! ( g_gameFlags & GAME_LEGACY ) & & g_engfuncs . pfnCVarGetPointer ( " bot_stop " ) ! = nullptr )
2016-02-11 21:50:05 +03:00
g_gameFlags | = GAME_OFFICIAL_CSBOT ;
2014-07-30 14:17:46 +04:00
}
2016-01-03 23:18:47 +03:00
else if ( strcmp ( entityClassname , " player_weaponstrip " ) = = 0 )
{
2016-02-11 21:50:05 +03:00
if ( ( g_gameFlags & GAME_LEGACY ) & & ( STRING ( ent - > v . target ) ) [ 0 ] = = ' 0 ' )
2016-01-03 23:18:47 +03:00
ent - > v . target = ent - > v . targetname = ALLOC_STRING ( " fake " ) ;
else
{
REMOVE_ENTITY ( ent ) ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-01-03 23:18:47 +03:00
RETURN_META_VALUE ( MRES_SUPERCEDE , 0 ) ;
return 0 ;
}
}
2015-12-26 17:19:20 +03:00
# ifndef XASH_CSDM
2016-01-03 23:18:47 +03:00
else if ( strcmp ( entityClassname , " info_player_start " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
SET_MODEL ( ent , ENGINE_STR ( " models/player/urban/urban.mdl " ) ) ;
ent - > v . rendermode = kRenderTransAlpha ; // set its render mode to transparency
ent - > v . renderamt = 127 ; // set its transparency amount
ent - > v . effects | = EF_NODRAW ;
}
2016-01-03 23:18:47 +03:00
else if ( strcmp ( entityClassname , " info_player_deathmatch " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
SET_MODEL ( ent , ENGINE_STR ( " models/player/terror/terror.mdl " ) ) ;
ent - > v . rendermode = kRenderTransAlpha ; // set its render mode to transparency
ent - > v . renderamt = 127 ; // set its transparency amount
ent - > v . effects | = EF_NODRAW ;
}
2016-01-03 23:18:47 +03:00
else if ( strcmp ( entityClassname , " info_vip_start " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
SET_MODEL ( ent , ENGINE_STR ( " models/player/vip/vip.mdl " ) ) ;
ent - > v . rendermode = kRenderTransAlpha ; // set its render mode to transparency
ent - > v . renderamt = 127 ; // set its transparency amount
ent - > v . effects | = EF_NODRAW ;
}
2015-12-26 17:19:20 +03:00
# endif
2016-01-03 23:18:47 +03:00
else if ( strcmp ( entityClassname , " func_vip_safetyzone " ) = = 0 | | strcmp ( STRING ( ent - > v . classname ) , " info_vip_safetyzone " ) = = 0 )
2014-07-30 14:17:46 +04:00
g_mapType | = MAP_AS ; // assassination map
2016-01-03 23:18:47 +03:00
else if ( strcmp ( entityClassname , " hostage_entity " ) = = 0 )
2014-07-30 14:17:46 +04:00
g_mapType | = MAP_CS ; // rescue map
2016-01-03 23:18:47 +03:00
else if ( strcmp ( entityClassname , " func_bomb_target " ) = = 0 | | strcmp ( STRING ( ent - > v . classname ) , " info_bomb_target " ) = = 0 )
2014-07-30 14:17:46 +04:00
g_mapType | = MAP_DE ; // defusion map
2016-01-03 23:18:47 +03:00
else if ( strcmp ( entityClassname , " func_escapezone " ) = = 0 )
2014-07-30 14:17:46 +04:00
g_mapType | = MAP_ES ;
// next maps doesn't have map-specific entities, so determine it by name
2016-03-01 13:37:10 +03:00
else if ( strncmp ( engine . GetMapName ( ) , " fy_ " , 3 ) = = 0 ) // fun map
2014-07-30 14:17:46 +04:00
g_mapType | = MAP_FY ;
2016-03-01 13:37:10 +03:00
else if ( strncmp ( engine . GetMapName ( ) , " ka_ " , 3 ) = = 0 ) // knife arena map
2014-07-30 14:17:46 +04:00
g_mapType | = MAP_KA ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META_VALUE ( MRES_IGNORED , 0 ) ;
int result = ( * g_functionTable . pfnSpawn ) ( ent ) ; // get result
if ( ent - > v . rendermode = = kRenderTransTexture )
ent - > v . flags & = ~ FL_WORLDBRUSH ; // clear the FL_WORLDBRUSH flag out of transparent ents
return result ;
}
2014-08-01 22:28:45 +04:00
void UpdateClientData ( const struct edict_s * ent , int sendweapons , struct clientdata_s * cd )
2014-07-30 14:17:46 +04:00
{
2014-08-01 22:28:45 +04:00
extern ConVar yb_latency_display ;
2016-09-14 11:51:58 +03:00
if ( ( g_gameFlags & GAME_SUPPORT_SVC_PINGS ) & & yb_latency_display . GetInt ( ) = = 2 )
2015-07-24 15:10:51 +03:00
bots . SendPingDataOffsets ( const_cast < edict_t * > ( ent ) ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2014-08-01 22:28:45 +04:00
( * g_functionTable . pfnUpdateClientData ) ( ent , sendweapons , cd ) ;
2014-07-30 14:17:46 +04:00
}
int ClientConnect ( edict_t * ent , const char * name , const char * addr , char rejectReason [ 128 ] )
{
// this function is called in order to tell the MOD DLL that a client attempts to connect the
// game. The entity pointer of this client is ent, the name under which he connects is
// pointed to by the pszName pointer, and its IP address string is pointed by the pszAddress
// one. Note that this does not mean this client will actually join the game ; he could as
// well be refused connection by the server later, because of latency timeout, unavailable
// game resources, or whatever reason. In which case the reason why the game DLL (read well,
// the game DLL, *NOT* the engine) refuses this player to connect will be printed in the
// rejectReason string in all letters. Understand that a client connecting process is done
// in three steps. First, the client requests a connection from the server. This is engine
// internals. When there are already too many players, the engine will refuse this client to
// connect, and the game DLL won't even notice. Second, if the engine sees no problem, the
// game DLL is asked. This is where we are. Once the game DLL acknowledges the connection,
// the client downloads the resources it needs and synchronizes its local engine with the one
// of the server. And then, the third step, which comes *AFTER* ClientConnect (), is when the
// client officially enters the game, through the ClientPutInServer () function, later below.
// Here we hook this function in order to keep track of the listen server client entity,
// because a listen server client always connects with a "loopback" address string. Also we
// tell the bot manager to check the bot population, in order to always have one free slot on
// the server for incoming clients.
// check if this client is the listen server client
if ( strcmp ( addr , " loopback " ) = = 0 )
g_hostEntity = ent ; // save the edict of the listen server client...
2016-01-12 23:57:02 +03:00
bots . AdjustQuota ( true , ent ) ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-01-14 23:32:38 +03:00
RETURN_META_VALUE ( MRES_IGNORED , 0 ) ;
2016-01-12 23:57:02 +03:00
2016-01-14 23:32:38 +03:00
return ( * g_functionTable . pfnClientConnect ) ( ent , name , addr , rejectReason ) ;
2016-01-12 23:57:02 +03:00
}
2014-07-30 14:17:46 +04:00
void ClientDisconnect ( edict_t * ent )
{
// this function is called whenever a client is VOLUNTARILY disconnected from the server,
// either because the client dropped the connection, or because the server dropped him from
// the game (latency timeout). The effect is the freeing of a client slot on the server. Note
// that clients and bots disconnected because of a level change NOT NECESSARILY call this
// function, because in case of a level change, it's a server shutdown, and not a normal
// disconnection. I find that completely stupid, but that's it. Anyway it's time to update
// the bots and players counts, and in case the client disconnecting is a bot, to back its
// brain(s) up to disk. We also try to notice when a listenserver client disconnects, so as
// to reset his entity pointer for safety. There are still a few server frames to go once a
// listen server client disconnects, and we don't want to send him any sort of message then.
2016-01-12 23:57:02 +03:00
bots . AdjustQuota ( false , ent ) ;
2016-03-05 23:08:07 +03:00
int i = engine . IndexOfEntity ( ent ) - 1 ;
2014-07-30 14:17:46 +04:00
2016-03-10 00:37:33 +03:00
InternalAssert ( i > = 0 & & i < MAX_ENGINE_PLAYERS ) ;
2014-07-30 14:17:46 +04:00
2015-07-24 15:10:51 +03:00
Bot * bot = bots . GetBot ( i ) ;
2014-09-17 20:36:42 +04:00
2014-07-30 14:17:46 +04:00
// check if its a bot
2016-09-11 21:01:06 +03:00
if ( bot ! = nullptr )
2014-07-30 14:17:46 +04:00
{
2014-09-17 20:36:42 +04:00
if ( bot - > pev = = & ent - > v )
{
2016-09-13 19:09:20 +03:00
bot - > EnableChatterIcon ( false ) ;
2015-07-24 15:10:51 +03:00
bots . Free ( i ) ;
2014-09-17 20:36:42 +04:00
}
2014-07-30 14:17:46 +04:00
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_functionTable . pfnClientDisconnect ) ( ent ) ;
}
void ClientUserInfoChanged ( edict_t * ent , char * infobuffer )
{
// this function is called when a player changes model, or changes team. Occasionally it
// enforces rules on these changes (for example, some MODs don't want to allow players to
// change their player model). But most commonly, this function is in charge of handling
// team changes, recounting the teams population, etc...
2016-03-01 13:37:10 +03:00
if ( engine . IsDedicatedServer ( ) & & ! IsValidBot ( ent ) )
2014-07-30 14:17:46 +04:00
{
2016-01-05 20:29:34 +03:00
const char * passwordField = yb_password_key . GetString ( ) ;
const char * password = yb_password . GetString ( ) ;
2014-07-30 14:17:46 +04:00
2016-01-05 20:29:34 +03:00
if ( ! IsNullString ( passwordField ) | | ! IsNullString ( password ) )
{
2016-03-05 23:08:07 +03:00
int clientIndex = engine . IndexOfEntity ( ent ) - 1 ;
2014-07-30 14:17:46 +04:00
2016-01-05 20:29:34 +03:00
if ( strcmp ( password , INFOKEY_VALUE ( infobuffer , const_cast < char * > ( passwordField ) ) ) = = 0 )
g_clients [ clientIndex ] . flags | = CF_ADMIN ;
else
g_clients [ clientIndex ] . flags & = ~ CF_ADMIN ;
}
}
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_functionTable . pfnClientUserInfoChanged ) ( ent , infobuffer ) ;
}
void ClientCommand ( edict_t * ent )
{
// this function is called whenever the client whose player entity is ent issues a client
// command. How it works is that clients all have a global string in their client DLL that
// stores the command string; if ever that string is filled with characters, the client DLL
// sends it to the engine as a command to be executed. When the engine has executed that
// command, that string is reset to zero. By the server side, we can access this string
// by asking the engine with the CmdArgv(), CmdArgs() and CmdArgc() functions that work just
// like executable files argument processing work in C (argc gets the number of arguments,
// command included, args returns the whole string, and argv returns the wanted argument
// only). Here is a good place to set up either bot debug commands the listen server client
// could type in his game console, or real new client commands, but we wouldn't want to do
// so as this is just a bot DLL, not a MOD. The purpose is not to add functionality to
// clients. Hence it can lack of commenting a bit, since this code is very subject to change.
const char * command = CMD_ARGV ( 0 ) ;
const char * arg1 = CMD_ARGV ( 1 ) ;
static int fillServerTeam = 5 ;
static bool fillCommand = false ;
2016-09-10 19:31:38 +03:00
int issuerPlayerIndex = engine . IndexOfEntity ( ent ) - 1 ;
if ( ! engine . IsBotCommand ( ) & & ( ent = = g_hostEntity | | ( g_clients [ issuerPlayerIndex ] . flags & CF_ADMIN ) ) )
2014-07-30 14:17:46 +04:00
{
2016-09-13 22:40:06 +03:00
if ( A_stricmp ( command , " yapb " ) = = 0 | | A_stricmp ( command , " yb " ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2015-06-20 14:14:36 +03:00
int state = BotCommandHandler ( ent , IsNullString ( arg1 ) ? " help " : arg1 , CMD_ARGV ( 2 ) , CMD_ARGV ( 3 ) , CMD_ARGV ( 4 ) , CMD_ARGV ( 5 ) , CMD_ARGV ( 6 ) , CMD_ARGV ( 0 ) ) ;
2014-07-30 14:17:46 +04:00
switch ( state )
{
case 0 :
2016-03-01 13:37:10 +03:00
engine . ClientPrintf ( ent , " Unknown command: %s " , arg1 ) ;
2014-07-30 14:17:46 +04:00
break ;
case 2 :
2016-03-01 13:37:10 +03:00
engine . ClientPrintf ( ent , " Command %s, can only be executed from server console. " , arg1 ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-16 16:10:22 +03:00
else if ( A_stricmp ( command , " menuselect " ) = = 0 & & ! IsNullString ( arg1 ) & & g_clients [ issuerPlayerIndex ] . menu ! = BOT_MENU_INVALID )
2014-07-30 14:17:46 +04:00
{
2016-09-10 19:31:38 +03:00
Client * client = & g_clients [ issuerPlayerIndex ] ;
2014-07-30 14:17:46 +04:00
int selection = atoi ( arg1 ) ;
2016-09-13 19:09:20 +03:00
if ( client - > menu = = BOT_MENU_WAYPOINT_TYPE )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
2015-07-24 15:10:51 +03:00
waypoints . Add ( selection - 1 ) ;
2014-07-30 14:17:46 +04:00
break ;
case 8 :
2015-07-24 15:10:51 +03:00
waypoints . Add ( 100 ) ;
2014-07-30 14:17:46 +04:00
break ;
case 9 :
2015-07-24 15:10:51 +03:00
waypoints . SetLearnJumpWaypoint ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_WAYPOINT_FLAG )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
2015-07-24 15:10:51 +03:00
waypoints . ToggleFlags ( FLAG_NOHOSTAGE ) ;
2014-07-30 14:17:46 +04:00
break ;
case 2 :
2015-07-24 15:10:51 +03:00
waypoints . ToggleFlags ( FLAG_TF_ONLY ) ;
2014-07-30 14:17:46 +04:00
break ;
case 3 :
2015-07-24 15:10:51 +03:00
waypoints . ToggleFlags ( FLAG_CF_ONLY ) ;
2014-07-30 14:17:46 +04:00
break ;
case 4 :
2015-07-24 15:10:51 +03:00
waypoints . ToggleFlags ( FLAG_LIFT ) ;
2014-07-30 14:17:46 +04:00
break ;
case 5 :
2015-07-24 15:10:51 +03:00
waypoints . ToggleFlags ( FLAG_SNIPER ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_WAYPOINT_MAIN_PAGE1 )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
if ( g_waypointOn )
2016-03-01 13:37:10 +03:00
engine . IssueCmd ( " yapb waypoint off " ) ;
2014-07-30 14:17:46 +04:00
else
2016-03-01 13:37:10 +03:00
engine . IssueCmd ( " yapb waypoint on " ) ;
2014-07-30 14:17:46 +04:00
break ;
case 2 :
g_waypointOn = true ;
2015-07-24 15:10:51 +03:00
waypoints . CacheWaypoint ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 3 :
g_waypointOn = true ;
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_WAYPOINT_PATH ) ;
2014-07-30 14:17:46 +04:00
break ;
case 4 :
g_waypointOn = true ;
2015-07-24 15:10:51 +03:00
waypoints . DeletePath ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 5 :
g_waypointOn = true ;
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_WAYPOINT_TYPE ) ;
2014-07-30 14:17:46 +04:00
break ;
case 6 :
g_waypointOn = true ;
2015-07-24 15:10:51 +03:00
waypoints . Delete ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 7 :
g_waypointOn = true ;
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_WAYPOINT_AUTOPATH ) ;
2014-07-30 14:17:46 +04:00
break ;
case 8 :
g_waypointOn = true ;
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_WAYPOINT_RADIUS ) ;
2014-07-30 14:17:46 +04:00
break ;
case 9 :
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_WAYPOINT_MAIN_PAGE2 ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_WAYPOINT_MAIN_PAGE2 )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
{
int terrPoints = 0 ;
int ctPoints = 0 ;
int goalPoints = 0 ;
int rescuePoints = 0 ;
int campPoints = 0 ;
int sniperPoints = 0 ;
int noHostagePoints = 0 ;
for ( int i = 0 ; i < g_numWaypoints ; i + + )
{
2015-07-24 15:10:51 +03:00
Path * path = waypoints . GetPath ( i ) ;
2014-07-30 14:17:46 +04:00
if ( path - > flags & FLAG_TF_ONLY )
terrPoints + + ;
if ( path - > flags & FLAG_CF_ONLY )
ctPoints + + ;
if ( path - > flags & FLAG_GOAL )
goalPoints + + ;
if ( path - > flags & FLAG_RESCUE )
rescuePoints + + ;
if ( path - > flags & FLAG_CAMP )
campPoints + + ;
if ( path - > flags & FLAG_SNIPER )
sniperPoints + + ;
if ( path - > flags & FLAG_NOHOSTAGE )
noHostagePoints + + ;
}
2016-03-01 13:37:10 +03:00
engine . Printf ( " Waypoints: %d - T Points: %d \n "
2014-07-30 14:17:46 +04:00
" CT Points: %d - Goal Points: %d \n "
" Rescue Points: %d - Camp Points: %d \n "
" Block Hostage Points: %d - Sniper Points: %d \n " , g_numWaypoints , terrPoints , ctPoints , goalPoints , rescuePoints , campPoints , noHostagePoints , sniperPoints ) ;
}
break ;
case 2 :
g_waypointOn = true ;
g_autoWaypoint & = 1 ;
g_autoWaypoint ^ = 1 ;
2016-03-01 13:37:10 +03:00
engine . CenterPrintf ( " Auto-Waypoint %s " , g_autoWaypoint ? " Enabled " : " Disabled " ) ;
2014-07-30 14:17:46 +04:00
break ;
case 3 :
g_waypointOn = true ;
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_WAYPOINT_FLAG ) ;
2014-07-30 14:17:46 +04:00
break ;
case 4 :
2015-07-24 15:10:51 +03:00
if ( waypoints . NodesValid ( ) )
waypoints . Save ( ) ;
2014-07-30 14:17:46 +04:00
else
2016-03-01 13:37:10 +03:00
engine . CenterPrintf ( " Waypoint not saved \n There are errors, see console " ) ;
2014-07-30 14:17:46 +04:00
break ;
case 5 :
2015-07-24 15:10:51 +03:00
waypoints . Save ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 6 :
2015-07-24 15:10:51 +03:00
waypoints . Load ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 7 :
2015-07-24 15:10:51 +03:00
if ( waypoints . NodesValid ( ) )
2016-03-01 13:37:10 +03:00
engine . CenterPrintf ( " Nodes works fine " ) ;
2014-07-30 14:17:46 +04:00
else
2016-03-01 13:37:10 +03:00
engine . CenterPrintf ( " There are errors, see console " ) ;
2014-07-30 14:17:46 +04:00
break ;
case 8 :
2016-03-01 13:37:10 +03:00
engine . IssueCmd ( " yapb wp on noclip " ) ;
2014-07-30 14:17:46 +04:00
break ;
case 9 :
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_WAYPOINT_MAIN_PAGE1 ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_WAYPOINT_RADIUS )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
g_waypointOn = true ; // turn waypoints on in case
const int radiusValue [ ] = { 0 , 8 , 16 , 32 , 48 , 64 , 80 , 96 , 128 } ;
if ( ( selection > = 1 ) & & ( selection < = 9 ) )
2015-07-24 15:10:51 +03:00
waypoints . SetRadius ( radiusValue [ selection - 1 ] ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_MAIN )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
fillCommand = false ;
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_CONTROL ) ;
2014-07-30 14:17:46 +04:00
break ;
case 2 :
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_FEATURES ) ;
2014-07-30 14:17:46 +04:00
break ;
case 3 :
fillCommand = true ;
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_TEAM_SELECT ) ;
2014-07-30 14:17:46 +04:00
break ;
case 4 :
2015-07-24 15:10:51 +03:00
bots . KillAll ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_CONTROL )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
2015-07-24 15:10:51 +03:00
bots . AddRandom ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 2 :
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_DIFFICULTY ) ;
2014-07-30 14:17:46 +04:00
break ;
case 3 :
2015-07-24 15:10:51 +03:00
bots . RemoveRandom ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 4 :
2015-07-24 15:10:51 +03:00
bots . RemoveAll ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 5 :
2015-07-24 15:10:51 +03:00
bots . RemoveMenu ( ent , 1 ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_FEATURES )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_WEAPON_MODE ) ;
2014-07-30 14:17:46 +04:00
break ;
case 2 :
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_WAYPOINT_MAIN_PAGE1 ) ;
2014-07-30 14:17:46 +04:00
break ;
case 3 :
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_PERSONALITY ) ;
2014-07-30 14:17:46 +04:00
break ;
case 4 :
extern ConVar yb_debug ;
yb_debug . SetInt ( yb_debug . GetInt ( ) ^ 1 ) ;
break ;
case 5 :
if ( IsAlive ( ent ) )
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_COMMANDS ) ;
2014-07-30 14:17:46 +04:00
else
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2016-03-01 13:37:10 +03:00
engine . CenterPrintf ( " You're dead, and have no access to this menu " ) ;
2014-07-30 14:17:46 +04:00
}
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_COMMANDS )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2016-09-11 21:01:06 +03:00
Bot * bot = nullptr ;
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
2015-06-28 19:43:31 +03:00
if ( FindNearestPlayer ( reinterpret_cast < void * * > ( & bot ) , client - > ent , 300.0f , true , true , true ) )
2014-07-30 14:17:46 +04:00
{
2015-06-24 15:38:48 +03:00
if ( ! bot - > m_hasC4 & & ! bot - > HasHostage ( ) )
2014-07-30 14:17:46 +04:00
{
if ( selection = = 1 )
{
bot - > ResetDoubleJumpState ( ) ;
bot - > m_doubleJumpOrigin = client - > ent - > v . origin ;
bot - > m_doubleJumpEntity = client - > ent ;
2016-03-01 13:37:10 +03:00
bot - > PushTask ( TASK_DOUBLEJUMP , TASKPRI_DOUBLEJUMP , - 1 , engine . Time ( ) , true ) ;
2014-07-30 14:17:46 +04:00
bot - > TeamSayText ( FormatBuffer ( " Ok %s, i will help you! " , STRING ( ent - > v . netname ) ) ) ;
}
else if ( selection = = 2 )
bot - > ResetDoubleJumpState ( ) ;
2016-09-13 19:09:20 +03:00
2014-07-30 14:17:46 +04:00
break ;
}
}
break ;
case 3 :
case 4 :
2015-06-28 19:43:31 +03:00
if ( FindNearestPlayer ( reinterpret_cast < void * * > ( & bot ) , ent , 300.0f , true , true , true ) )
2014-07-30 14:17:46 +04:00
bot - > DiscardWeaponForUser ( ent , selection = = 4 ? false : true ) ;
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_WAYPOINT_AUTOPATH )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
2016-09-11 21:01:06 +03:00
const float autoDistanceValue [ ] = { 0.0f , 100.0f , 130.0f , 160.0f , 190.0f , 220.0f , 250.0f } ;
2014-07-30 14:17:46 +04:00
if ( selection > = 1 & & selection < = 7 )
g_autoPathDistance = autoDistanceValue [ selection - 1 ] ;
2016-09-11 21:01:06 +03:00
if ( g_autoPathDistance = = 0.0f )
2016-03-01 13:37:10 +03:00
engine . CenterPrintf ( " AutoPath disabled " ) ;
2014-07-30 14:17:46 +04:00
else
2016-09-11 21:01:06 +03:00
engine . CenterPrintf ( " AutoPath maximum distance set to %.2f " , g_autoPathDistance ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_WAYPOINT_PATH )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
2015-07-24 15:10:51 +03:00
waypoints . CreatePath ( CONNECTION_OUTGOING ) ;
2014-07-30 14:17:46 +04:00
break ;
case 2 :
2015-07-24 15:10:51 +03:00
waypoints . CreatePath ( CONNECTION_INCOMING ) ;
2014-07-30 14:17:46 +04:00
break ;
case 3 :
2015-07-24 15:10:51 +03:00
waypoints . CreatePath ( CONNECTION_BOTHWAYS ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_DIFFICULTY )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
2016-09-13 19:09:20 +03:00
client - > menu = BOT_MENU_PERSONALITY ;
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
2015-06-04 11:52:48 +03:00
g_storeAddbotVars [ 0 ] = 0 ;
2014-07-30 14:17:46 +04:00
break ;
case 2 :
2015-06-04 11:52:48 +03:00
g_storeAddbotVars [ 0 ] = 1 ;
2014-07-30 14:17:46 +04:00
break ;
case 3 :
2015-06-04 11:52:48 +03:00
g_storeAddbotVars [ 0 ] = 2 ;
2014-07-30 14:17:46 +04:00
break ;
case 4 :
2015-06-04 11:52:48 +03:00
g_storeAddbotVars [ 0 ] = 3 ;
2014-07-30 14:17:46 +04:00
break ;
case 5 :
2015-06-04 11:52:48 +03:00
g_storeAddbotVars [ 0 ] = 4 ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-13 19:09:20 +03:00
if ( client - > menu = = BOT_MENU_PERSONALITY )
DisplayMenuToClient ( ent , BOT_MENU_PERSONALITY ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_TEAM_SELECT & & fillCommand )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
// turn off cvars if specified team
CVAR_SET_STRING ( " mp_limitteams " , " 0 " ) ;
CVAR_SET_STRING ( " mp_autoteambalance " , " 0 " ) ;
case 5 :
fillServerTeam = selection ;
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_DIFFICULTY ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_PERSONALITY & & fillCommand )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 3 :
case 4 :
2015-07-24 15:10:51 +03:00
bots . FillServer ( fillServerTeam , selection - 2 , g_storeAddbotVars [ 0 ] ) ;
2014-07-30 14:17:46 +04:00
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_TEAM_SELECT )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 5 :
g_storeAddbotVars [ 1 ] = selection ;
if ( selection = = 5 )
{
g_storeAddbotVars [ 2 ] = 5 ;
2015-07-24 15:10:51 +03:00
bots . AddBot ( " " , g_storeAddbotVars [ 0 ] , g_storeAddbotVars [ 3 ] , g_storeAddbotVars [ 1 ] , g_storeAddbotVars [ 2 ] ) ;
2014-07-30 14:17:46 +04:00
}
else
{
if ( selection = = 1 )
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_TERRORIST_SELECT ) ;
2014-07-30 14:17:46 +04:00
else
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_CT_SELECT ) ;
2014-07-30 14:17:46 +04:00
}
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_PERSONALITY )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 3 :
case 4 :
g_storeAddbotVars [ 3 ] = selection - 2 ;
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_TEAM_SELECT ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_TERRORIST_SELECT | | client - > menu = = BOT_MENU_CT_SELECT )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
g_storeAddbotVars [ 2 ] = selection ;
2015-07-24 15:10:51 +03:00
bots . AddBot ( " " , g_storeAddbotVars [ 0 ] , g_storeAddbotVars [ 3 ] , g_storeAddbotVars [ 1 ] , g_storeAddbotVars [ 2 ] ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_WEAPON_MODE )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
2015-07-24 15:10:51 +03:00
bots . SetWeaponMode ( selection ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_KICK_PAGE_1 )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
2015-07-24 15:10:51 +03:00
bots . GetBot ( selection - 1 ) - > Kick ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 9 :
2015-07-24 15:10:51 +03:00
bots . RemoveMenu ( ent , 2 ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2016-09-13 19:09:20 +03:00
DisplayMenuToClient ( ent , BOT_MENU_CONTROL ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_KICK_PAGE_2 )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
2015-07-24 15:10:51 +03:00
bots . GetBot ( selection + 8 - 1 ) - > Kick ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 9 :
2015-07-24 15:10:51 +03:00
bots . RemoveMenu ( ent , 3 ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2015-07-24 15:10:51 +03:00
bots . RemoveMenu ( ent , 1 ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_KICK_PAGE_3 )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
2015-07-24 15:10:51 +03:00
bots . GetBot ( selection + 16 - 1 ) - > Kick ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 9 :
2015-07-24 15:10:51 +03:00
bots . RemoveMenu ( ent , 4 ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2015-07-24 15:10:51 +03:00
bots . RemoveMenu ( ent , 2 ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-13 19:09:20 +03:00
else if ( client - > menu = = BOT_MENU_KICK_PAGE_4 )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
DisplayMenuToClient ( ent , BOT_MENU_INVALID ) ; // reset menu display
2014-07-30 14:17:46 +04:00
switch ( selection )
{
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
2015-07-24 15:10:51 +03:00
bots . GetBot ( selection + 24 - 1 ) - > Kick ( ) ;
2014-07-30 14:17:46 +04:00
break ;
case 10 :
2015-07-24 15:10:51 +03:00
bots . RemoveMenu ( ent , 3 ) ;
2014-07-30 14:17:46 +04:00
break ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
}
}
2016-09-13 22:40:06 +03:00
if ( ! engine . IsBotCommand ( ) & & ( A_stricmp ( command , " say " ) = = 0 | | A_stricmp ( command , " say_team " ) = = 0 ) )
2014-07-30 14:17:46 +04:00
{
2016-09-11 21:01:06 +03:00
Bot * bot = nullptr ;
2014-07-30 14:17:46 +04:00
if ( FStrEq ( arg1 , " dropme " ) | | FStrEq ( arg1 , " dropc4 " ) )
{
2015-06-28 19:43:31 +03:00
if ( FindNearestPlayer ( reinterpret_cast < void * * > ( & bot ) , ent , 300.0f , true , true , true ) )
2014-07-30 14:17:46 +04:00
bot - > DiscardWeaponForUser ( ent , IsNullString ( strstr ( arg1 , " c4 " ) ) ? false : true ) ;
return ;
}
bool isAlive = IsAlive ( ent ) ;
int team = - 1 ;
if ( FStrEq ( command , " say_team " ) )
2016-03-05 23:08:07 +03:00
team = engine . GetTeam ( ent ) ;
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
{
2016-09-10 19:31:38 +03:00
const Client & client = g_clients [ i ] ;
if ( ! ( client . flags & CF_USED ) | | ( team ! = - 1 & & team ! = client . team ) | | isAlive ! = IsAlive ( client . ent ) )
2014-07-30 14:17:46 +04:00
continue ;
2015-07-24 15:10:51 +03:00
Bot * target = bots . GetBot ( i ) ;
2014-07-30 14:17:46 +04:00
2016-09-11 21:01:06 +03:00
if ( target ! = nullptr )
2014-07-30 14:17:46 +04:00
{
2016-03-05 23:08:07 +03:00
target - > m_sayTextBuffer . entityIndex = engine . IndexOfEntity ( ent ) ;
2014-07-30 14:17:46 +04:00
if ( IsNullString ( CMD_ARGS ( ) ) )
continue ;
2015-06-29 21:49:52 +03:00
strncpy ( target - > m_sayTextBuffer . sayText , CMD_ARGS ( ) , SIZEOF_CHAR ( target - > m_sayTextBuffer . sayText ) ) ;
2016-03-01 13:37:10 +03:00
target - > m_sayTextBuffer . timeNextChat = engine . Time ( ) + target - > m_sayTextBuffer . chatDelay ;
2014-07-30 14:17:46 +04:00
}
}
}
2016-09-10 19:31:38 +03:00
2016-03-05 23:08:07 +03:00
int clientIndex = engine . IndexOfEntity ( ent ) - 1 ;
2016-09-10 19:31:38 +03:00
const Client & radioTarget = g_clients [ clientIndex ] ;
2014-07-30 14:17:46 +04:00
// check if this player alive, and issue something
2016-09-10 19:31:38 +03:00
if ( ( radioTarget . flags & CF_ALIVE ) & & g_radioSelect [ clientIndex ] ! = 0 & & strncmp ( command , " menuselect " , 10 ) = = 0 )
2014-07-30 14:17:46 +04:00
{
int radioCommand = atoi ( arg1 ) ;
if ( radioCommand ! = 0 )
{
radioCommand + = 10 * ( g_radioSelect [ clientIndex ] - 1 ) ;
if ( radioCommand ! = Radio_Affirmative & & radioCommand ! = Radio_Negative & & radioCommand ! = Radio_ReportingIn )
{
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
Bot * bot = bots . GetBot ( i ) ;
2014-07-30 14:17:46 +04:00
// validate bot
2016-09-11 21:01:06 +03:00
if ( bot ! = nullptr & & bot - > m_team = = radioTarget . team & & ent ! = bot - > GetEntity ( ) & & bot - > m_radioOrder = = 0 )
2014-07-30 14:17:46 +04:00
{
bot - > m_radioOrder = radioCommand ;
bot - > m_radioEntity = ent ;
}
}
}
2016-09-10 19:31:38 +03:00
g_lastRadioTime [ radioTarget . team ] = engine . Time ( ) ;
2014-07-30 14:17:46 +04:00
}
g_radioSelect [ clientIndex ] = 0 ;
}
else if ( strncmp ( command , " radio " , 5 ) = = 0 )
g_radioSelect [ clientIndex ] = atoi ( & command [ 5 ] ) ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_functionTable . pfnClientCommand ) ( ent ) ;
}
void ServerActivate ( edict_t * pentEdictList , int edictCount , int clientMax )
{
// this function is called when the server has fully loaded and is about to manifest itself
// on the network as such. Since a mapchange is actually a server shutdown followed by a
// restart, this function is also called when a new map is being loaded. Hence it's the
// perfect place for doing initialization stuff for our bots, such as reading the BSP data,
// loading the bot profiles, and drawing the world map (ie, filling the navigation hashtable).
// Once this function has been called, the server can be considered as "running".
FreeLibraryMemory ( ) ;
InitConfig ( ) ; // initialize all config files
// do level initialization stuff here...
2015-07-24 15:10:51 +03:00
waypoints . Init ( ) ;
waypoints . Load ( ) ;
2014-07-30 14:17:46 +04:00
2015-07-26 21:47:29 +03:00
// create global killer entity
bots . CreateKillerEntity ( ) ;
2014-07-30 14:17:46 +04:00
// execute main config
2016-03-01 13:37:10 +03:00
engine . IssueCmd ( " exec addons/yapb/conf/yapb.cfg " ) ;
2014-07-30 14:17:46 +04:00
2016-03-01 13:37:10 +03:00
if ( File : : Accessible ( FormatBuffer ( " %s/maps/%s_yapb.cfg " , engine . GetModName ( ) , engine . GetMapName ( ) ) ) )
2014-07-30 14:17:46 +04:00
{
2016-03-01 13:37:10 +03:00
engine . IssueCmd ( " exec maps/%s_yapb.cfg " , engine . GetMapName ( ) ) ;
engine . Printf ( " Executing Map-Specific config file " ) ;
2014-07-30 14:17:46 +04:00
}
2015-07-24 15:10:51 +03:00
bots . InitQuota ( ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_functionTable . pfnServerActivate ) ( pentEdictList , edictCount , clientMax ) ;
2015-07-24 15:10:51 +03:00
waypoints . InitializeVisibility ( ) ;
2014-07-30 14:17:46 +04:00
}
void ServerDeactivate ( void )
{
// this function is called when the server is shutting down. A particular note about map
// changes: changing the map means shutting down the server and starting a new one. Of course
// this process is transparent to the user, but either in single player when the hero reaches
// a new level and in multiplayer when it's time for a map change, be aware that what happens
// is that the server actually shuts down and restarts with a new map. Hence we can use this
// function to free and deinit anything which is map-specific, for example we free the memory
// space we m'allocated for our BSP data, since a new map means new BSP data to interpret. In
// any case, when the new map will be booting, ServerActivate() will be called, so we'll do
// the loading of new bots and the new BSP data parsing there.
// save collected experience on shutdown
2015-07-24 15:10:51 +03:00
waypoints . SaveExperienceTab ( ) ;
waypoints . SaveVisibilityTab ( ) ;
2014-07-30 14:17:46 +04:00
2015-07-26 21:47:29 +03:00
// destroy global killer entity
bots . DestroyKillerEntity ( ) ;
2014-07-30 14:17:46 +04:00
FreeLibraryMemory ( ) ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_functionTable . pfnServerDeactivate ) ( ) ;
}
void StartFrame ( void )
{
// this function starts a video frame. It is called once per video frame by the engine. If
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
// placing a hook on it, we have a good place to do things that should be done continuously
// during the game, for example making the bots think (yes, because no Think() function exists
// for the bots by the MOD side, remember). Also here we have control on the bot population,
// for example if a new player joins the server, we should disconnect a bot, and if the
// player population decreases, we should fill the server with other bots.
2015-07-12 17:18:20 +03:00
// run periodic update of bot states
2015-07-24 15:10:51 +03:00
bots . PeriodicThink ( ) ;
2015-07-12 17:18:20 +03:00
2014-07-30 14:17:46 +04:00
// record some stats of all players on the server
2016-03-01 13:37:10 +03:00
for ( int i = 0 ; i < engine . MaxClients ( ) ; i + + )
2014-07-30 14:17:46 +04:00
{
2016-03-05 23:08:07 +03:00
edict_t * player = engine . EntityOfIndex ( i + 1 ) ;
2016-09-10 19:31:38 +03:00
Client & storeClient = g_clients [ i ] ;
2014-07-30 14:17:46 +04:00
2016-03-05 23:08:07 +03:00
if ( ! engine . IsNullEntity ( player ) & & ( player - > v . flags & FL_CLIENT ) )
2014-07-30 14:17:46 +04:00
{
2016-09-10 19:31:38 +03:00
storeClient . ent = player ;
storeClient . flags | = CF_USED ;
2014-07-30 14:17:46 +04:00
if ( IsAlive ( player ) )
2016-09-10 19:31:38 +03:00
storeClient . flags | = CF_ALIVE ;
2014-07-30 14:17:46 +04:00
else
2016-09-10 19:31:38 +03:00
storeClient . flags & = ~ CF_ALIVE ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( storeClient . flags & CF_ALIVE )
2014-07-30 14:17:46 +04:00
{
// keep the clipping mode enabled, or it can be turned off after new round has started
if ( g_hostEntity = = player & & g_editNoclip )
g_hostEntity - > v . movetype = MOVETYPE_NOCLIP ;
2016-09-10 19:31:38 +03:00
storeClient . origin = player - > v . origin ;
2014-07-30 14:17:46 +04:00
SoundSimulateUpdate ( i ) ;
}
}
else
{
2016-09-10 19:31:38 +03:00
storeClient . flags & = ~ ( CF_USED | CF_ALIVE ) ;
2016-09-11 21:01:06 +03:00
storeClient . ent = nullptr ;
2014-07-30 14:17:46 +04:00
}
}
2016-03-05 23:08:07 +03:00
if ( ! engine . IsDedicatedServer ( ) & & ! engine . IsNullEntity ( g_hostEntity ) )
2014-07-30 14:17:46 +04:00
{
if ( g_waypointOn )
2015-07-24 15:10:51 +03:00
waypoints . Think ( ) ;
2014-07-30 14:17:46 +04:00
2016-08-27 23:39:20 +03:00
CheckWelcomeMessage ( ) ;
2014-07-30 14:17:46 +04:00
}
2015-07-24 15:10:51 +03:00
bots . SetDeathMsgState ( false ) ;
2014-07-30 14:17:46 +04:00
2016-03-01 13:37:10 +03:00
if ( g_timePerSecondUpdate < engine . Time ( ) )
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
{
2016-03-05 23:08:07 +03:00
edict_t * player = engine . EntityOfIndex ( i + 1 ) ;
2014-07-30 14:17:46 +04:00
// code below is executed only on dedicated server
2016-03-05 23:08:07 +03:00
if ( engine . IsDedicatedServer ( ) & & ! engine . IsNullEntity ( player ) & & ( player - > v . flags & FL_CLIENT ) & & ! ( player - > v . flags & FL_FAKECLIENT ) )
2014-07-30 14:17:46 +04:00
{
2016-03-12 19:56:09 +03:00
Client & client = g_clients [ i ] ;
if ( client . flags & CF_ADMIN )
2014-07-30 14:17:46 +04:00
{
if ( IsNullString ( yb_password_key . GetString ( ) ) & & IsNullString ( yb_password . GetString ( ) ) )
2016-03-12 19:56:09 +03:00
client . flags & = ~ CF_ADMIN ;
else if ( strcmp ( yb_password . GetString ( ) , INFOKEY_VALUE ( GET_INFOKEYBUFFER ( client . ent ) , const_cast < char * > ( yb_password_key . GetString ( ) ) ) ) )
2014-07-30 14:17:46 +04:00
{
2016-03-12 19:56:09 +03:00
client . flags & = ~ CF_ADMIN ;
2016-03-01 13:37:10 +03:00
engine . Printf ( " Player %s had lost remote access to yapb. " , STRING ( player - > v . netname ) ) ;
2014-07-30 14:17:46 +04:00
}
}
2016-03-12 19:56:09 +03:00
else if ( ! ( client . flags & CF_ADMIN ) & & ! IsNullString ( yb_password_key . GetString ( ) ) & & ! IsNullString ( yb_password . GetString ( ) ) )
2014-07-30 14:17:46 +04:00
{
2016-03-12 19:56:09 +03:00
if ( strcmp ( yb_password . GetString ( ) , INFOKEY_VALUE ( GET_INFOKEYBUFFER ( client . ent ) , const_cast < char * > ( yb_password_key . GetString ( ) ) ) ) = = 0 )
2014-07-30 14:17:46 +04:00
{
2016-03-12 19:56:09 +03:00
client . flags | = CF_ADMIN ;
2016-03-01 13:37:10 +03:00
engine . Printf ( " Player %s had gained full remote access to yapb. " , STRING ( player - > v . netname ) ) ;
2014-07-30 14:17:46 +04:00
}
}
}
}
2016-01-16 11:00:40 +03:00
bots . CalculatePingOffsets ( ) ;
2016-01-04 18:26:06 +03:00
2016-09-10 19:31:38 +03:00
// select the leader each team
for ( int team = TERRORIST ; team < SPECTATOR ; team + + )
bots . SelectLeaderEachTeam ( team , false ) ;
if ( g_gameFlags & GAME_METAMOD )
2015-06-11 00:18:49 +03:00
{
static cvar_t * csdm_active ;
static cvar_t * mp_freeforall ;
2016-09-11 21:01:06 +03:00
if ( csdm_active = = nullptr )
2015-06-11 00:18:49 +03:00
csdm_active = CVAR_GET_POINTER ( " csdm_active " ) ;
2016-09-11 21:01:06 +03:00
if ( mp_freeforall = = nullptr )
2015-06-11 00:18:49 +03:00
mp_freeforall = CVAR_GET_POINTER ( " mp_freeforall " ) ;
2016-09-11 21:01:06 +03:00
if ( csdm_active ! = nullptr & & csdm_active - > value > 0 )
yb_csdm_mode . SetInt ( mp_freeforall ! = nullptr & & mp_freeforall - > value > 0 ? 2 : 1 ) ;
2015-06-11 00:18:49 +03:00
}
2016-03-01 13:37:10 +03:00
g_timePerSecondUpdate = engine . Time ( ) + 1.0f ;
2014-07-30 14:17:46 +04:00
}
2016-03-25 14:56:40 +03:00
// keep track of grenades on map
bots . UpdateActiveGrenades ( ) ;
2014-07-30 14:17:46 +04:00
// keep bot number up to date
2015-07-24 15:10:51 +03:00
bots . MaintainBotQuota ( ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_functionTable . pfnStartFrame ) ( ) ;
2015-06-21 19:04:41 +03:00
// **** AI EXECUTION STARTS ****
2015-07-24 15:10:51 +03:00
bots . Think ( ) ;
2015-06-21 19:04:41 +03:00
// **** AI EXECUTION FINISH ****
}
void StartFrame_Post ( void )
{
// this function starts a video frame. It is called once per video frame by the engine. If
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
// placing a hook on it, we have a good place to do things that should be done continuously
// during the game, for example making the bots think (yes, because no Think() function exists
// for the bots by the MOD side, remember). Post version called only by metamod.
// **** AI EXECUTION STARTS ****
2015-07-24 15:10:51 +03:00
bots . Think ( ) ;
2015-06-21 19:04:41 +03:00
// **** AI EXECUTION FINISH ****
RETURN_META ( MRES_IGNORED ) ;
2014-07-30 14:17:46 +04:00
}
int Spawn_Post ( edict_t * ent )
{
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
// world, in other words to 'display') the entity pointed to by ent in the game. The
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
// and any MOD is supposed to implement one for each of its entities. Post version called
// only by metamod.
// solves the bots unable to see through certain types of glass bug.
if ( ent - > v . rendermode = = kRenderTransTexture )
ent - > v . flags & = ~ FL_WORLDBRUSH ; // clear the FL_WORLDBRUSH flag out of transparent ents
RETURN_META_VALUE ( MRES_IGNORED , 0 ) ;
}
2015-06-28 19:43:31 +03:00
void ServerActivate_Post ( edict_t * , int , int )
2014-07-30 14:17:46 +04:00
{
// this function is called when the server has fully loaded and is about to manifest itself
// on the network as such. Since a mapchange is actually a server shutdown followed by a
// restart, this function is also called when a new map is being loaded. Hence it's the
// perfect place for doing initialization stuff for our bots, such as reading the BSP data,
// loading the bot profiles, and drawing the world map (ie, filling the navigation hashtable).
// Once this function has been called, the server can be considered as "running". Post version
// called only by metamod.
2015-07-24 15:10:51 +03:00
waypoints . InitializeVisibility ( ) ;
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
}
void pfnChangeLevel ( char * s1 , char * s2 )
{
// the purpose of this function is to ask the engine to shutdown the server and restart a
// new one running the map whose name is s1. It is used ONLY IN SINGLE PLAYER MODE and is
// transparent to the user, because it saves the player state and equipment and restores it
// back in the new level. The "changelevel trigger point" in the old level is linked to the
// new level's spawn point using the s2 string, which is formatted as follows: "trigger_name
// to spawnpoint_name", without spaces (for example, "tr_1atotr_2lm" would tell the engine
// the player has reached the trigger point "tr_1a" and has to spawn in the next level on the
// spawn point named "tr_2lm".
// save collected experience on map change
2015-07-24 15:10:51 +03:00
waypoints . SaveExperienceTab ( ) ;
waypoints . SaveVisibilityTab ( ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
CHANGE_LEVEL ( s1 , s2 ) ;
}
edict_t * pfnFindEntityByString ( edict_t * edictStartSearchAfter , const char * field , const char * value )
{
// round starts in counter-strike 1.5
if ( strcmp ( value , " info_map_parameters " ) = = 0 )
2016-03-05 21:22:29 +03:00
RoundInit ( ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META_VALUE ( MRES_IGNORED , 0 ) ;
return FIND_ENTITY_BY_STRING ( edictStartSearchAfter , field , value ) ;
}
void pfnEmitSound ( edict_t * entity , int channel , const char * sample , float volume , float attenuation , int flags , int pitch )
{
// this function tells the engine that the entity pointed to by "entity", is emitting a sound
// which fileName is "sample", at level "channel" (CHAN_VOICE, etc...), with "volume" as
// loudness multiplicator (normal volume VOL_NORM is 1.0), with a pitch of "pitch" (normal
// pitch PITCH_NORM is 100.0), and that this sound has to be attenuated by distance in air
// according to the value of "attenuation" (normal attenuation ATTN_NORM is 0.8 ; ATTN_NONE
// means no attenuation with distance). Optionally flags "fFlags" can be passed, which I don't
// know the heck of the purpose. After we tell the engine to emit the sound, we have to call
// SoundAttachToThreat() to bring the sound to the ears of the bots. Since bots have no client DLL
// to handle this for them, such a job has to be done manually.
2015-07-19 13:39:00 +03:00
SoundAttachToClients ( entity , sample , volume ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_engfuncs . pfnEmitSound ) ( entity , channel , sample , volume , attenuation , flags , pitch ) ;
}
2016-03-12 14:35:44 +03:00
void pfnClientCommand ( edict_t * ent , char const * format , . . . )
2014-07-30 14:17:46 +04:00
{
// this function forces the client whose player entity is ent to issue a client command.
// How it works is that clients all have a g_xgv global string in their client DLL that
// stores the command string; if ever that string is filled with characters, the client DLL
// sends it to the engine as a command to be executed. When the engine has executed that
// command, this g_xgv string is reset to zero. Here is somehow a curious implementation of
// ClientCommand: the engine sets the command it wants the client to issue in his g_xgv, then
// the client DLL sends it back to the engine, the engine receives it then executes the
// command therein. Don't ask me why we need all this complicated crap. Anyhow since bots have
// no client DLL, be certain never to call this function upon a bot entity, else it will just
// make the server crash. Since hordes of uncautious, not to say stupid, programmers don't
// even imagine some players on their servers could be bots, this check is performed less than
// sometimes actually by their side, that's why we strongly recommend to check it here too. In
2016-03-01 22:52:17 +03:00
// case it's a bot asking for a client command, we handle it like we do for bot commands
2014-07-30 14:17:46 +04:00
va_list ap ;
2016-03-12 19:56:09 +03:00
char buffer [ MAX_PRINT_BUFFER ] ;
2014-07-30 14:17:46 +04:00
va_start ( ap , format ) ;
2016-03-12 19:56:09 +03:00
_vsnprintf ( buffer , SIZEOF_CHAR ( buffer ) , format , ap ) ;
2014-07-30 14:17:46 +04:00
va_end ( ap ) ;
2016-09-16 16:10:22 +03:00
if ( bots . GetBot ( ent ) )
2014-07-30 14:17:46 +04:00
{
2016-09-14 15:40:42 +03:00
engine . IssueBotCommand ( ent , buffer ) ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ; // prevent bots to be forced to issue client commands
return ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
CLIENT_COMMAND ( ent , buffer ) ;
}
void pfnMessageBegin ( int msgDest , int msgType , const float * origin , edict_t * ed )
{
// this function called each time a message is about to sent.
// store the message type in our own variables, since the GET_USER_MSG_ID () will just do a lot of strcmp()'s...
2016-09-10 19:31:38 +03:00
if ( ( g_gameFlags & GAME_METAMOD ) & & engine . FindMessageId ( NETMSG_MONEY ) = = - 1 )
2014-07-30 14:17:46 +04:00
{
2016-09-11 21:01:06 +03:00
engine . AssignMessageId ( NETMSG_VGUI , GET_USER_MSG_ID ( PLID , " VGUIMenu " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_SHOWMENU , GET_USER_MSG_ID ( PLID , " ShowMenu " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_WEAPONLIST , GET_USER_MSG_ID ( PLID , " WeaponList " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_CURWEAPON , GET_USER_MSG_ID ( PLID , " CurWeapon " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_AMMOX , GET_USER_MSG_ID ( PLID , " AmmoX " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_AMMOPICKUP , GET_USER_MSG_ID ( PLID , " AmmoPickup " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_DAMAGE , GET_USER_MSG_ID ( PLID , " Damage " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_MONEY , GET_USER_MSG_ID ( PLID , " Money " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_STATUSICON , GET_USER_MSG_ID ( PLID , " StatusIcon " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_DEATH , GET_USER_MSG_ID ( PLID , " DeathMsg " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_SCREENFADE , GET_USER_MSG_ID ( PLID , " ScreenFade " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_HLTV , GET_USER_MSG_ID ( PLID , " HLTV " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_TEXTMSG , GET_USER_MSG_ID ( PLID , " TextMsg " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_SCOREINFO , GET_USER_MSG_ID ( PLID , " ScoreInfo " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_BARTIME , GET_USER_MSG_ID ( PLID , " BarTime " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_SENDAUDIO , GET_USER_MSG_ID ( PLID , " SendAudio " , nullptr ) ) ;
engine . AssignMessageId ( NETMSG_SAYTEXT , GET_USER_MSG_ID ( PLID , " SayText " , nullptr ) ) ;
2014-07-30 14:17:46 +04:00
2016-09-14 11:51:58 +03:00
if ( g_gameFlags & GAME_SUPPORT_BOT_VOICE )
2016-09-11 21:01:06 +03:00
engine . AssignMessageId ( NETMSG_BOTVOICE , GET_USER_MSG_ID ( PLID , " BotVoice " , nullptr ) ) ;
2014-07-30 14:17:46 +04:00
}
2016-03-12 14:35:44 +03:00
engine . ResetMessageCapture ( ) ;
2014-07-30 14:17:46 +04:00
2016-09-14 09:20:33 +03:00
if ( ( ! ( g_gameFlags & GAME_LEGACY ) | | ( g_gameFlags & GAME_XASH_ENGINE ) ) & & msgDest = = MSG_SPEC & & msgType = = engine . FindMessageId ( NETMSG_HLTV ) )
2016-03-12 14:35:44 +03:00
engine . SetOngoingMessageId ( NETMSG_HLTV ) ;
2014-07-30 14:17:46 +04:00
2016-03-12 14:35:44 +03:00
engine . TryCaptureMessage ( msgType , NETMSG_WEAPONLIST ) ;
2014-07-30 14:17:46 +04:00
2016-03-05 23:08:07 +03:00
if ( ! engine . IsNullEntity ( ed ) )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
int index = bots . GetIndex ( ed ) ;
2014-07-30 14:17:46 +04:00
// is this message for a bot?
2016-03-12 14:35:44 +03:00
if ( index ! = - 1 & & ! ( ed - > v . flags & FL_DORMANT ) )
2014-07-30 14:17:46 +04:00
{
2016-03-12 14:35:44 +03:00
engine . SetOngoingMessageReceiver ( index ) ;
2014-07-30 14:17:46 +04:00
// message handling is done in usermsg.cpp
2016-03-12 14:35:44 +03:00
engine . TryCaptureMessage ( msgType , NETMSG_VGUI ) ;
engine . TryCaptureMessage ( msgType , NETMSG_CURWEAPON ) ;
engine . TryCaptureMessage ( msgType , NETMSG_AMMOX ) ;
engine . TryCaptureMessage ( msgType , NETMSG_AMMOPICKUP ) ;
engine . TryCaptureMessage ( msgType , NETMSG_DAMAGE ) ;
engine . TryCaptureMessage ( msgType , NETMSG_MONEY ) ;
engine . TryCaptureMessage ( msgType , NETMSG_STATUSICON ) ;
engine . TryCaptureMessage ( msgType , NETMSG_SCREENFADE ) ;
engine . TryCaptureMessage ( msgType , NETMSG_BARTIME ) ;
engine . TryCaptureMessage ( msgType , NETMSG_TEXTMSG ) ;
engine . TryCaptureMessage ( msgType , NETMSG_SHOWMENU ) ;
2014-07-30 14:17:46 +04:00
}
}
else if ( msgDest = = MSG_ALL )
{
2016-03-12 14:35:44 +03:00
engine . TryCaptureMessage ( msgType , NETMSG_SCOREINFO ) ;
engine . TryCaptureMessage ( msgType , NETMSG_DEATH ) ;
engine . TryCaptureMessage ( msgType , NETMSG_TEXTMSG ) ;
2014-07-30 14:17:46 +04:00
if ( msgType = = SVC_INTERMISSION )
{
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
Bot * bot = bots . GetBot ( i ) ;
2014-07-30 14:17:46 +04:00
2016-09-11 21:01:06 +03:00
if ( bot ! = nullptr )
2014-07-30 14:17:46 +04:00
bot - > m_notKilled = false ;
}
}
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnMessageBegin ( msgDest , msgType , origin , ed ) ;
2014-07-30 14:17:46 +04:00
}
void pfnMessageEnd ( void )
{
2016-03-12 14:35:44 +03:00
engine . ResetMessageCapture ( ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnMessageEnd ( ) ;
2014-08-01 22:28:45 +04:00
// send latency fix
2015-07-24 15:10:51 +03:00
bots . SendDeathMsgFix ( ) ;
2014-08-01 22:28:45 +04:00
}
void pfnMessageEnd_Post ( void )
{
// send latency fix
2015-07-24 15:10:51 +03:00
bots . SendDeathMsgFix ( ) ;
2014-08-01 22:28:45 +04:00
RETURN_META ( MRES_IGNORED ) ;
2014-07-30 14:17:46 +04:00
}
void pfnWriteByte ( int value )
{
// if this message is for a bot, call the client message function...
2016-03-13 11:58:35 +03:00
engine . ProcessMessageCapture ( ( void * ) & value ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnWriteByte ( value ) ;
2014-07-30 14:17:46 +04:00
}
void pfnWriteChar ( int value )
{
// if this message is for a bot, call the client message function...
2016-03-13 11:58:35 +03:00
engine . ProcessMessageCapture ( ( void * ) & value ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnWriteChar ( value ) ;
2014-07-30 14:17:46 +04:00
}
void pfnWriteShort ( int value )
{
// if this message is for a bot, call the client message function...
2016-03-13 11:58:35 +03:00
engine . ProcessMessageCapture ( ( void * ) & value ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnWriteShort ( value ) ;
2014-07-30 14:17:46 +04:00
}
void pfnWriteLong ( int value )
{
// if this message is for a bot, call the client message function...
2016-03-13 11:58:35 +03:00
engine . ProcessMessageCapture ( ( void * ) & value ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnWriteLong ( value ) ;
2014-07-30 14:17:46 +04:00
}
void pfnWriteAngle ( float value )
{
// if this message is for a bot, call the client message function...
2016-03-13 11:58:35 +03:00
engine . ProcessMessageCapture ( ( void * ) & value ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnWriteAngle ( value ) ;
2014-07-30 14:17:46 +04:00
}
void pfnWriteCoord ( float value )
{
// if this message is for a bot, call the client message function...
2016-03-13 11:58:35 +03:00
engine . ProcessMessageCapture ( ( void * ) & value ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnWriteCoord ( value ) ;
2014-07-30 14:17:46 +04:00
}
void pfnWriteString ( const char * sz )
{
// if this message is for a bot, call the client message function...
2016-03-13 11:58:35 +03:00
engine . ProcessMessageCapture ( ( void * ) sz ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnWriteString ( sz ) ;
2014-07-30 14:17:46 +04:00
}
void pfnWriteEntity ( int value )
{
// if this message is for a bot, call the client message function...
2016-03-13 11:58:35 +03:00
engine . ProcessMessageCapture ( ( void * ) & value ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
2016-09-14 15:40:42 +03:00
g_engfuncs . pfnWriteEntity ( value ) ;
2014-07-30 14:17:46 +04:00
}
int pfnCmd_Argc ( void )
{
// this function returns the number of arguments the current client command string has. Since
// bots have no client DLL and we may want a bot to execute a client command, we had to
// implement a g_xgv string in the bot DLL for holding the bots' commands, and also keep
// track of the argument count. Hence this hook not to let the engine ask an unexistent client
// DLL for a command we are holding here. Of course, real clients commands are still retrieved
// the normal way, by asking the engine.
2016-03-01 22:52:17 +03:00
// is this a bot issuing that client command?
if ( engine . IsBotCommand ( ) )
2014-07-30 14:17:46 +04:00
{
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-03-01 22:52:17 +03:00
RETURN_META_VALUE ( MRES_SUPERCEDE , engine . GetOverrideArgc ( ) ) ;
2014-07-30 14:17:46 +04:00
2016-03-01 22:52:17 +03:00
return engine . GetOverrideArgc ( ) ; // if so, then return the argument count we know
2014-07-30 14:17:46 +04:00
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META_VALUE ( MRES_IGNORED , 0 ) ;
return CMD_ARGC ( ) ; // ask the engine how many arguments there are
}
const char * pfnCmd_Args ( void )
{
// this function returns a pointer to the whole current client command string. Since bots
// have no client DLL and we may want a bot to execute a client command, we had to implement
// a g_xgv string in the bot DLL for holding the bots' commands, and also keep track of the
// argument count. Hence this hook not to let the engine ask an unexistent client DLL for a
// command we are holding here. Of course, real clients commands are still retrieved the
// normal way, by asking the engine.
// is this a bot issuing that client command?
2016-03-01 22:52:17 +03:00
if ( engine . IsBotCommand ( ) )
2014-07-30 14:17:46 +04:00
{
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-03-01 22:52:17 +03:00
RETURN_META_VALUE ( MRES_SUPERCEDE , engine . GetOverrideArgs ( ) ) ;
2014-07-30 14:17:46 +04:00
2016-03-01 22:52:17 +03:00
return engine . GetOverrideArgs ( ) ; // else return the whole bot client command string we know
2014-07-30 14:17:46 +04:00
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-09-11 21:01:06 +03:00
RETURN_META_VALUE ( MRES_IGNORED , nullptr ) ;
2014-07-30 14:17:46 +04:00
return CMD_ARGS ( ) ; // ask the client command string to the engine
}
const char * pfnCmd_Argv ( int argc )
{
// this function returns a pointer to a certain argument of the current client command. Since
// bots have no client DLL and we may want a bot to execute a client command, we had to
// implement a g_xgv string in the bot DLL for holding the bots' commands, and also keep
// track of the argument count. Hence this hook not to let the engine ask an unexistent client
// DLL for a command we are holding here. Of course, real clients commands are still retrieved
// the normal way, by asking the engine.
2016-03-01 22:52:17 +03:00
// is this a bot issuing that client command?
if ( engine . IsBotCommand ( ) )
2014-07-30 14:17:46 +04:00
{
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-03-01 22:52:17 +03:00
RETURN_META_VALUE ( MRES_SUPERCEDE , engine . GetOverrideArgv ( argc ) ) ;
2014-07-30 14:17:46 +04:00
2016-03-01 22:52:17 +03:00
return engine . GetOverrideArgv ( argc ) ; // if so, then return the wanted argument we know
2014-07-30 14:17:46 +04:00
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-09-11 21:01:06 +03:00
RETURN_META_VALUE ( MRES_IGNORED , nullptr ) ;
2014-07-30 14:17:46 +04:00
return CMD_ARGV ( argc ) ; // ask the argument number "argc" to the engine
}
void pfnClientPrintf ( edict_t * ent , PRINT_TYPE printType , const char * message )
{
// this function prints the text message string pointed to by message by the client side of
// the client entity pointed to by ent, in a manner depending of printType (print_console,
// print_center or print_chat). Be certain never to try to feed a bot with this function,
// as it will crash your server. Why would you, anyway ? bots have no client DLL as far as
// we know, right ? But since stupidity rules this world, we do a preventive check :)
if ( IsValidBot ( ent ) )
{
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_SUPERCEDE ) ;
return ;
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
CLIENT_PRINTF ( ent , printType , message ) ;
}
void pfnSetClientMaxspeed ( const edict_t * ent , float newMaxspeed )
{
2015-07-24 15:10:51 +03:00
Bot * bot = bots . GetBot ( const_cast < edict_t * > ( ent ) ) ;
2014-07-30 14:17:46 +04:00
// check wether it's not a bot
2016-09-11 21:01:06 +03:00
if ( bot ! = nullptr )
2014-07-30 14:17:46 +04:00
bot - > pev - > maxspeed = newMaxspeed ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_engfuncs . pfnSetClientMaxspeed ) ( ent , newMaxspeed ) ;
}
int pfnRegUserMsg ( const char * name , int size )
{
// this function registers a "user message" by the engine side. User messages are network
// messages the game DLL asks the engine to send to clients. Since many MODs have completely
// different client features (Counter-Strike has a radar and a timer, for example), network
// messages just can't be the same for every MOD. Hence here the MOD DLL tells the engine,
// "Hey, you have to know that I use a network message whose name is pszName and it is size
// packets long". The engine books it, and returns the ID number under which he recorded that
// custom message. Thus every time the MOD DLL will be wanting to send a message named pszName
// using pfnMessageBegin (), it will know what message ID number to send, and the engine will
// know what to do, only for non-metamod version
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META_VALUE ( MRES_IGNORED , 0 ) ;
int message = REG_USER_MSG ( name , size ) ;
if ( strcmp ( name , " VGUIMenu " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_VGUI , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " ShowMenu " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_SHOWMENU , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " WeaponList " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_WEAPONLIST , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " CurWeapon " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_CURWEAPON , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " AmmoX " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_AMMOX , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " AmmoPickup " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_AMMOPICKUP , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " Damage " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_DAMAGE , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " Money " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_MONEY , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " StatusIcon " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_STATUSICON , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " DeathMsg " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_DEATH , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " ScreenFade " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_SCREENFADE , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " HLTV " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_HLTV , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " TextMsg " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_TEXTMSG , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " ScoreInfo " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_SCOREINFO , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " BarTime " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_BARTIME , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " SendAudio " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_SENDAUDIO , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " SayText " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_SAYTEXT , message ) ;
2014-07-30 14:17:46 +04:00
else if ( strcmp ( name , " BotVoice " ) = = 0 )
2016-03-12 14:35:44 +03:00
engine . AssignMessageId ( NETMSG_BOTVOICE , message ) ;
2014-07-30 14:17:46 +04:00
return message ;
}
void pfnAlertMessage ( ALERT_TYPE alertType , char * format , . . . )
{
va_list ap ;
char buffer [ 1024 ] ;
va_start ( ap , format ) ;
2016-03-12 14:35:44 +03:00
vsnprintf ( buffer , SIZEOF_CHAR ( buffer ) , format , ap ) ;
2014-07-30 14:17:46 +04:00
va_end ( ap ) ;
2016-09-11 21:01:06 +03:00
if ( ( g_mapType & MAP_DE ) & & g_bombPlanted & & strstr ( buffer , " _Defuse_ " ) ! = nullptr )
2014-07-30 14:17:46 +04:00
{
// notify all terrorists that CT is starting bomb defusing
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
Bot * bot = bots . GetBot ( i ) ;
2014-07-30 14:17:46 +04:00
2016-09-11 21:01:06 +03:00
if ( bot ! = nullptr & & bot - > m_team = = TERRORIST & & bot - > m_notKilled )
2014-07-30 14:17:46 +04:00
{
2016-06-23 15:30:19 +03:00
bot - > DeleteSearchNodes ( ) ;
bot - > m_position = waypoints . GetBombPosition ( ) ;
bot - > PushTask ( TASK_MOVETOPOSITION , TASKPRI_MOVETOPOSITION , - 1 , 0.0f , true ) ;
2014-07-30 14:17:46 +04:00
}
}
}
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
RETURN_META ( MRES_IGNORED ) ;
( * g_engfuncs . pfnAlertMessage ) ( alertType , buffer ) ;
}
2016-09-16 16:10:22 +03:00
typedef void ( * entity_func_t ) ( entvars_t * ) ;
2014-07-30 14:17:46 +04:00
gamedll_funcs_t gameDLLFunc ;
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT int GetEntityAPI2 ( gamefuncs_t * functionTable , int * )
2014-07-30 14:17:46 +04:00
{
// this function is called right after FuncPointers_t() by the engine in the game DLL (or
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
// be called by the engine, into a memory block pointed to by the functionTable pointer
// that is passed into this function (explanation comes straight from botman). This allows
// the Half-Life engine to call these MOD DLL functions when it needs to spawn an entity,
// connect or disconnect a player, call Think() functions, Touch() functions, or Use()
// functions, etc. The bot DLL passes its OWN list of these functions back to the Half-Life
// engine, and then calls the MOD DLL's version of GetEntityAPI to get the REAL gamedll
// functions this time (to use in the bot code).
memset ( functionTable , 0 , sizeof ( gamefuncs_t ) ) ;
2016-09-10 19:31:38 +03:00
if ( ! ( g_gameFlags & GAME_METAMOD ) )
2014-07-30 14:17:46 +04:00
{
2016-09-16 16:10:22 +03:00
auto api_GetEntityAPI = g_gameLib - > GetFuncAddr < int ( * ) ( gamefuncs_t * , int ) > ( " GetEntityAPI " ) ;
2016-09-10 19:31:38 +03:00
2014-07-30 14:17:46 +04:00
// pass other DLLs engine callbacks to function table...
2016-09-10 19:31:38 +03:00
if ( api_GetEntityAPI ( & g_functionTable , INTERFACE_VERSION ) = = 0 )
{
AddLogEntry ( true , LL_FATAL , " GetEntityAPI2: ERROR - Not Initialized. " ) ;
return FALSE ; // error initializing function table!!!
}
2014-07-30 14:17:46 +04:00
gameDLLFunc . dllapi_table = & g_functionTable ;
gpGamedllFuncs = & gameDLLFunc ;
memcpy ( functionTable , & g_functionTable , sizeof ( gamefuncs_t ) ) ;
}
functionTable - > pfnGameInit = GameDLLInit ;
functionTable - > pfnSpawn = Spawn ;
2015-06-09 15:45:34 +03:00
functionTable - > pfnTouch = Touch ;
2014-07-30 14:17:46 +04:00
functionTable - > pfnClientConnect = ClientConnect ;
functionTable - > pfnClientDisconnect = ClientDisconnect ;
functionTable - > pfnClientUserInfoChanged = ClientUserInfoChanged ;
functionTable - > pfnClientCommand = ClientCommand ;
functionTable - > pfnServerActivate = ServerActivate ;
functionTable - > pfnServerDeactivate = ServerDeactivate ;
functionTable - > pfnStartFrame = StartFrame ;
2014-08-01 22:28:45 +04:00
functionTable - > pfnUpdateClientData = UpdateClientData ;
2014-07-30 14:17:46 +04:00
return TRUE ;
}
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post ( gamefuncs_t * functionTable , int * )
2014-07-30 14:17:46 +04:00
{
// this function is called right after FuncPointers_t() by the engine in the game DLL (or
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
// be called by the engine, into a memory block pointed to by the functionTable pointer
// that is passed into this function (explanation comes straight from botman). This allows
// the Half-Life engine to call these MOD DLL functions when it needs to spawn an entity,
// connect or disconnect a player, call Think() functions, Touch() functions, or Use()
// functions, etc. The bot DLL passes its OWN list of these functions back to the Half-Life
// engine, and then calls the MOD DLL's version of GetEntityAPI to get the REAL gamedll
// functions this time (to use in the bot code). Post version, called only by metamod.
memset ( functionTable , 0 , sizeof ( gamefuncs_t ) ) ;
functionTable - > pfnSpawn = Spawn_Post ;
2015-06-21 19:04:41 +03:00
functionTable - > pfnStartFrame = StartFrame_Post ;
2014-07-30 14:17:46 +04:00
functionTable - > pfnServerActivate = ServerActivate_Post ;
return TRUE ;
}
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT int GetNewDLLFunctions ( newgamefuncs_t * functionTable , int * interfaceVersion )
2014-07-30 14:17:46 +04:00
{
// it appears that an extra function table has been added in the engine to gamedll interface
// since the date where the first enginefuncs table standard was frozen. These ones are
// facultative and we don't hook them, but since some MODs might be featuring it, we have to
// pass them too, else the DLL interfacing wouldn't be complete and the game possibly wouldn't
// run properly.
2016-09-16 16:10:22 +03:00
auto api_GetNewDLLFunctions = g_gameLib - > GetFuncAddr < int ( * ) ( newgamefuncs_t * , int * ) > ( " GetNewDLLFunctions " ) ;
2016-09-10 19:31:38 +03:00
2016-09-11 21:01:06 +03:00
if ( api_GetNewDLLFunctions = = nullptr )
2014-07-30 14:17:46 +04:00
return FALSE ;
2016-09-10 19:31:38 +03:00
if ( ! api_GetNewDLLFunctions ( functionTable , interfaceVersion ) )
2014-07-30 14:17:46 +04:00
{
AddLogEntry ( true , LL_FATAL , " GetNewDLLFunctions: ERROR - Not Initialized. " ) ;
return FALSE ;
}
gameDLLFunc . newapi_table = functionTable ;
return TRUE ;
}
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT int GetEngineFunctions ( enginefuncs_t * functionTable , int * )
2014-07-30 14:17:46 +04:00
{
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2014-07-30 14:17:46 +04:00
memset ( functionTable , 0 , sizeof ( enginefuncs_t ) ) ;
2016-03-12 19:56:09 +03:00
2014-07-30 14:17:46 +04:00
functionTable - > pfnChangeLevel = pfnChangeLevel ;
functionTable - > pfnFindEntityByString = pfnFindEntityByString ;
functionTable - > pfnEmitSound = pfnEmitSound ;
functionTable - > pfnClientCommand = pfnClientCommand ;
functionTable - > pfnMessageBegin = pfnMessageBegin ;
functionTable - > pfnMessageEnd = pfnMessageEnd ;
functionTable - > pfnWriteByte = pfnWriteByte ;
functionTable - > pfnWriteChar = pfnWriteChar ;
functionTable - > pfnWriteShort = pfnWriteShort ;
functionTable - > pfnWriteLong = pfnWriteLong ;
functionTable - > pfnWriteAngle = pfnWriteAngle ;
functionTable - > pfnWriteCoord = pfnWriteCoord ;
functionTable - > pfnWriteString = pfnWriteString ;
functionTable - > pfnWriteEntity = pfnWriteEntity ;
functionTable - > pfnRegUserMsg = pfnRegUserMsg ;
functionTable - > pfnClientPrintf = pfnClientPrintf ;
functionTable - > pfnCmd_Args = pfnCmd_Args ;
functionTable - > pfnCmd_Argv = pfnCmd_Argv ;
functionTable - > pfnCmd_Argc = pfnCmd_Argc ;
functionTable - > pfnSetClientMaxspeed = pfnSetClientMaxspeed ;
functionTable - > pfnAlertMessage = pfnAlertMessage ;
2016-03-12 19:56:09 +03:00
2014-07-30 14:17:46 +04:00
return TRUE ;
}
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT int GetEngineFunctions_Post ( enginefuncs_t * functionTable , int * )
2014-08-01 22:28:45 +04:00
{
memset ( functionTable , 0 , sizeof ( enginefuncs_t ) ) ;
functionTable - > pfnMessageEnd = pfnMessageEnd_Post ;
return TRUE ;
}
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT int Server_GetBlendingInterface ( int version , void * * ppinterface , void * pstudio , float ( * rotationmatrix ) [ 3 ] [ 4 ] , float ( * bonetransform ) [ 128 ] [ 3 ] [ 4 ] )
2014-07-30 14:17:46 +04:00
{
// this function synchronizes the studio model animation blending interface (i.e, what parts
// of the body move, which bones, which hitboxes and how) between the server and the game DLL.
// some MODs can be using a different hitbox scheme than the standard one.
2016-09-16 16:10:22 +03:00
auto api_GetBlendingInterface = g_gameLib - > GetFuncAddr < int ( * ) ( int , void * * , void * , float ( * ) [ 3 ] [ 4 ] , float ( * ) [ 128 ] [ 3 ] [ 4 ] ) > ( " Server_GetBlendingInterface " ) ;
2016-09-10 19:31:38 +03:00
2016-09-11 21:01:06 +03:00
if ( api_GetBlendingInterface = = nullptr )
2014-07-30 14:17:46 +04:00
return FALSE ;
2016-09-10 19:31:38 +03:00
return api_GetBlendingInterface ( version , ppinterface , pstudio , rotationmatrix , bonetransform ) ;
2014-07-30 14:17:46 +04:00
}
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT int Meta_Query ( char * , plugin_info_t * * pPlugInfo , mutil_funcs_t * pMetaUtilFuncs )
2014-07-30 14:17:46 +04:00
{
// this function is the first function ever called by metamod in the plugin DLL. Its purpose
// is for metamod to retrieve basic information about the plugin, such as its meta-interface
// version, for ensuring compatibility with the current version of the running metamod.
gpMetaUtilFuncs = pMetaUtilFuncs ;
* pPlugInfo = & Plugin_info ;
return TRUE ; // tell metamod this plugin looks safe
}
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT int Meta_Attach ( PLUG_LOADTIME , metamod_funcs_t * functionTable , meta_globals_t * pMGlobals , gamedll_funcs_t * pGamedllFuncs )
2014-07-30 14:17:46 +04:00
{
// this function is called when metamod attempts to load the plugin. Since it's the place
// where we can tell if the plugin will be allowed to run or not, we wait until here to make
// our initialization stuff, like registering CVARs and dedicated server commands.
2016-09-11 21:01:06 +03:00
// metamod engine & dllapi function tables
static metamod_funcs_t metamodFunctionTable =
{
nullptr , // pfnGetEntityAPI ()
nullptr , // pfnGetEntityAPI_Post ()
GetEntityAPI2 , // pfnGetEntityAPI2 ()
GetEntityAPI2_Post , // pfnGetEntityAPI2_Post ()
nullptr , // pfnGetNewDLLFunctions ()
nullptr , // pfnGetNewDLLFunctions_Post ()
GetEngineFunctions , // pfnGetEngineFunctions ()
GetEngineFunctions_Post , // pfnGetEngineFunctions_Post ()
} ;
2014-07-30 14:17:46 +04:00
// keep track of the pointers to engine function tables metamod gives us
gpMetaGlobals = pMGlobals ;
2016-09-11 21:01:06 +03:00
memcpy ( functionTable , & metamodFunctionTable , sizeof ( metamod_funcs_t ) ) ;
2014-07-30 14:17:46 +04:00
gpGamedllFuncs = pGamedllFuncs ;
return TRUE ; // returning true enables metamod to attach this plugin
}
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT int Meta_Detach ( PLUG_LOADTIME , PL_UNLOAD_REASON )
2014-07-30 14:17:46 +04:00
{
// this function is called when metamod unloads the plugin. A basic check is made in order
// to prevent unloading the plugin if its processing should not be interrupted.
2015-07-24 15:10:51 +03:00
bots . RemoveAll ( ) ; // kick all bots off this server
2014-07-30 14:17:46 +04:00
FreeLibraryMemory ( ) ;
return TRUE ;
}
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT void Meta_Init ( void )
2014-07-30 14:17:46 +04:00
{
// this function is called by metamod, before any other interface functions. Purpose of this
// function to give plugin a chance to determine is plugin running under metamod or not.
2016-09-10 19:31:38 +03:00
g_gameFlags | = GAME_METAMOD ;
2014-07-30 14:17:46 +04:00
}
2016-07-01 09:32:43 +03:00
Library * LoadCSBinary ( void )
{
const char * modname = engine . GetModName ( ) ;
if ( ! modname )
2016-09-11 21:01:06 +03:00
return nullptr ;
2016-07-01 09:32:43 +03:00
# if defined (PLATFORM_WIN32)
const char * libs [ ] = { " mp.dll " , " cs.dll " } ;
# elif defined (PLATFORM_LINUX)
const char * libs [ ] = { " cs.so " , " cs_i386.so " } ;
# elif defined (PLATFORM_OSX)
const char * libs [ ] = { " cs.dylib " } ;
# endif
// search the libraries inside game dlls directory
for ( int i = 0 ; i < ARRAYSIZE_HLSDK ( libs ) ; i + + )
{
char path [ 256 ] ;
sprintf ( path , " %s/dlls/%s " , modname , libs [ i ] ) ;
// if we can't read file, skip it
if ( ! File : : Accessible ( path ) )
continue ;
// special case, czero is always detected first, as it's has custom directory
if ( strcmp ( modname , " czero " ) = = 0 )
{
g_gameFlags | = GAME_CZERO ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-09-11 21:01:06 +03:00
return nullptr ;
2016-07-01 09:32:43 +03:00
return new Library ( path ) ;
}
else
{
Library * game = new Library ( path ) ;
// try to load gamedll
if ( ! game - > IsLoaded ( ) )
{
AddLogEntry ( true , LL_FATAL | LL_IGNORE , " Unable to load gamedll \" %s \" . Exiting... (gamedir: %s) " , libs [ i ] , modname ) ;
2016-09-11 21:01:06 +03:00
return nullptr ;
2016-07-01 09:32:43 +03:00
}
2016-09-14 11:51:58 +03:00
// detect if we're running modern game
2016-09-16 16:10:22 +03:00
auto entity = game - > GetFuncAddr < entity_func_t > ( " weapon_famas " ) ;
2016-07-01 09:32:43 +03:00
// detect xash engine
2016-09-11 21:01:06 +03:00
if ( g_engfuncs . pfnCVarGetPointer ( " build " ) ! = nullptr )
2016-07-01 09:32:43 +03:00
{
2016-09-14 09:20:33 +03:00
g_gameFlags | = ( GAME_LEGACY | GAME_XASH_ENGINE ) ;
2016-07-01 09:32:43 +03:00
2016-09-14 11:51:58 +03:00
if ( entity ! = nullptr )
g_gameFlags | = GAME_SUPPORT_BOT_VOICE ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-07-01 09:32:43 +03:00
{
delete game ;
2016-09-11 21:01:06 +03:00
return nullptr ;
2016-07-01 09:32:43 +03:00
}
return game ;
}
2016-09-11 21:01:06 +03:00
if ( entity ! = nullptr )
2016-09-14 11:51:58 +03:00
g_gameFlags | = ( GAME_CSTRIKE16 | GAME_SUPPORT_BOT_VOICE | GAME_SUPPORT_SVC_PINGS ) ;
2016-07-01 09:32:43 +03:00
else
g_gameFlags | = GAME_LEGACY ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-07-01 09:32:43 +03:00
{
delete game ;
2016-09-11 21:01:06 +03:00
return nullptr ;
2016-07-01 09:32:43 +03:00
}
return game ;
}
}
2016-09-11 21:01:06 +03:00
return nullptr ;
2016-07-01 09:32:43 +03:00
}
2014-07-30 14:17:46 +04:00
DLL_GIVEFNPTRSTODLL GiveFnptrsToDll ( enginefuncs_t * functionTable , globalvars_t * pGlobals )
{
// this is the very first function that is called in the game DLL by the engine. Its purpose
// is to set the functions interfacing up, by exchanging the functionTable function list
// along with a pointer to the engine's global variables structure pGlobals, with the game
// DLL. We can there decide if we want to load the normal game DLL just behind our bot DLL,
// or any other game DLL that is present, such as Will Day's metamod. Also, since there is
// a known bug on Win32 platforms that prevent hook DLLs (such as our bot DLL) to be used in
// single player games (because they don't export all the stuff they should), we may need to
// build our own array of exported symbols from the actual game DLL in order to use it as
// such if necessary. Nothing really bot-related is done in this function. The actual bot
// initialization stuff will be done later, when we'll be certain to have a multilayer game.
2015-06-18 19:29:40 +03:00
// get the engine functions from the engine...
memcpy ( & g_engfuncs , functionTable , sizeof ( enginefuncs_t ) ) ;
g_pGlobals = pGlobals ;
// register our cvars
2016-03-12 14:35:44 +03:00
engine . PushRegisteredConVarsToEngine ( ) ;
2015-06-18 19:29:40 +03:00
2016-03-09 19:17:56 +03:00
// ensure we're have all needed directories
{
const char * mod = engine . GetModName ( ) ;
// create the needed paths
File : : CreatePath ( const_cast < char * > ( FormatBuffer ( " %s/addons/yapb/conf/lang " , mod ) ) ) ;
File : : CreatePath ( const_cast < char * > ( FormatBuffer ( " %s/addons/yapb/data/learned " , mod ) ) ) ;
}
2016-01-01 13:40:39 +03:00
# ifdef PLATFORM_ANDROID
2016-09-14 11:51:58 +03:00
g_gameFlags | = ( GAME_LEGACY | GAME_XASH_ENGINE | GAME_MOBILITY | GAME_SUPPORT_BOT_VOICE ) ;
2015-12-26 01:31:46 +03:00
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2015-12-26 01:31:46 +03:00
return ; // we should stop the attempt for loading the real gamedll, since metamod handle this for us
# ifdef LOAD_HARDFP
2016-03-09 19:17:56 +03:00
const char * serverDLL = " libserver_hardfp.so " ;
2015-12-26 01:31:46 +03:00
# else
2016-03-09 19:17:56 +03:00
const char * serverDLL = " libserver.so " ;
2015-12-26 01:31:46 +03:00
# endif
char gameDLLName [ 256 ] ;
2016-03-09 19:17:56 +03:00
snprintf ( gameDLLName , SIZEOF_CHAR ( gameDLLName ) , " %s/%s " , getenv ( " XASH3D_GAMELIBDIR " ) , serverDLL ) ;
2015-12-26 01:31:46 +03:00
g_gameLib = new Library ( gameDLLName ) ;
if ( ! g_gameLib - > IsLoaded ( ) )
2016-04-18 20:15:54 +03:00
AddLogEntry ( true , LL_FATAL | LL_IGNORE , " Unable to load gamedll \" %s \" . Exiting... (gamedir: %s) " , gameDLLName , engine . GetModName ( ) ) ;
2015-12-26 01:31:46 +03:00
# else
2016-07-01 09:32:43 +03:00
g_gameLib = LoadCSBinary ( ) ;
2014-07-30 14:17:46 +04:00
{
2016-09-11 21:01:06 +03:00
if ( g_gameLib = = nullptr & & ! ( g_gameFlags & GAME_METAMOD ) )
2014-07-30 14:17:46 +04:00
{
2016-07-01 09:32:43 +03:00
AddLogEntry ( true , LL_FATAL | LL_IGNORE , " Mod that you has started, not supported by this bot (gamedir: %s) " , engine . GetModName ( ) ) ;
return ;
2014-07-30 14:17:46 +04:00
}
2016-07-01 09:32:43 +03:00
// print game detection info
String gameVersionStr ;
2014-07-30 14:17:46 +04:00
2016-07-01 09:32:43 +03:00
if ( g_gameFlags & GAME_LEGACY )
gameVersionStr . Assign ( " Legacy " ) ;
2014-07-30 14:17:46 +04:00
2016-07-01 09:32:43 +03:00
else if ( g_gameFlags & GAME_CZERO )
gameVersionStr . Assign ( " Condition Zero " ) ;
2014-07-30 14:17:46 +04:00
2016-07-01 09:32:43 +03:00
else if ( g_gameFlags & GAME_CSTRIKE16 )
gameVersionStr . Assign ( " v1.6 " ) ;
2014-07-30 14:17:46 +04:00
2016-09-14 09:20:33 +03:00
if ( g_gameFlags & GAME_XASH_ENGINE )
2016-07-01 09:32:43 +03:00
{
gameVersionStr . Append ( " @ Xash3D Engine " ) ;
if ( g_gameFlags & GAME_MOBILITY )
gameVersionStr . Append ( " Mobile " ) ;
gameVersionStr . Replace ( " Legacy " , " 1.6 Limited " ) ;
}
2016-09-14 11:51:58 +03:00
if ( g_gameFlags & GAME_SUPPORT_BOT_VOICE )
gameVersionStr . Append ( " (BV) " ) ;
if ( g_gameFlags & GAME_SUPPORT_SVC_PINGS )
gameVersionStr . Append ( " (SVC) " ) ;
2016-07-01 09:32:43 +03:00
engine . Printf ( " YaPB Bot has detect game version as Counter-Strike: %s " , gameVersionStr . GetBuffer ( ) ) ;
2016-09-10 19:31:38 +03:00
if ( g_gameFlags & GAME_METAMOD )
2016-07-01 09:32:43 +03:00
return ;
2014-07-30 14:17:46 +04:00
}
2015-12-26 01:31:46 +03:00
# endif
2016-07-01 09:32:43 +03:00
2016-09-16 16:10:22 +03:00
auto api_GiveFnptrsToDll = g_gameLib - > GetFuncAddr < void ( STD_CALL * ) ( enginefuncs_t * , globalvars_t * ) > ( " GiveFnptrsToDll " ) ;
2014-07-30 14:17:46 +04:00
2016-09-10 19:31:38 +03:00
if ( ! api_GiveFnptrsToDll )
2014-07-30 14:17:46 +04:00
TerminateOnMalloc ( ) ;
2015-06-20 12:56:22 +03:00
2016-09-11 21:01:06 +03:00
GetEngineFunctions ( functionTable , nullptr ) ;
2014-07-30 14:17:46 +04:00
// give the engine functions to the other DLL...
2016-09-10 19:31:38 +03:00
api_GiveFnptrsToDll ( functionTable , pGlobals ) ;
2014-07-30 14:17:46 +04:00
}
DLL_ENTRYPOINT
{
// dynamic library entry point, can be used for uninitialization stuff. NOT for initializing
// anything because if you ever attempt to wander outside the scope of this function on a
// DLL attach, LoadLibrary() will simply fail. And you can't do I/Os here either.
// dynamic library detaching ??
if ( DLL_DETACHING )
{
FreeLibraryMemory ( ) ; // free everything that's freeable
delete g_gameLib ; // if dynamic link library of mod is load, free it
}
DLL_RETENTRY ; // the return data type is OS specific too
}
2016-09-16 16:10:22 +03:00
void LinkEntity_Helper ( entity_func_t & addr , const char * name , entvars_t * pev )
2016-01-27 21:40:47 +03:00
{
2016-09-11 21:01:06 +03:00
if ( addr = = nullptr )
2016-09-16 16:10:22 +03:00
addr = g_gameLib - > GetFuncAddr < entity_func_t > ( name ) ;
2016-01-27 21:40:47 +03:00
2016-09-11 21:01:06 +03:00
if ( addr = = nullptr )
2016-01-27 21:40:47 +03:00
return ;
2016-03-13 11:58:35 +03:00
addr ( pev ) ;
2016-01-27 21:40:47 +03:00
}
# define LINK_ENTITY(entityName) \
2016-03-12 14:35:44 +03:00
SHARED_LIBRARAY_EXPORT void entityName ( entvars_t * pev ) \
2014-07-30 14:17:46 +04:00
{ \
2016-09-16 16:10:22 +03:00
static entity_func_t addr ; \
2016-03-13 11:58:35 +03:00
LinkEntity_Helper ( addr , # entityName , pev ) ; \
2014-07-30 14:17:46 +04:00
} \
// entities in counter-strike...
2015-06-28 19:43:31 +03:00
LINK_ENTITY ( DelayedUse )
LINK_ENTITY ( ambient_generic )
LINK_ENTITY ( ammo_338magnum )
LINK_ENTITY ( ammo_357sig )
LINK_ENTITY ( ammo_45acp )
LINK_ENTITY ( ammo_50ae )
LINK_ENTITY ( ammo_556nato )
LINK_ENTITY ( ammo_556natobox )
LINK_ENTITY ( ammo_57mm )
LINK_ENTITY ( ammo_762nato )
LINK_ENTITY ( ammo_9mm )
LINK_ENTITY ( ammo_buckshot )
LINK_ENTITY ( armoury_entity )
LINK_ENTITY ( beam )
LINK_ENTITY ( bodyque )
LINK_ENTITY ( button_target )
LINK_ENTITY ( cycler )
LINK_ENTITY ( cycler_prdroid )
LINK_ENTITY ( cycler_sprite )
LINK_ENTITY ( cycler_weapon )
LINK_ENTITY ( cycler_wreckage )
LINK_ENTITY ( env_beam )
LINK_ENTITY ( env_beverage )
LINK_ENTITY ( env_blood )
LINK_ENTITY ( env_bombglow )
LINK_ENTITY ( env_bubbles )
LINK_ENTITY ( env_debris )
LINK_ENTITY ( env_explosion )
LINK_ENTITY ( env_fade )
LINK_ENTITY ( env_funnel )
LINK_ENTITY ( env_global )
LINK_ENTITY ( env_glow )
LINK_ENTITY ( env_laser )
LINK_ENTITY ( env_lightning )
LINK_ENTITY ( env_message )
LINK_ENTITY ( env_rain )
LINK_ENTITY ( env_render )
LINK_ENTITY ( env_shake )
LINK_ENTITY ( env_shooter )
LINK_ENTITY ( env_snow )
LINK_ENTITY ( env_sound )
LINK_ENTITY ( env_spark )
LINK_ENTITY ( env_sprite )
LINK_ENTITY ( fireanddie )
LINK_ENTITY ( func_bomb_target )
LINK_ENTITY ( func_breakable )
LINK_ENTITY ( func_button )
LINK_ENTITY ( func_buyzone )
LINK_ENTITY ( func_conveyor )
LINK_ENTITY ( func_door )
LINK_ENTITY ( func_door_rotating )
LINK_ENTITY ( func_escapezone )
LINK_ENTITY ( func_friction )
LINK_ENTITY ( func_grencatch )
LINK_ENTITY ( func_guntarget )
LINK_ENTITY ( func_healthcharger )
LINK_ENTITY ( func_hostage_rescue )
LINK_ENTITY ( func_illusionary )
LINK_ENTITY ( func_ladder )
LINK_ENTITY ( func_monsterclip )
LINK_ENTITY ( func_mortar_field )
LINK_ENTITY ( func_pendulum )
LINK_ENTITY ( func_plat )
LINK_ENTITY ( func_platrot )
LINK_ENTITY ( func_pushable )
LINK_ENTITY ( func_rain )
LINK_ENTITY ( func_recharge )
LINK_ENTITY ( func_rot_button )
LINK_ENTITY ( func_rotating )
LINK_ENTITY ( func_snow )
LINK_ENTITY ( func_tank )
LINK_ENTITY ( func_tankcontrols )
LINK_ENTITY ( func_tanklaser )
LINK_ENTITY ( func_tankmortar )
LINK_ENTITY ( func_tankrocket )
LINK_ENTITY ( func_trackautochange )
LINK_ENTITY ( func_trackchange )
LINK_ENTITY ( func_tracktrain )
LINK_ENTITY ( func_train )
LINK_ENTITY ( func_traincontrols )
LINK_ENTITY ( func_vehicle )
LINK_ENTITY ( func_vehiclecontrols )
LINK_ENTITY ( func_vip_safetyzone )
LINK_ENTITY ( func_wall )
LINK_ENTITY ( func_wall_toggle )
LINK_ENTITY ( func_water )
LINK_ENTITY ( func_weaponcheck )
LINK_ENTITY ( game_counter )
LINK_ENTITY ( game_counter_set )
LINK_ENTITY ( game_end )
LINK_ENTITY ( game_player_equip )
LINK_ENTITY ( game_player_hurt )
LINK_ENTITY ( game_player_team )
LINK_ENTITY ( game_score )
LINK_ENTITY ( game_team_master )
LINK_ENTITY ( game_team_set )
LINK_ENTITY ( game_text )
LINK_ENTITY ( game_zone_player )
LINK_ENTITY ( gibshooter )
LINK_ENTITY ( grenade )
LINK_ENTITY ( hostage_entity )
LINK_ENTITY ( info_bomb_target )
LINK_ENTITY ( info_hostage_rescue )
LINK_ENTITY ( info_intermission )
LINK_ENTITY ( info_landmark )
LINK_ENTITY ( info_map_parameters )
LINK_ENTITY ( info_null )
LINK_ENTITY ( info_player_deathmatch )
LINK_ENTITY ( info_player_start )
LINK_ENTITY ( info_target )
LINK_ENTITY ( info_teleport_destination )
LINK_ENTITY ( info_vip_start )
LINK_ENTITY ( infodecal )
LINK_ENTITY ( item_airtank )
LINK_ENTITY ( item_antidote )
LINK_ENTITY ( item_assaultsuit )
LINK_ENTITY ( item_battery )
LINK_ENTITY ( item_healthkit )
LINK_ENTITY ( item_kevlar )
LINK_ENTITY ( item_longjump )
LINK_ENTITY ( item_security )
LINK_ENTITY ( item_sodacan )
LINK_ENTITY ( item_suit )
LINK_ENTITY ( item_thighpack )
LINK_ENTITY ( light )
LINK_ENTITY ( light_environment )
LINK_ENTITY ( light_spot )
LINK_ENTITY ( momentary_door )
LINK_ENTITY ( momentary_rot_button )
LINK_ENTITY ( monster_hevsuit_dead )
LINK_ENTITY ( monster_mortar )
LINK_ENTITY ( monster_scientist )
LINK_ENTITY ( multi_manager )
LINK_ENTITY ( multisource )
LINK_ENTITY ( path_corner )
LINK_ENTITY ( path_track )
LINK_ENTITY ( player )
LINK_ENTITY ( player_loadsaved )
LINK_ENTITY ( player_weaponstrip )
LINK_ENTITY ( soundent )
LINK_ENTITY ( spark_shower )
LINK_ENTITY ( speaker )
LINK_ENTITY ( target_cdaudio )
LINK_ENTITY ( test_effect )
LINK_ENTITY ( trigger )
LINK_ENTITY ( trigger_auto )
LINK_ENTITY ( trigger_autosave )
LINK_ENTITY ( trigger_camera )
LINK_ENTITY ( trigger_cdaudio )
LINK_ENTITY ( trigger_changelevel )
LINK_ENTITY ( trigger_changetarget )
LINK_ENTITY ( trigger_counter )
LINK_ENTITY ( trigger_endsection )
LINK_ENTITY ( trigger_gravity )
LINK_ENTITY ( trigger_hurt )
LINK_ENTITY ( trigger_monsterjump )
LINK_ENTITY ( trigger_multiple )
LINK_ENTITY ( trigger_once )
LINK_ENTITY ( trigger_push )
LINK_ENTITY ( trigger_relay )
LINK_ENTITY ( trigger_teleport )
LINK_ENTITY ( trigger_transition )
LINK_ENTITY ( weapon_ak47 )
LINK_ENTITY ( weapon_aug )
LINK_ENTITY ( weapon_awp )
LINK_ENTITY ( weapon_c4 )
LINK_ENTITY ( weapon_deagle )
LINK_ENTITY ( weapon_elite )
LINK_ENTITY ( weapon_famas )
LINK_ENTITY ( weapon_fiveseven )
LINK_ENTITY ( weapon_flashbang )
LINK_ENTITY ( weapon_g3sg1 )
LINK_ENTITY ( weapon_galil )
LINK_ENTITY ( weapon_glock18 )
LINK_ENTITY ( weapon_hegrenade )
LINK_ENTITY ( weapon_knife )
LINK_ENTITY ( weapon_m249 )
LINK_ENTITY ( weapon_m3 )
LINK_ENTITY ( weapon_m4a1 )
LINK_ENTITY ( weapon_mac10 )
LINK_ENTITY ( weapon_mp5navy )
LINK_ENTITY ( weapon_p228 )
LINK_ENTITY ( weapon_p90 )
LINK_ENTITY ( weapon_scout )
LINK_ENTITY ( weapon_sg550 )
LINK_ENTITY ( weapon_sg552 )
LINK_ENTITY ( weapon_shield )
LINK_ENTITY ( weapon_shieldgun )
LINK_ENTITY ( weapon_smokegrenade )
LINK_ENTITY ( weapon_tmp )
LINK_ENTITY ( weapon_ump45 )
LINK_ENTITY ( weapon_usp )
LINK_ENTITY ( weapon_xm1014 )
LINK_ENTITY ( weaponbox )
LINK_ENTITY ( world_items )
LINK_ENTITY ( worldspawn )
2015-12-26 23:34:37 +03:00
# ifdef XASH_CSDM
LINK_ENTITY ( aiscripted_sequence )
LINK_ENTITY ( cine_blood )
LINK_ENTITY ( deadplayer_entity )
LINK_ENTITY ( func_headq )
LINK_ENTITY ( info_node )
LINK_ENTITY ( info_node_air )
LINK_ENTITY ( info_player_csdm )
LINK_ENTITY ( monster_c4 )
LINK_ENTITY ( monster_cine2_hvyweapons )
LINK_ENTITY ( monster_cine2_scientist )
LINK_ENTITY ( monster_cine2_slave )
LINK_ENTITY ( monster_cine3_barney )
LINK_ENTITY ( monster_cine3_scientist )
LINK_ENTITY ( monster_cine_barney )
LINK_ENTITY ( monster_cine_panther )
LINK_ENTITY ( monster_cine_scientist )
LINK_ENTITY ( monster_cockroach )
LINK_ENTITY ( monster_furniture )
LINK_ENTITY ( monster_osprey )
LINK_ENTITY ( monster_rat )
LINK_ENTITY ( monster_tentacle )
LINK_ENTITY ( monster_tentaclemaw )
LINK_ENTITY ( monstermaker )
LINK_ENTITY ( node_viewer )
LINK_ENTITY ( node_viewer_fly )
LINK_ENTITY ( node_viewer_human )
LINK_ENTITY ( node_viewer_large )
LINK_ENTITY ( scripted_sequence )
LINK_ENTITY ( testhull )
LINK_ENTITY ( xen_hair )
LINK_ENTITY ( xen_hull )
LINK_ENTITY ( xen_plantlight )
LINK_ENTITY ( xen_spore_large )
LINK_ENTITY ( xen_spore_medium )
LINK_ENTITY ( xen_spore_small )
LINK_ENTITY ( xen_tree )
LINK_ENTITY ( xen_ttrigger )
# endif