2019-07-01 21:10:00 +03:00
//
2023-05-24 23:41:23 +03:00
// YaPB, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright © YaPB Project Developers <yapb@jeefo.net>.
2019-07-01 21:10:00 +03:00
//
2020-11-03 08:57:12 +03:00
// SPDX-License-Identifier: MIT
2019-07-01 21:10:00 +03:00
//
# include <yapb.h>
2023-07-21 21:43:36 +03:00
ConVar cv_display_menu_text ( " display_menu_text " , " 1 " , " Enables or disables display menu text, when players asks for menu. Useful only for Android. " , true , 0.0f , 1.0f , Var : : Xash3D ) ;
ConVar cv_password ( " password " , " " , " The value (password) for the setinfo key , if user sets correct password , he ' s gains access to bot commands and menus . " , false, 0.0f, 0.0f, Var::Password) ;
ConVar cv_password_key ( " password_key " , " _ybpw " , " The name of setinfo key used to store password to bot commands and menus. " , false ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
int BotControl : : cmdAddBot ( ) {
2019-07-01 21:10:00 +03:00
enum args { alias = 1 , difficulty , personality , team , model , name , max } ;
2019-07-27 17:36:24 +03:00
// this is duplicate error as in main bot creation code, but not to be silent
if ( ! graph . length ( ) | | graph . hasChanged ( ) ) {
2019-07-28 15:47:46 +03:00
ctrl . msg ( " There is no graph found or graph is changed. Cannot create bot. " ) ;
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
}
2020-06-12 18:52:38 +03:00
// give a chance to use additional args
m_args . resize ( max ) ;
2019-07-01 21:10:00 +03:00
// if team is specified, modify args to set team
aim: verify camp angles from nav data before using them
aim: tweaked a bit grenade handling, so bots should use them more
aim: reduce time between selecting grenade and throwing it away
aim: removed hacks in look angles code, due to removing yb_whoose_your_daddy cvar
aim: use direct enemy origin from visibility check, and not re-calculate it
aim: update enemy prediction, so it now depends on frame interval for a bot
aim: additional height offset are tweaked, and now used only for difficulty 4
nav: tweaked a bit player avoidance code, and it's not preventing bot from checking terrain
nav: do not check banned nodes, when bucket sizes re too low
nav: cover nodes are now selected depending on total bots on server
nav: let bot enter pause task after long jump
nav: extend velocity by a little for a jump, like it was in first versions of bot
nav: stuck checking is now taken in account lower minimal speed if bot is ducking
fix: navigation reachability timers, so bots will have correct current node index while camping
fix: bots are unable to finish pickup or destroy breakable task, if target is not reachable
fix: cover nodes are now calculated as they should
fix: manual calling bots add_[t/ct] now ignores yb_join_team cvar
bot: tweaked a little difficulty levels, so level 4 is now nightmare level, and 3 is very heard
bot: minor refactoring and moving functions to correct source file
bot: add yb_economics_disrespect_percent, so bots can ignore economics and buy more different guns
bot: add yb_check_darkness that allows to disable darkness checks for bot, thus disallowing usage of flashlight
bot: camp buttons are now lightly depends on bot health
chat: welcome chat message from bots is now sent during first freeze time period
crlib: switch over to stdint.h and remove crlib-own types
crlib: fixed alignment in sse code
2023-04-07 14:46:49 +03:00
if ( strValue ( alias ) . endsWith ( " _ct " ) ) {
2019-07-01 21:10:00 +03:00
m_args . set ( team , " 2 " ) ;
}
aim: verify camp angles from nav data before using them
aim: tweaked a bit grenade handling, so bots should use them more
aim: reduce time between selecting grenade and throwing it away
aim: removed hacks in look angles code, due to removing yb_whoose_your_daddy cvar
aim: use direct enemy origin from visibility check, and not re-calculate it
aim: update enemy prediction, so it now depends on frame interval for a bot
aim: additional height offset are tweaked, and now used only for difficulty 4
nav: tweaked a bit player avoidance code, and it's not preventing bot from checking terrain
nav: do not check banned nodes, when bucket sizes re too low
nav: cover nodes are now selected depending on total bots on server
nav: let bot enter pause task after long jump
nav: extend velocity by a little for a jump, like it was in first versions of bot
nav: stuck checking is now taken in account lower minimal speed if bot is ducking
fix: navigation reachability timers, so bots will have correct current node index while camping
fix: bots are unable to finish pickup or destroy breakable task, if target is not reachable
fix: cover nodes are now calculated as they should
fix: manual calling bots add_[t/ct] now ignores yb_join_team cvar
bot: tweaked a little difficulty levels, so level 4 is now nightmare level, and 3 is very heard
bot: minor refactoring and moving functions to correct source file
bot: add yb_economics_disrespect_percent, so bots can ignore economics and buy more different guns
bot: add yb_check_darkness that allows to disable darkness checks for bot, thus disallowing usage of flashlight
bot: camp buttons are now lightly depends on bot health
chat: welcome chat message from bots is now sent during first freeze time period
crlib: switch over to stdint.h and remove crlib-own types
crlib: fixed alignment in sse code
2023-04-07 14:46:49 +03:00
else if ( strValue ( alias ) . endsWith ( " _t " ) ) {
2019-07-01 21:10:00 +03:00
m_args . set ( team , " 1 " ) ;
}
2023-05-24 23:41:23 +03:00
// if high-skilled bot is requested set personality to rusher and max-out difficulty
aim: verify camp angles from nav data before using them
aim: tweaked a bit grenade handling, so bots should use them more
aim: reduce time between selecting grenade and throwing it away
aim: removed hacks in look angles code, due to removing yb_whoose_your_daddy cvar
aim: use direct enemy origin from visibility check, and not re-calculate it
aim: update enemy prediction, so it now depends on frame interval for a bot
aim: additional height offset are tweaked, and now used only for difficulty 4
nav: tweaked a bit player avoidance code, and it's not preventing bot from checking terrain
nav: do not check banned nodes, when bucket sizes re too low
nav: cover nodes are now selected depending on total bots on server
nav: let bot enter pause task after long jump
nav: extend velocity by a little for a jump, like it was in first versions of bot
nav: stuck checking is now taken in account lower minimal speed if bot is ducking
fix: navigation reachability timers, so bots will have correct current node index while camping
fix: bots are unable to finish pickup or destroy breakable task, if target is not reachable
fix: cover nodes are now calculated as they should
fix: manual calling bots add_[t/ct] now ignores yb_join_team cvar
bot: tweaked a little difficulty levels, so level 4 is now nightmare level, and 3 is very heard
bot: minor refactoring and moving functions to correct source file
bot: add yb_economics_disrespect_percent, so bots can ignore economics and buy more different guns
bot: add yb_check_darkness that allows to disable darkness checks for bot, thus disallowing usage of flashlight
bot: camp buttons are now lightly depends on bot health
chat: welcome chat message from bots is now sent during first freeze time period
crlib: switch over to stdint.h and remove crlib-own types
crlib: fixed alignment in sse code
2023-04-07 14:46:49 +03:00
if ( strValue ( alias ) . endsWith ( " _hs " ) ) {
2019-07-01 21:10:00 +03:00
m_args . set ( difficulty , " 4 " ) ;
m_args . set ( personality , " 1 " ) ;
}
2020-06-12 18:52:38 +03:00
bots . addbot ( strValue ( name ) , strValue ( difficulty ) , strValue ( personality ) , strValue ( team ) , strValue ( model ) , true ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdKickBot ( ) {
2020-06-12 18:52:38 +03:00
enum args { alias = 1 , team } ;
2019-07-01 21:10:00 +03:00
// if team is specified, kick from specified tram
2023-04-02 12:17:12 +03:00
if ( strValue ( alias ) . endsWith ( " _ct " ) | | intValue ( team ) = = 2 | | strValue ( team ) = = " ct " ) {
2019-07-27 17:36:24 +03:00
bots . kickFromTeam ( Team : : CT ) ;
2019-07-01 21:10:00 +03:00
}
2023-04-02 12:17:12 +03:00
else if ( strValue ( alias ) . endsWith ( " _t " ) | | intValue ( team ) = = 1 | | strValue ( team ) = = " t " ) {
2019-07-27 17:36:24 +03:00
bots . kickFromTeam ( Team : : Terrorist ) ;
2019-07-01 21:10:00 +03:00
}
else {
bots . kickRandom ( ) ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdKickBots ( ) {
2023-05-02 09:42:43 +03:00
enum args { alias = 1 , instant , team } ;
2019-07-01 21:10:00 +03:00
// check if we're need to remove bots instantly
2023-06-24 02:36:51 +03:00
const auto kickInstant = strValue ( instant ) = = " instant " ;
2019-07-01 21:10:00 +03:00
2023-05-02 09:42:43 +03:00
// if team is specified, kick from specified tram
if ( strValue ( alias ) . endsWith ( " _ct " ) | | intValue ( team ) = = 2 | | strValue ( team ) = = " ct " ) {
bots . kickFromTeam ( Team : : CT , true ) ;
}
else if ( strValue ( alias ) . endsWith ( " _t " ) | | intValue ( team ) = = 1 | | strValue ( team ) = = " t " ) {
bots . kickFromTeam ( Team : : Terrorist , true ) ;
}
else {
bots . kickEveryone ( kickInstant ) ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdKillBots ( ) {
2024-01-29 08:08:07 +03:00
enum args { alias = 1 , team , silent , max } ;
// do not issue any messages
bool silentKill = hasArg ( silent ) & & strValue ( silent ) . startsWith ( " si " ) ;
2019-07-01 21:10:00 +03:00
// if team is specified, kick from specified tram
2023-04-02 12:17:12 +03:00
if ( strValue ( alias ) . endsWith ( " _ct " ) | | intValue ( team ) = = 2 | | strValue ( team ) = = " ct " ) {
2024-01-29 08:08:07 +03:00
bots . killAllBots ( Team : : CT , silentKill ) ;
2019-07-01 21:10:00 +03:00
}
2023-04-02 12:17:12 +03:00
else if ( strValue ( alias ) . endsWith ( " _t " ) | | intValue ( team ) = = 1 | | strValue ( team ) = = " t " ) {
2024-01-29 08:08:07 +03:00
bots . killAllBots ( Team : : Terrorist , silentKill ) ;
2019-07-01 21:10:00 +03:00
}
else {
2024-01-29 08:08:07 +03:00
bots . killAllBots ( - 1 , silentKill ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdFill ( ) {
2020-06-12 18:52:38 +03:00
enum args { alias = 1 , team , count , difficulty , personality } ;
2019-07-01 21:10:00 +03:00
if ( ! hasArg ( team ) ) {
2019-07-27 17:36:24 +03:00
return BotCommandResult : : BadFormat ;
2019-07-01 21:10:00 +03:00
}
2023-01-25 10:39:52 +00:00
bots . serverFill ( intValue ( team ) , hasArg ( personality ) ? intValue ( personality ) : - 1 , hasArg ( difficulty ) ? intValue ( difficulty ) : - 1 , hasArg ( count ) ? intValue ( count ) - 1 : - 1 ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdVote ( ) {
2020-06-12 18:52:38 +03:00
enum args { alias = 1 , mapid } ;
2019-07-01 21:10:00 +03:00
if ( ! hasArg ( mapid ) ) {
2019-07-27 17:36:24 +03:00
return BotCommandResult : : BadFormat ;
2019-07-01 21:10:00 +03:00
}
2023-06-24 02:36:51 +03:00
const int mapID = intValue ( mapid ) ;
2019-07-01 21:10:00 +03:00
// loop through all players
2019-07-27 17:36:24 +03:00
for ( const auto & bot : bots ) {
bot - > m_voteMap = mapID ;
2019-07-01 21:10:00 +03:00
}
2019-11-30 23:18:37 +03:00
msg ( " All dead bots will vote for map #%d. " , mapID ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdWeaponMode ( ) {
2020-06-12 18:52:38 +03:00
enum args { alias = 1 , type } ;
2019-07-01 21:10:00 +03:00
if ( ! hasArg ( type ) ) {
2019-07-27 17:36:24 +03:00
return BotCommandResult : : BadFormat ;
2019-07-01 21:10:00 +03:00
}
2023-06-24 02:36:51 +03:00
static HashMap < String , int > modes {
{ " knife " , 1 } ,
{ " pistol " , 2 } ,
{ " shotgun " , 3 } ,
{ " smg " , 4 } ,
{ " rifle " , 5 } ,
{ " sniper " , 6 } ,
{ " standard " , 7 }
} ;
2020-06-12 18:52:38 +03:00
auto mode = strValue ( type ) ;
2019-07-01 21:10:00 +03:00
// check if selected mode exists
2023-04-15 04:10:09 +03:00
if ( ! modes . exists ( mode ) ) {
2019-07-27 17:36:24 +03:00
return BotCommandResult : : BadFormat ;
2019-07-01 21:10:00 +03:00
}
bots . setWeaponMode ( modes [ mode ] ) ;
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdVersion ( ) {
2023-06-24 02:36:51 +03:00
const auto & build = product . build ;
2019-08-24 12:43:42 +03:00
2020-10-07 10:25:31 +03:00
msg ( " %s v%s (ID %s) " , product . name , product . version , build . id ) ;
2020-06-12 18:52:38 +03:00
msg ( " by %s (%s) " , product . author , product . email ) ;
msg ( " %s " , product . url ) ;
msg ( " compiled: %s on %s with %s " , product . dtime , build . machine , build . compiler ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeMenu ( ) {
2020-06-12 18:52:38 +03:00
enum args { alias = 1 } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// graph editor is available only with editor
if ( ! graph . hasEditor ( ) ) {
msg ( " Unable to open graph editor without setting the editor player. " ) ;
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage1 ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdMenu ( ) {
2020-06-12 18:52:38 +03:00
enum args { alias = 1 , cmd } ;
2019-07-01 21:10:00 +03:00
// reset the current menu
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
2020-06-12 18:52:38 +03:00
if ( strValue ( cmd ) = = " cmd " & & util . isAlive ( m_ent ) ) {
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Commands ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Main ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdList ( ) {
2020-06-12 18:52:38 +03:00
enum args { alias = 1 } ;
2019-07-01 21:10:00 +03:00
bots . listBots ( ) ;
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-08-24 12:43:42 +03:00
int BotControl : : cmdCvars ( ) {
2020-06-12 18:52:38 +03:00
enum args { alias = 1 , pattern } ;
2019-08-24 12:43:42 +03:00
2024-01-19 00:03:45 +03:00
auto match = strValue ( pattern ) ;
// revert all the cvars to their default values
if ( match = = " defaults " ) {
msg ( " Bots cvars has been reverted to their default values. " ) ;
for ( const auto & cvar : game . getCvars ( ) ) {
if ( ! cvar . self | | ! cvar . self - > ptr | | cvar . type = = Var : : GameRef ) {
continue ;
}
// set depending on cvar type
if ( cvar . bounded ) {
cvar . self - > set ( cvar . initial ) ;
}
else {
cvar . self - > set ( cvar . init . chars ( ) ) ;
}
}
cv_quota . revert ( ) ; // quota should be reverted instead of regval
return BotCommandResult : : Handled ;
}
2023-07-03 11:38:52 +03:00
const bool isSaveMain = match = = " save " ;
const bool isSaveMap = match = = " save_map " ;
const bool isSave = isSaveMain | | isSaveMap ;
2019-08-24 12:43:42 +03:00
File cfg ;
2023-05-12 20:00:06 +03:00
// if save requested, dump cvars to main config
2019-08-24 12:43:42 +03:00
if ( isSave ) {
2023-12-20 00:06:45 +03:00
auto cfgPath = strings . joinPath ( bstor . getRunningPath ( ) , folders . config , strings . format ( " %s.%s " , product . nameLower , kConfigExtension ) ) ;
2023-07-03 11:38:52 +03:00
if ( isSaveMap ) {
2023-12-20 00:06:45 +03:00
cfgPath = strings . joinPath ( bstor . getRunningPath ( ) , folders . config , " maps " , strings . format ( " %s.%s " , game . getMapName ( ) , kConfigExtension ) ) ;
2023-07-03 11:38:52 +03:00
}
cfg . open ( cfgPath , " wt " ) ;
2020-06-12 18:52:38 +03:00
cfg . puts ( " // Configuration file for %s \n \n " , product . name ) ;
2019-08-24 12:43:42 +03:00
}
2020-10-13 15:43:25 +03:00
else {
ctrl . setRapidOutput ( true ) ;
}
2019-08-24 12:43:42 +03:00
for ( const auto & cvar : game . getCvars ( ) ) {
2023-06-14 19:36:46 +03:00
if ( cvar . info . empty ( ) | | ! cvar . self | | ! cvar . self - > ptr ) {
2019-08-24 12:43:42 +03:00
continue ;
}
2020-06-12 18:52:38 +03:00
if ( ! isSave & & ! match . empty ( ) & & ! strstr ( cvar . reg . name , match . chars ( ) ) ) {
2019-08-24 12:43:42 +03:00
continue ;
}
2023-07-03 11:38:52 +03:00
// prevent crash if file not accessible
if ( isSave & & ! cfg ) {
continue ;
}
2023-06-20 15:18:35 +03:00
auto val = cvar . self - > str ( ) ;
2019-08-24 12:43:42 +03:00
// float value ?
2023-06-20 15:18:35 +03:00
bool isFloat = ! val . empty ( ) & & val . find ( " . " ) ! = StringRef : : InvalidIndex ;
2019-08-24 12:43:42 +03:00
if ( isSave ) {
cfg . puts ( " // \n " ) ;
2020-06-12 18:52:38 +03:00
cfg . puts ( " // %s \n " , String : : join ( cvar . info . split ( " \n " ) , " \n // " ) ) ;
2019-08-24 12:43:42 +03:00
cfg . puts ( " // --- \n " ) ;
if ( cvar . bounded ) {
if ( isFloat ) {
cfg . puts ( " // Default: \" %.1f \" , Min: \" %.1f \" , Max: \" %.1f \" \n " , cvar . initial , cvar . min , cvar . max ) ;
}
else {
cfg . puts ( " // Default: \" %i \" , Min: \" %i \" , Max: \" %i \" \n " , static_cast < int > ( cvar . initial ) , static_cast < int > ( cvar . min ) , static_cast < int > ( cvar . max ) ) ;
}
}
else {
cfg . puts ( " // Default: \" %s \" \n " , cvar . self - > str ( ) ) ;
}
cfg . puts ( " // \n " ) ;
if ( cvar . bounded ) {
if ( isFloat ) {
cfg . puts ( " %s \" %.1f \" \n " , cvar . reg . name , cvar . self - > float_ ( ) ) ;
}
else {
cfg . puts ( " %s \" %i \" \n " , cvar . reg . name , cvar . self - > int_ ( ) ) ;
}
}
else {
cfg . puts ( " %s \" %s \" \n " , cvar . reg . name , cvar . self - > str ( ) ) ;
}
cfg . puts ( " \n " ) ;
}
else {
2020-10-23 19:46:16 +06:00
msg ( " name: %s " , cvar . reg . name ) ;
2020-10-12 20:59:48 +03:00
msg ( " info: %s " , conf . translate ( cvar . info ) ) ;
2019-08-24 12:43:42 +03:00
2020-10-12 20:59:48 +03:00
msg ( " " ) ;
2019-08-24 12:43:42 +03:00
}
}
2020-10-13 15:43:25 +03:00
ctrl . setRapidOutput ( false ) ;
2019-08-24 12:43:42 +03:00
if ( isSave ) {
2023-07-03 11:38:52 +03:00
if ( ! cfg ) {
2023-08-08 11:48:37 +03:00
msg ( " Unable to write cvars to config file. File not accessible " ) ;
2023-07-03 11:38:52 +03:00
return BotCommandResult : : Handled ;
}
2019-11-30 23:18:37 +03:00
msg ( " Bots cvars has been written to file. " ) ;
2019-08-24 12:43:42 +03:00
cfg . close ( ) ;
}
return BotCommandResult : : Handled ;
}
2020-12-15 15:28:58 +03:00
int BotControl : : cmdShowCustom ( ) {
enum args { alias = 1 } ;
conf . showCustomValues ( ) ;
return BotCommandResult : : Handled ;
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNode ( ) {
2020-06-12 18:52:38 +03:00
enum args { root , alias , cmd , cmd2 } ;
2019-07-01 21:10:00 +03:00
2020-07-11 20:34:26 +03:00
static Array < StringRef > allowedOnDedicatedServer {
" acquire_editor " ,
" upload " ,
" save " ,
2020-08-31 14:30:09 +03:00
" load " ,
2021-11-16 14:12:09 +03:00
" help " ,
2022-09-21 14:47:36 +03:00
" erase " ,
" fileinfo "
2020-07-11 20:34:26 +03:00
} ;
// check if cmd is allowed on dedicated server
auto isAllowedOnDedicatedServer = [ ] ( StringRef str ) - > bool {
for ( const auto & test : allowedOnDedicatedServer ) {
if ( test = = str ) {
return true ;
}
}
return false ;
} ;
2019-07-27 17:36:24 +03:00
// graph editor supported only with editor
2020-07-11 20:34:26 +03:00
if ( game . isDedicated ( ) & & ! graph . hasEditor ( ) & & ! isAllowedOnDedicatedServer ( strValue ( cmd ) ) ) {
2019-07-27 17:36:24 +03:00
msg ( " Unable to use graph edit commands without setting graph editor player. Please use \" graph acquire_editor \" to acquire rights for graph editing. " ) ;
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
// should be moved to class?
2020-06-15 22:36:11 +03:00
static HashMap < String , BotCmd > commands ;
2019-07-27 17:36:24 +03:00
static StringArray descriptions ;
2019-07-01 21:10:00 +03:00
// fill only once
if ( descriptions . empty ( ) ) {
// separate function
2020-06-12 18:52:38 +03:00
auto addGraphCmd = [ & ] ( String cmd , String format , String help , Handler handler ) - > void {
BotCmd botCmd { cmd , cr : : move ( format ) , cr : : move ( help ) , cr : : move ( handler ) } ;
2019-07-27 17:36:24 +03:00
2020-06-15 22:36:11 +03:00
commands [ cmd ] = cr : : move ( botCmd ) ;
2019-07-01 21:10:00 +03:00
descriptions . push ( cmd ) ;
} ;
2019-07-27 17:36:24 +03:00
// add graph commands
2020-06-12 18:52:38 +03:00
addGraphCmd ( " on " , " on [display|auto|noclip|models] " , " Enables displaying of graph, nodes, noclip cheat " , & BotControl : : cmdNodeOn ) ;
addGraphCmd ( " off " , " off [display|auto|noclip|models] " , " Disables displaying of graph, auto adding nodes, noclip cheat " , & BotControl : : cmdNodeOff ) ;
2020-08-24 13:49:54 +06:00
addGraphCmd ( " menu " , " menu [noarguments] " , " Opens and displays bots graph editor. " , & BotControl : : cmdNodeMenu ) ;
2020-06-12 18:52:38 +03:00
addGraphCmd ( " add " , " add [noarguments] " , " Opens and displays graph node add menu. " , & BotControl : : cmdNodeAdd ) ;
addGraphCmd ( " addbasic " , " menu [noarguments] " , " Adds basic nodes such as player spawn points, goals and ladders. " , & BotControl : : cmdNodeAddBasic ) ;
addGraphCmd ( " save " , " save [noarguments] " , " Save graph file to disk. " , & BotControl : : cmdNodeSave ) ;
addGraphCmd ( " load " , " load [noarguments] " , " Load graph file from disk. " , & BotControl : : cmdNodeLoad ) ;
addGraphCmd ( " erase " , " erase [iamsure] " , " Erases the graph file from disk. " , & BotControl : : cmdNodeErase ) ;
addGraphCmd ( " delete " , " delete [nearest|index] " , " Deletes single graph node from map. " , & BotControl : : cmdNodeDelete ) ;
addGraphCmd ( " check " , " check [noarguments] " , " Check if graph working correctly. " , & BotControl : : cmdNodeCheck ) ;
addGraphCmd ( " cache " , " cache [nearest|index] " , " Caching node for future use. " , & BotControl : : cmdNodeCache ) ;
addGraphCmd ( " clean " , " clean [all|nearest|index] " , " Clean useless path connections from all or single node. " , & BotControl : : cmdNodeClean ) ;
addGraphCmd ( " setradius " , " setradius [radius] [nearest|index] " , " Sets the radius for node. " , & BotControl : : cmdNodeSetRadius ) ;
addGraphCmd ( " flags " , " flags [noarguments] " , " Open and displays menu for modifying flags for nearest point. " , & BotControl : : cmdNodeSetFlags ) ;
addGraphCmd ( " teleport " , " teleport [index] " , " Teleports player to specified node index. " , & BotControl : : cmdNodeTeleport ) ;
2020-10-08 15:25:19 +03:00
addGraphCmd ( " upload " , " upload " , " Uploads created graph to graph database. " , & BotControl : : cmdNodeUpload ) ;
addGraphCmd ( " stats " , " stats [noarguments] " , " Shows the stats about node types on the map. " , & BotControl : : cmdNodeShowStats ) ;
2022-09-21 14:47:36 +03:00
addGraphCmd ( " fileinfo " , " fileinfo [noarguments] " , " Shows basic information about graph file. " , & BotControl : : cmdNodeFileInfo ) ;
2022-12-22 21:32:45 +03:00
addGraphCmd ( " adjust_height " , " adjust_height [height offset] " , " Modifies all the graph nodes height (z-component) with specified offset. " , & BotControl : : cmdAdjustHeight ) ;
2019-07-01 21:10:00 +03:00
// add path commands
2020-06-12 18:52:38 +03:00
addGraphCmd ( " path_create " , " path_create [noarguments] " , " Opens and displays path creation menu. " , & BotControl : : cmdNodePathCreate ) ;
2020-11-02 20:12:52 +06:00
addGraphCmd ( " path_create_in " , " path_create_in [noarguments] " , " Creates incoming path connection from faced to nearest node. " , & BotControl : : cmdNodePathCreate ) ;
addGraphCmd ( " path_create_out " , " path_create_out [noarguments] " , " Creates outgoing path connection from nearest to faced node. " , & BotControl : : cmdNodePathCreate ) ;
addGraphCmd ( " path_create_both " , " path_create_both [noarguments] " , " Creates both-ways path connection between faced and nearest node. " , & BotControl : : cmdNodePathCreate ) ;
2023-05-13 00:19:07 +06:00
addGraphCmd ( " path_create_jump " , " path_create_jump [noarguments] " , " Creates jumping path connection from nearest to faced node. " , & BotControl : : cmdNodePathCreate ) ;
2020-11-02 20:12:52 +06:00
addGraphCmd ( " path_delete " , " path_delete [noarguments] " , " Deletes path from nearest to faced node. " , & BotControl : : cmdNodePathDelete ) ;
2020-08-24 12:56:26 +06:00
addGraphCmd ( " path_set_autopath " , " path_set_autopath [max_distance] " , " Opens menu for setting autopath maximum distance. " , & BotControl : : cmdNodePathSetAutoDistance ) ;
2023-08-14 20:36:01 +00:00
addGraphCmd ( " path_clean " , " path_clean [index] " , " Clears connections of all types from the node. " , & BotControl : : cmdNodePathCleanAll ) ;
2019-07-27 17:36:24 +03:00
2019-08-30 10:52:31 +03:00
// camp points iterator
2020-06-12 18:52:38 +03:00
addGraphCmd ( " iterate_camp " , " iterate_camp [begin|end|next] " , " Allows to go through all camp points on map. " , & BotControl : : cmdNodeIterateCamp ) ;
2019-08-30 10:52:31 +03:00
2019-07-27 17:36:24 +03:00
// remote graph editing stuff
2019-07-01 21:10:00 +03:00
if ( game . isDedicated ( ) ) {
2020-11-02 20:12:52 +06:00
addGraphCmd ( " acquire_editor " , " acquire_editor [noarguments] " , " Acquires rights to edit graph on dedicated server. " , & BotControl : : cmdNodeAcquireEditor ) ;
2020-10-08 15:25:19 +03:00
addGraphCmd ( " release_editor " , " release_editor [noarguments] " , " Releases graph editing rights. " , & BotControl : : cmdNodeReleaseEditor ) ;
2019-07-01 21:10:00 +03:00
}
}
2023-04-15 04:10:09 +03:00
if ( commands . exists ( strValue ( cmd ) ) ) {
2021-09-16 16:09:51 +03:00
const auto & item = commands [ strValue ( cmd ) ] ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// graph have only bad format return status
2019-07-01 21:10:00 +03:00
int status = ( this - > * item . handler ) ( ) ;
2019-07-27 17:36:24 +03:00
if ( status = = BotCommandResult : : BadFormat ) {
2020-09-02 18:10:54 +06:00
msg ( " Incorrect usage of \" %s %s %s \" command. Correct usage is: " , m_args [ root ] , m_args [ alias ] , item . name ) ;
msg ( " \n \t %s \n " , item . format ) ;
msg ( " Please use correct format. " ) ;
2019-07-01 21:10:00 +03:00
}
}
else {
2023-04-15 04:10:09 +03:00
if ( strValue ( cmd ) = = " help " & & hasArg ( cmd2 ) & & commands . exists ( strValue ( cmd2 ) ) ) {
2020-06-12 18:52:38 +03:00
auto & item = commands [ strValue ( cmd2 ) ] ;
2019-07-01 21:10:00 +03:00
2020-09-11 16:01:33 +03:00
msg ( " Command: \" %s %s %s \" " , m_args [ root ] , m_args [ alias ] , item . name ) ;
msg ( " Format: %s " , item . format ) ;
msg ( " Help: %s " , conf . translate ( item . help ) ) ;
2019-07-01 21:10:00 +03:00
}
else {
for ( auto & desc : descriptions ) {
auto & item = commands [ desc ] ;
2020-08-22 17:01:16 +03:00
msg ( " %s - %s " , item . name , conf . translate ( item . help ) ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
msg ( " Currently Graph Status %s " , graph . hasEditFlag ( GraphEdit : : On ) ? " Enabled " : " Disabled " ) ;
2019-07-01 21:10:00 +03:00
}
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeOn ( ) {
2020-06-12 18:52:38 +03:00
enum args { alias = 1 , cmd , option } ;
2019-07-01 21:10:00 +03:00
// enable various features of editor
2020-06-12 18:52:38 +03:00
if ( strValue ( option ) . empty ( ) | | strValue ( option ) = = " display " | | strValue ( option ) = = " models " ) {
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
enableDrawModels ( true ) ;
2019-07-27 17:36:24 +03:00
msg ( " Graph editor has been enabled. " ) ;
2019-07-01 21:10:00 +03:00
}
2020-06-12 18:52:38 +03:00
else if ( strValue ( option ) = = " noclip " ) {
2019-07-01 21:10:00 +03:00
m_ent - > v . movetype = MOVETYPE_NOCLIP ;
2023-04-20 10:56:37 +00:00
if ( graph . hasEditFlag ( GraphEdit : : On ) ) {
graph . setEditFlag ( GraphEdit : : Noclip ) ;
2019-07-01 21:10:00 +03:00
2023-04-20 10:56:37 +00:00
msg ( " Noclip mode enabled. " ) ;
}
else {
graph . setEditFlag ( GraphEdit : : On | GraphEdit : : Noclip ) ;
enableDrawModels ( true ) ;
msg ( " Graph editor has been enabled with noclip mode. " ) ;
}
2019-07-01 21:10:00 +03:00
}
2020-06-12 18:52:38 +03:00
else if ( strValue ( option ) = = " auto " ) {
2023-04-20 10:56:37 +00:00
if ( graph . hasEditFlag ( GraphEdit : : On ) ) {
graph . setEditFlag ( GraphEdit : : Auto ) ;
2019-07-01 21:10:00 +03:00
2023-04-20 10:56:37 +00:00
msg ( " Enabled auto nodes placement. " ) ;
}
else {
graph . setEditFlag ( GraphEdit : : On | GraphEdit : : Auto ) ;
enableDrawModels ( true ) ;
msg ( " Graph editor has been enabled with auto add node mode. " ) ;
}
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
if ( graph . hasEditFlag ( GraphEdit : : On ) ) {
2019-07-01 21:10:00 +03:00
mp_roundtime . set ( 9 ) ;
mp_freezetime . set ( 0 ) ;
mp_timelimit . set ( 0 ) ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeOff ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd , option } ;
2019-07-01 21:10:00 +03:00
// enable various features of editor
2020-06-12 18:52:38 +03:00
if ( strValue ( option ) . empty ( ) | | strValue ( option ) = = " display " ) {
2019-07-27 17:36:24 +03:00
graph . clearEditFlag ( GraphEdit : : On | GraphEdit : : Auto | GraphEdit : : Noclip ) ;
2019-07-01 21:10:00 +03:00
enableDrawModels ( false ) ;
2019-07-27 17:36:24 +03:00
msg ( " Graph editor has been disabled. " ) ;
2019-07-01 21:10:00 +03:00
}
2020-06-12 18:52:38 +03:00
else if ( strValue ( option ) = = " models " ) {
2019-07-01 21:10:00 +03:00
enableDrawModels ( false ) ;
2019-07-27 17:36:24 +03:00
msg ( " Graph editor has disabled spawn points highlighting. " ) ;
2019-07-01 21:10:00 +03:00
}
2020-06-12 18:52:38 +03:00
else if ( strValue ( option ) = = " noclip " ) {
2019-07-01 21:10:00 +03:00
m_ent - > v . movetype = MOVETYPE_WALK ;
2019-07-27 17:36:24 +03:00
graph . clearEditFlag ( GraphEdit : : Noclip ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
msg ( " Graph editor has disabled noclip mode. " ) ;
2019-07-01 21:10:00 +03:00
}
2020-06-12 18:52:38 +03:00
else if ( strValue ( option ) = = " auto " ) {
2019-07-27 17:36:24 +03:00
graph . clearEditFlag ( GraphEdit : : Auto ) ;
msg ( " Graph editor has disabled auto add node mode. " ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeAdd ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
// show the menu
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeType ) ;
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeAddBasic ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd } ;
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
graph . addBasic ( ) ;
msg ( " Basic graph nodes was added. " ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeSave ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd , option } ;
2019-07-01 21:10:00 +03:00
// if no check is set save anyway
2020-06-12 18:52:38 +03:00
if ( strValue ( option ) = = " nocheck " ) {
2019-07-27 17:36:24 +03:00
graph . saveGraphData ( ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
msg ( " All nodes has been saved and written to disk (IGNORING QUALITY CONTROL). " ) ;
}
2023-05-12 20:00:06 +03:00
else if ( strValue ( option ) = = " old " | | strValue ( option ) = = " oldformat " ) {
2020-10-22 14:40:24 +03:00
if ( graph . length ( ) > = 1024 ) {
msg ( " Unable to save POD-Bot Format waypoint file. Number of nodes exceeds 1024. " ) ;
return BotCommandResult : : Handled ;
}
2019-07-27 17:36:24 +03:00
graph . saveOldFormat ( ) ;
msg ( " All nodes has been saved and written to disk (POD-Bot Format (.pwf)). " ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-07-27 17:36:24 +03:00
if ( graph . checkNodes ( false ) ) {
graph . saveGraphData ( ) ;
2023-04-02 12:17:12 +03:00
msg ( " All nodes has been saved and written to disk. \n *** Please don't forget to share your work by typing \" %s g upload \" . Thank you! *** " , product . cmdPri ) ;
2019-07-01 21:10:00 +03:00
}
else {
2023-05-24 23:41:23 +03:00
msg ( " Could not save nodes to disk. Graph check has failed. " ) ;
2019-07-01 21:10:00 +03:00
}
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeLoad ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// just save graph on request
if ( graph . loadGraphData ( ) ) {
msg ( " Graph successfully loaded. " ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-07-27 17:36:24 +03:00
msg ( " Could not load Graph. See console... " ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeErase ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd , iamsure } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// prevent accidents when graph are deleted unintentionally
2020-06-12 18:52:38 +03:00
if ( strValue ( iamsure ) = = " iamsure " ) {
2023-05-02 09:42:43 +03:00
bstor . unlinkFromDisk ( ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-07-27 17:36:24 +03:00
msg ( " Please, append \" iamsure \" as parameter to get graph erased from the disk. " ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeDelete ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd , nearest } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
2022-01-04 01:29:07 +06:00
// if "nearest" or nothing passed delete nearest, else delete by index
2020-06-12 18:52:38 +03:00
if ( strValue ( nearest ) . empty ( ) | | strValue ( nearest ) = = " nearest " ) {
2019-07-27 17:36:24 +03:00
graph . erase ( kInvalidNodeIndex ) ;
2019-07-01 21:10:00 +03:00
}
else {
2020-06-12 18:52:38 +03:00
int index = intValue ( nearest ) ;
2019-07-01 21:10:00 +03:00
// check for existence
2019-07-27 17:36:24 +03:00
if ( graph . exists ( index ) ) {
graph . erase ( index ) ;
2020-08-24 12:56:26 +06:00
msg ( " Node %d has been deleted. " , index ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-11-30 23:18:37 +03:00
msg ( " Could not delete node %d. " , index ) ;
2019-07-01 21:10:00 +03:00
}
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeCheck ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd } ;
2019-07-01 21:10:00 +03:00
// check if nodes are ok
2019-07-27 17:36:24 +03:00
if ( graph . checkNodes ( true ) ) {
msg ( " Graph seems to be OK. " ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeCache ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd , nearest } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
2023-01-22 19:12:03 +06:00
// if "nearest" or nothing passed delete nearest, else delete by index
2020-06-12 18:52:38 +03:00
if ( strValue ( nearest ) . empty ( ) | | strValue ( nearest ) = = " nearest " ) {
2019-07-27 17:36:24 +03:00
graph . cachePoint ( kInvalidNodeIndex ) ;
2019-07-01 21:10:00 +03:00
}
else {
2023-06-24 02:36:51 +03:00
const int index = intValue ( nearest ) ;
2019-07-01 21:10:00 +03:00
// check for existence
2019-07-27 17:36:24 +03:00
if ( graph . exists ( index ) ) {
graph . cachePoint ( index ) ;
2019-07-01 21:10:00 +03:00
}
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeClean ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd , option } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
// if "all" passed clean up all the paths
2020-06-12 18:52:38 +03:00
if ( strValue ( option ) = = " all " ) {
2019-07-01 21:10:00 +03:00
int removed = 0 ;
2023-04-11 22:32:28 +03:00
for ( auto i = 0 ; i < graph . length ( ) ; + + i ) {
2019-07-27 17:36:24 +03:00
removed + = graph . clearConnections ( i ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
msg ( " Done. Processed %d nodes. %d useless paths was cleared. " , graph . length ( ) , removed ) ;
2019-07-01 21:10:00 +03:00
}
2020-06-12 18:52:38 +03:00
else if ( strValue ( option ) . empty ( ) | | strValue ( option ) = = " nearest " ) {
2023-01-22 19:12:03 +06:00
int removed = graph . clearConnections ( graph . getEditorNearest ( ) ) ;
2019-07-01 21:10:00 +03:00
2023-01-22 19:12:03 +06:00
msg ( " Done. Processed node %d. %d useless paths was cleared. " , graph . getEditorNearest ( ) , removed ) ;
2019-07-01 21:10:00 +03:00
}
else {
2023-06-24 02:36:51 +03:00
const int index = intValue ( option ) ;
2019-07-01 21:10:00 +03:00
// check for existence
2019-07-27 17:36:24 +03:00
if ( graph . exists ( index ) ) {
2023-06-24 02:36:51 +03:00
const int removed = graph . clearConnections ( index ) ;
2019-07-01 21:10:00 +03:00
2019-11-30 23:18:37 +03:00
msg ( " Done. Processed node %d. %d useless paths was cleared. " , index , removed ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-11-30 23:18:37 +03:00
msg ( " Could not process node %d clearance. " , index ) ;
2019-07-01 21:10:00 +03:00
}
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeSetRadius ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd , radius , index } ;
2019-07-01 21:10:00 +03:00
// radius is a must
if ( ! hasArg ( radius ) ) {
2019-07-27 17:36:24 +03:00
return BotCommandResult : : BadFormat ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int radiusIndex = kInvalidNodeIndex ;
2019-07-01 21:10:00 +03:00
2020-06-12 18:52:38 +03:00
if ( strValue ( index ) . empty ( ) | | strValue ( index ) = = " nearest " ) {
2023-01-22 19:12:03 +06:00
radiusIndex = graph . getEditorNearest ( ) ;
2019-07-01 21:10:00 +03:00
}
else {
2020-06-12 18:52:38 +03:00
radiusIndex = intValue ( index ) ;
2019-07-01 21:10:00 +03:00
}
2020-08-22 01:38:59 +03:00
graph . setRadius ( radiusIndex , strValue ( radius ) . float_ ( ) ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeSetFlags ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
//show the flag menu
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeFlag ) ;
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeTeleport ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd , teleport_index } ;
2019-07-01 21:10:00 +03:00
if ( ! hasArg ( teleport_index ) ) {
2019-07-27 17:36:24 +03:00
return BotCommandResult : : BadFormat ;
2019-07-01 21:10:00 +03:00
}
2020-06-12 18:52:38 +03:00
int index = intValue ( teleport_index ) ;
2019-07-01 21:10:00 +03:00
// check for existence
2019-07-27 17:36:24 +03:00
if ( graph . exists ( index ) ) {
engfuncs . pfnSetOrigin ( graph . getEditor ( ) , graph [ index ] . origin ) ;
2019-07-01 21:10:00 +03:00
2019-11-30 23:18:37 +03:00
msg ( " You have been teleported to node %d. " , index ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On | GraphEdit : : Noclip ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-11-30 23:18:37 +03:00
msg ( " Could not teleport to node %d. " , index ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodePathCreate ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
// choose the direction for path creation
2023-05-13 00:19:07 +06:00
if ( strValue ( cmd ) . endsWith ( " _jump " ) ) {
graph . pathCreate ( PathConnection : : Jumping ) ;
}
else if ( strValue ( cmd ) . endsWith ( " _both " ) ) {
2019-07-27 17:36:24 +03:00
graph . pathCreate ( PathConnection : : Bidirectional ) ;
2019-07-01 21:10:00 +03:00
}
aim: verify camp angles from nav data before using them
aim: tweaked a bit grenade handling, so bots should use them more
aim: reduce time between selecting grenade and throwing it away
aim: removed hacks in look angles code, due to removing yb_whoose_your_daddy cvar
aim: use direct enemy origin from visibility check, and not re-calculate it
aim: update enemy prediction, so it now depends on frame interval for a bot
aim: additional height offset are tweaked, and now used only for difficulty 4
nav: tweaked a bit player avoidance code, and it's not preventing bot from checking terrain
nav: do not check banned nodes, when bucket sizes re too low
nav: cover nodes are now selected depending on total bots on server
nav: let bot enter pause task after long jump
nav: extend velocity by a little for a jump, like it was in first versions of bot
nav: stuck checking is now taken in account lower minimal speed if bot is ducking
fix: navigation reachability timers, so bots will have correct current node index while camping
fix: bots are unable to finish pickup or destroy breakable task, if target is not reachable
fix: cover nodes are now calculated as they should
fix: manual calling bots add_[t/ct] now ignores yb_join_team cvar
bot: tweaked a little difficulty levels, so level 4 is now nightmare level, and 3 is very heard
bot: minor refactoring and moving functions to correct source file
bot: add yb_economics_disrespect_percent, so bots can ignore economics and buy more different guns
bot: add yb_check_darkness that allows to disable darkness checks for bot, thus disallowing usage of flashlight
bot: camp buttons are now lightly depends on bot health
chat: welcome chat message from bots is now sent during first freeze time period
crlib: switch over to stdint.h and remove crlib-own types
crlib: fixed alignment in sse code
2023-04-07 14:46:49 +03:00
else if ( strValue ( cmd ) . endsWith ( " _in " ) ) {
2019-07-27 17:36:24 +03:00
graph . pathCreate ( PathConnection : : Incoming ) ;
2019-07-01 21:10:00 +03:00
}
aim: verify camp angles from nav data before using them
aim: tweaked a bit grenade handling, so bots should use them more
aim: reduce time between selecting grenade and throwing it away
aim: removed hacks in look angles code, due to removing yb_whoose_your_daddy cvar
aim: use direct enemy origin from visibility check, and not re-calculate it
aim: update enemy prediction, so it now depends on frame interval for a bot
aim: additional height offset are tweaked, and now used only for difficulty 4
nav: tweaked a bit player avoidance code, and it's not preventing bot from checking terrain
nav: do not check banned nodes, when bucket sizes re too low
nav: cover nodes are now selected depending on total bots on server
nav: let bot enter pause task after long jump
nav: extend velocity by a little for a jump, like it was in first versions of bot
nav: stuck checking is now taken in account lower minimal speed if bot is ducking
fix: navigation reachability timers, so bots will have correct current node index while camping
fix: bots are unable to finish pickup or destroy breakable task, if target is not reachable
fix: cover nodes are now calculated as they should
fix: manual calling bots add_[t/ct] now ignores yb_join_team cvar
bot: tweaked a little difficulty levels, so level 4 is now nightmare level, and 3 is very heard
bot: minor refactoring and moving functions to correct source file
bot: add yb_economics_disrespect_percent, so bots can ignore economics and buy more different guns
bot: add yb_check_darkness that allows to disable darkness checks for bot, thus disallowing usage of flashlight
bot: camp buttons are now lightly depends on bot health
chat: welcome chat message from bots is now sent during first freeze time period
crlib: switch over to stdint.h and remove crlib-own types
crlib: fixed alignment in sse code
2023-04-07 14:46:49 +03:00
else if ( strValue ( cmd ) . endsWith ( " _out " ) ) {
2019-07-27 17:36:24 +03:00
graph . pathCreate ( PathConnection : : Outgoing ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodePath ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodePathDelete ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
2022-01-04 01:29:07 +06:00
// delete the path
2019-07-27 17:36:24 +03:00
graph . erasePath ( ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodePathSetAutoDistance ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
showMenu ( Menu : : NodeAutoPath ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2023-08-08 11:48:37 +03:00
int BotControl : : cmdNodePathCleanAll ( ) {
enum args { graph_cmd = 1 , cmd , index } ;
auto requestedNode = kInvalidNodeIndex ;
if ( hasArg ( index ) ) {
requestedNode = intValue ( index ) ;
}
graph . resetPath ( requestedNode ) ;
return BotCommandResult : : Handled ;
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeAcquireEditor ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 } ;
2019-07-01 21:10:00 +03:00
if ( game . isNullEntity ( m_ent ) ) {
msg ( " This command should not be executed from HLDS console. " ) ;
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
if ( graph . hasEditor ( ) ) {
2019-09-14 23:13:55 +03:00
msg ( " Sorry, players \" %s \" already acquired rights to edit graph on this server. " , graph . getEditor ( ) - > v . netname . chars ( ) ) ;
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
graph . setEditor ( m_ent ) ;
msg ( " You're acquired rights to edit graph on this server. You're now able to use graph commands. " ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : cmdNodeReleaseEditor ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 } ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
if ( ! graph . hasEditor ( ) ) {
2019-07-01 21:10:00 +03:00
msg ( " No one is currently has rights to edit. Nothing to release. " ) ;
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
graph . setEditor ( nullptr ) ;
msg ( " Graph editor rights freed. You're now not able to use graph commands. " ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
}
int BotControl : : cmdNodeUpload ( ) {
2020-04-12 17:41:42 +03:00
enum args { graph_cmd = 1 , cmd } ;
2019-07-27 17:36:24 +03:00
2023-05-02 09:42:43 +03:00
// do not allow to upload analyzed graphs
if ( graph . isAnalyzed ( ) ) {
msg ( " Sorry, unable to upload graph that was generated automatically. " ) ;
return BotCommandResult : : Handled ;
}
2019-07-27 17:36:24 +03:00
// do not allow to upload bad graph
if ( ! graph . checkNodes ( false ) ) {
2023-05-24 23:41:23 +03:00
msg ( " Sorry, unable to upload graph file that contains errors. Please type \" graph check \" to verify graph consistency. " ) ;
2023-05-02 09:42:43 +03:00
return BotCommandResult : : Handled ;
2019-07-27 17:36:24 +03:00
}
2023-07-18 15:59:15 +03:00
String uploadUrlAddress = cv_graph_url_upload . str ( ) ;
// only allow to upload to non-https endpoint
2024-01-30 14:37:14 +03:00
if ( uploadUrlAddress . startsWith ( " https " ) ) {
2023-07-18 15:59:15 +03:00
msg ( " Value of \" %s \" cvar should not contain URL scheme, only the host name and path. " , cv_graph_url_upload . name ( ) ) ;
return BotCommandResult : : Handled ;
}
2024-01-30 14:37:14 +03:00
String uploadUrl = strings . format ( " %s://%s " , product . httpScheme , uploadUrlAddress ) ;
2020-04-12 17:41:42 +03:00
2019-07-27 17:36:24 +03:00
msg ( " \n " ) ;
msg ( " WARNING! " ) ;
msg ( " Graph uploaded to graph database in synchronous mode. That means if graph is big enough " ) ;
msg ( " you may notice the game freezes a bit during upload and issue request creation. Please, be patient. " ) ;
msg ( " \n " ) ;
// try to upload the file
2023-05-02 09:42:43 +03:00
if ( http . uploadFile ( uploadUrl , bstor . buildPath ( BotFile : : Graph ) ) ) {
2020-06-12 18:52:38 +03:00
msg ( " Graph file was successfully validated and uploaded to the YaPB Graph DB (%s). " , product . download ) ;
msg ( " It will be available for download for all YaPB users in a few minutes. " ) ;
2019-07-27 17:36:24 +03:00
msg ( " \n " ) ;
msg ( " Thank you. " ) ;
msg ( " \n " ) ;
}
else {
String status ;
auto code = http . getLastStatusCode ( ) ;
if ( code = = HttpClientResult : : Forbidden ) {
status = " AlreadyExists " ;
}
else if ( code = = HttpClientResult : : NotFound ) {
status = " AccessDenied " ;
}
else {
status . assignf ( " %d " , code ) ;
}
2020-06-12 18:52:38 +03:00
msg ( " Something went wrong with uploading. Come back later. (%s) " , status ) ;
2019-07-27 17:36:24 +03:00
msg ( " \n " ) ;
2020-04-12 17:41:42 +03:00
2019-07-27 17:36:24 +03:00
if ( code = = HttpClientResult : : Forbidden ) {
msg ( " You should create issue-request manually for this graph " ) ;
msg ( " as it's already exists in database, can't overwrite. Sorry... " ) ;
}
else {
2020-04-12 17:41:42 +03:00
msg ( " There is an internal error, or something is totally wrong with " ) ;
2019-07-27 17:36:24 +03:00
msg ( " your files, and they are not passed sanity checks. Sorry... " ) ;
}
msg ( " \n " ) ;
}
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-08-30 10:52:31 +03:00
int BotControl : : cmdNodeIterateCamp ( ) {
2020-06-12 18:52:38 +03:00
enum args { graph_cmd = 1 , cmd , option } ;
2019-08-30 10:52:31 +03:00
// turn graph on
graph . setEditFlag ( GraphEdit : : On ) ;
2023-05-24 23:41:23 +03:00
// get the option describing operation
2020-06-12 18:52:38 +03:00
auto op = strValue ( option ) ;
2019-08-30 10:52:31 +03:00
if ( op ! = " begin " & & op ! = " end " & & op ! = " next " ) {
return BotCommandResult : : BadFormat ;
}
2019-08-30 11:10:22 +03:00
if ( ( op = = " next " | | op = = " end " ) & & m_campIterator . empty ( ) ) {
2019-08-30 10:52:31 +03:00
msg ( " Before calling for 'next' / 'end' camp point, you should hit 'begin'. " ) ;
return BotCommandResult : : Handled ;
}
2019-08-30 11:10:22 +03:00
else if ( op = = " begin " & & ! m_campIterator . empty ( ) ) {
2019-08-30 10:52:31 +03:00
msg ( " Before calling for 'begin' camp point, you should hit 'end'. " ) ;
return BotCommandResult : : Handled ;
}
2020-11-03 08:57:12 +03:00
2019-08-30 10:52:31 +03:00
if ( op = = " end " ) {
2019-08-30 11:10:22 +03:00
m_campIterator . clear ( ) ;
2019-08-30 10:52:31 +03:00
}
else if ( op = = " next " ) {
2019-08-30 11:10:22 +03:00
if ( ! m_campIterator . empty ( ) ) {
Vector origin = graph [ m_campIterator . first ( ) ] . origin ;
2019-08-30 10:52:31 +03:00
2019-08-30 11:10:22 +03:00
if ( graph [ m_campIterator . first ( ) ] . flags & NodeFlag : : Crouch ) {
2019-08-30 10:52:31 +03:00
origin . z + = 23.0f ;
}
engfuncs . pfnSetOrigin ( m_ent , origin ) ;
2019-08-30 11:10:22 +03:00
// go to next
m_campIterator . shift ( ) ;
2019-08-30 17:23:28 +03:00
if ( m_campIterator . empty ( ) ) {
msg ( " Finished iterating camp spots. " ) ;
}
2019-08-30 10:52:31 +03:00
}
}
else if ( op = = " begin " ) {
2023-04-11 22:32:28 +03:00
for ( const auto & path : graph ) {
if ( path . flags & NodeFlag : : Camp ) {
m_campIterator . push ( path . number ) ;
2019-08-30 10:52:31 +03:00
}
}
2022-02-18 17:30:29 +06:00
if ( ! m_campIterator . empty ( ) ) {
msg ( " Ready for iteration. Type 'next' to go to first camp node. " ) ;
return BotCommandResult : : Handled ;
}
msg ( " Unable to begin iteration, camp points is not set. " ) ;
2019-08-30 10:52:31 +03:00
}
return BotCommandResult : : Handled ;
}
2020-08-31 14:52:12 +03:00
int BotControl : : cmdNodeShowStats ( ) {
graph . showStats ( ) ;
return BotCommandResult : : Handled ;
}
2022-09-21 14:47:36 +03:00
int BotControl : : cmdNodeFileInfo ( ) {
graph . showFileInfo ( ) ;
return BotCommandResult : : Handled ;
}
2023-03-13 15:39:15 +03:00
int BotControl : : cmdAdjustHeight ( ) {
2022-12-22 21:32:45 +03:00
enum args { graph_cmd = 1 , cmd , offset } ;
if ( ! hasArg ( offset ) ) {
return BotCommandResult : : BadFormat ;
}
auto heightOffset = floatValue ( offset ) ;
// adjust the height for all the nodes (negative values possible)
2023-04-11 22:32:28 +03:00
for ( auto & path : graph ) {
path . origin . z + = heightOffset ;
2022-12-22 21:32:45 +03:00
}
return BotCommandResult : : Handled ;
}
2019-07-01 21:10:00 +03:00
int BotControl : : menuMain ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
m_isMenuFillCommand = false ;
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Control ) ;
2019-07-01 21:10:00 +03:00
break ;
case 2 :
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Features ) ;
2019-07-01 21:10:00 +03:00
break ;
case 3 :
m_isMenuFillCommand = true ;
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : TeamSelect ) ;
2019-07-01 21:10:00 +03:00
break ;
case 4 :
bots . killAllBots ( ) ;
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
default :
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Main ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuFeatures ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
2022-01-31 22:00:07 +03:00
auto autoAcquireEditorRights = [ & ] ( ) {
if ( ! graph . hasEditor ( ) ) {
graph . setEditor ( m_ent ) ;
}
return graph . hasEditor ( ) & & graph . getEditor ( ) = = m_ent ? Menu : : NodeMainPage1 : Menu : : Features ;
} ;
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : WeaponMode ) ;
2019-07-01 21:10:00 +03:00
break ;
case 2 :
2022-01-31 22:00:07 +03:00
showMenu ( autoAcquireEditorRights ( ) ) ;
2019-07-01 21:10:00 +03:00
break ;
case 3 :
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Personality ) ;
2019-07-01 21:10:00 +03:00
break ;
case 4 :
2020-06-12 18:52:38 +03:00
cv_debug . set ( cv_debug . int_ ( ) ^ 1 ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Features ) ;
2019-07-01 21:10:00 +03:00
break ;
case 5 :
if ( util . isAlive ( m_ent ) ) {
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Commands ) ;
2019-07-01 21:10:00 +03:00
}
else {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
msg ( " You're dead, and have no access to this menu " ) ;
}
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuControl ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
bots . createRandom ( true ) ;
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Control ) ;
2019-07-01 21:10:00 +03:00
break ;
case 2 :
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Difficulty ) ;
2019-07-01 21:10:00 +03:00
break ;
case 3 :
bots . kickRandom ( ) ;
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Control ) ;
2019-07-01 21:10:00 +03:00
break ;
case 4 :
bots . kickEveryone ( ) ;
break ;
case 5 :
kickBotByMenu ( 1 ) ;
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuWeaponMode ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
bots . setWeaponMode ( item ) ;
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : WeaponMode ) ;
2019-07-01 21:10:00 +03:00
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuPersonality ( int item ) {
if ( m_isMenuFillCommand ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 3 :
case 4 :
bots . serverFill ( m_menuServerFillTeam , item - 2 , m_interMenuData [ 0 ] ) ;
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 3 :
case 4 :
m_interMenuData [ 3 ] = item - 2 ;
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : TeamSelect ) ;
2019-07-01 21:10:00 +03:00
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuDifficulty ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
m_interMenuData [ 0 ] = 0 ;
break ;
case 2 :
m_interMenuData [ 0 ] = 1 ;
break ;
case 3 :
m_interMenuData [ 0 ] = 2 ;
break ;
case 4 :
m_interMenuData [ 0 ] = 3 ;
break ;
case 5 :
m_interMenuData [ 0 ] = 4 ;
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Personality ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuTeamSelect ( int item ) {
if ( m_isMenuFillCommand ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
if ( item < 3 ) {
// turn off cvars if specified team
mp_limitteams . set ( 0 ) ;
mp_autoteambalance . set ( 0 ) ;
}
switch ( item ) {
case 1 :
case 2 :
case 5 :
m_menuServerFillTeam = item ;
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Difficulty ) ;
2019-07-01 21:10:00 +03:00
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 5 :
m_interMenuData [ 1 ] = item ;
if ( item = = 5 ) {
m_interMenuData [ 2 ] = item ;
bots . addbot ( " " , m_interMenuData [ 0 ] , m_interMenuData [ 3 ] , m_interMenuData [ 1 ] , m_interMenuData [ 2 ] , true ) ;
}
2023-02-07 10:19:40 +00:00
else if ( game . is ( GameFlags : : ConditionZero ) ) {
showMenu ( item = = 1 ? Menu : : TerroristSelectCZ : Menu : : CTSelectCZ ) ;
}
2019-07-01 21:10:00 +03:00
else {
2019-07-27 17:36:24 +03:00
showMenu ( item = = 1 ? Menu : : TerroristSelect : Menu : : CTSelect ) ;
2019-07-01 21:10:00 +03:00
}
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuClassSelect ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
2023-02-07 10:19:40 +00:00
case 6 :
2019-07-01 21:10:00 +03:00
m_interMenuData [ 2 ] = item ;
bots . addbot ( " " , m_interMenuData [ 0 ] , m_interMenuData [ 3 ] , m_interMenuData [ 1 ] , m_interMenuData [ 2 ] , true ) ;
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuCommands ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-08-18 21:00:00 +03:00
Bot * nearest = nullptr ;
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
2023-05-06 20:14:03 +03:00
if ( util . findNearestPlayer ( reinterpret_cast < void * * > ( & m_djump ) , m_ent , 600.0f , true , true , true , true , false ) & & ! m_djump - > m_hasC4 & & ! m_djump - > m_hasHostage ) {
2019-07-01 21:10:00 +03:00
if ( item = = 1 ) {
2019-08-18 21:00:00 +03:00
m_djump - > startDoubleJump ( m_ent ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-08-18 21:00:00 +03:00
if ( m_djump ) {
m_djump - > resetDoubleJump ( ) ;
m_djump = nullptr ;
}
2019-07-01 21:10:00 +03:00
}
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Commands ) ;
2019-07-01 21:10:00 +03:00
break ;
case 3 :
case 4 :
2019-08-18 21:00:00 +03:00
if ( util . findNearestPlayer ( reinterpret_cast < void * * > ( & nearest ) , m_ent , 600.0f , true , true , true , true , item = = 4 ? false : true ) ) {
nearest - > dropWeaponForUser ( m_ent , item = = 4 ? false : true ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Commands ) ;
2019-07-01 21:10:00 +03:00
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : menuGraphPage1 ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
2019-07-27 17:36:24 +03:00
if ( graph . hasEditFlag ( GraphEdit : : On ) ) {
graph . clearEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
enableDrawModels ( false ) ;
2019-07-27 17:36:24 +03:00
msg ( " Graph editor has been disabled. " ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
enableDrawModels ( true ) ;
2019-07-27 17:36:24 +03:00
msg ( " Graph editor has been enabled. " ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage1 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 2 :
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
graph . cachePoint ( kInvalidNodeIndex ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage1 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 3 :
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
showMenu ( Menu : : NodePath ) ;
2019-07-01 21:10:00 +03:00
break ;
case 4 :
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
graph . erasePath ( ) ;
2020-11-03 08:57:12 +03:00
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage1 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 5 :
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
showMenu ( Menu : : NodeType ) ;
2019-07-01 21:10:00 +03:00
break ;
case 6 :
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
graph . erase ( kInvalidNodeIndex ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage1 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 7 :
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
showMenu ( Menu : : NodeAutoPath ) ;
2019-07-01 21:10:00 +03:00
break ;
case 8 :
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
showMenu ( Menu : : NodeRadius ) ;
2019-07-01 21:10:00 +03:00
break ;
case 9 :
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage2 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : menuGraphPage2 ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
2020-11-03 08:57:12 +03:00
case 1 :
2023-04-20 11:04:47 +00:00
graph . setEditFlag ( GraphEdit : : On ) ;
2023-01-22 19:12:03 +06:00
showMenu ( Menu : : NodeDebug ) ;
2020-08-31 14:52:12 +03:00
break ;
2019-07-01 21:10:00 +03:00
case 2 :
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
if ( graph . hasEditFlag ( GraphEdit : : Auto ) ) {
graph . clearEditFlag ( GraphEdit : : Auto ) ;
2019-07-01 21:10:00 +03:00
}
else {
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : Auto ) ;
2019-07-01 21:10:00 +03:00
}
2020-08-22 01:38:59 +03:00
if ( graph . hasEditFlag ( GraphEdit : : Auto ) ) {
msg ( " Enabled auto nodes placement. " ) ;
}
else {
msg ( " Disabled auto nodes placement. " ) ;
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage2 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 3 :
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
showMenu ( Menu : : NodeFlag ) ;
2019-07-01 21:10:00 +03:00
break ;
case 4 :
2019-07-27 17:36:24 +03:00
if ( graph . checkNodes ( true ) ) {
graph . saveGraphData ( ) ;
2023-04-20 11:46:23 +00:00
msg ( " Graph successfully saved. " ) ;
2019-07-01 21:10:00 +03:00
}
else {
2023-04-20 11:20:03 +00:00
msg ( " Graph not saved. There are errors, see console... " ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage2 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 5 :
2023-04-20 11:20:03 +00:00
if ( graph . saveGraphData ( ) ) {
2023-04-20 11:46:23 +00:00
msg ( " Graph successfully saved. " ) ;
2023-04-20 11:20:03 +00:00
}
else {
msg ( " Could not save Graph. See console... " ) ;
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage2 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 6 :
2023-04-20 11:20:03 +00:00
if ( graph . loadGraphData ( ) ) {
2023-04-20 11:46:23 +00:00
msg ( " Graph successfully loaded. " ) ;
2023-04-20 11:20:03 +00:00
}
else {
msg ( " Could not load Graph. See console... " ) ;
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage2 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 7 :
2019-07-27 17:36:24 +03:00
if ( graph . checkNodes ( true ) ) {
2019-07-01 21:10:00 +03:00
msg ( " Nodes works fine " ) ;
}
else {
msg ( " There are errors, see console " ) ;
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage2 ) ;
2019-07-01 21:10:00 +03:00
break ;
case 8 :
2020-08-21 17:08:05 +03:00
graph . setEditFlag ( GraphEdit : : On ) ;
if ( graph . hasEditFlag ( GraphEdit : : Noclip ) ) {
graph . clearEditFlag ( GraphEdit : : Noclip ) ;
2023-04-20 11:20:03 +00:00
msg ( " Noclip mode disabled. " ) ;
2020-08-21 17:08:05 +03:00
}
else {
graph . setEditFlag ( GraphEdit : : Noclip ) ;
2023-04-20 11:20:03 +00:00
msg ( " Noclip mode enabled. " ) ;
2020-08-21 17:08:05 +03:00
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage2 ) ;
2020-08-21 17:08:05 +03:00
// update editor movetype based on flag
m_ent - > v . movetype = graph . hasEditFlag ( GraphEdit : : Noclip ) ? MOVETYPE_NOCLIP : MOVETYPE_WALK ;
2019-07-01 21:10:00 +03:00
break ;
case 9 :
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeMainPage1 ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : menuGraphRadius ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-27 17:36:24 +03:00
graph . setEditFlag ( GraphEdit : : On ) ; // turn graph on in case
2019-07-01 21:10:00 +03:00
if ( item > = 1 & & item < = 9 ) {
2024-01-26 19:52:00 +03:00
constexpr float kRadiusValues [ ] = { 0.0f , 8.0f , 16.0f , 32.0f , 48.0f , 64.0f , 80.0f , 96.0f , 128.0f } ;
graph . setRadius ( kInvalidNodeIndex , kRadiusValues [ item - 1 ] ) ;
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeRadius ) ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : menuGraphType ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
2019-07-27 17:36:24 +03:00
graph . add ( item - 1 ) ;
showMenu ( Menu : : NodeType ) ;
2019-07-01 21:10:00 +03:00
break ;
case 8 :
2021-09-20 13:50:00 +03:00
graph . add ( NodeAddFlag : : Goal ) ;
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeType ) ;
2019-07-01 21:10:00 +03:00
break ;
case 9 :
2019-07-27 17:36:24 +03:00
graph . startLearnJump ( ) ;
showMenu ( Menu : : NodeType ) ;
2019-07-01 21:10:00 +03:00
break ;
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2023-01-22 19:12:03 +06:00
int BotControl : : menuGraphDebug ( int item ) {
closeMenu ( ) ; // reset menu display
switch ( item ) {
case 1 :
cv_debug_goal . set ( graph . getEditorNearest ( ) ) ;
if ( cv_debug_goal . int_ ( ) ! = kInvalidNodeIndex ) {
msg ( " Debug goal is set to node %d. " , cv_debug_goal . int_ ( ) ) ;
}
else {
msg ( " Cannot find the node. Debug goal is disabled. " ) ;
}
showMenu ( Menu : : NodeDebug ) ;
break ;
case 2 :
cv_debug_goal . set ( graph . getFacingIndex ( ) ) ;
if ( cv_debug_goal . int_ ( ) ! = kInvalidNodeIndex ) {
msg ( " Debug goal is set to node %d. " , cv_debug_goal . int_ ( ) ) ;
}
else {
msg ( " Cannot find the node. Debug goal is disabled. " ) ;
}
showMenu ( Menu : : NodeDebug ) ;
break ;
case 3 :
cv_debug_goal . set ( kInvalidNodeIndex ) ;
msg ( " Debug goal is disabled. " ) ;
showMenu ( Menu : : NodeDebug ) ;
break ;
case 10 :
closeMenu ( ) ;
break ;
}
return BotCommandResult : : Handled ;
}
2019-07-27 17:36:24 +03:00
int BotControl : : menuGraphFlag ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2023-01-22 19:12:03 +06:00
int nearest = graph . getEditorNearest ( ) ;
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
2019-07-27 17:36:24 +03:00
graph . toggleFlags ( NodeFlag : : NoHostage ) ;
showMenu ( Menu : : NodeFlag ) ;
2019-07-01 21:10:00 +03:00
break ;
case 2 :
2023-02-07 15:17:52 +06:00
if ( graph [ nearest ] . flags & NodeFlag : : CTOnly ) {
2023-01-22 19:12:03 +06:00
graph . toggleFlags ( NodeFlag : : CTOnly ) ;
graph . toggleFlags ( NodeFlag : : TerroristOnly ) ;
}
else {
graph . toggleFlags ( NodeFlag : : TerroristOnly ) ;
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeFlag ) ;
2019-07-01 21:10:00 +03:00
break ;
case 3 :
2023-02-07 15:17:52 +06:00
if ( graph [ nearest ] . flags & NodeFlag : : TerroristOnly ) {
2023-01-22 19:12:03 +06:00
graph . toggleFlags ( NodeFlag : : TerroristOnly ) ;
graph . toggleFlags ( NodeFlag : : CTOnly ) ;
}
else {
graph . toggleFlags ( NodeFlag : : CTOnly ) ;
}
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : NodeFlag ) ;
2019-07-01 21:10:00 +03:00
break ;
case 4 :
2019-07-27 17:36:24 +03:00
graph . toggleFlags ( NodeFlag : : Lift ) ;
showMenu ( Menu : : NodeFlag ) ;
2019-07-01 21:10:00 +03:00
break ;
case 5 :
2019-07-27 17:36:24 +03:00
graph . toggleFlags ( NodeFlag : : Sniper ) ;
showMenu ( Menu : : NodeFlag ) ;
2019-07-01 21:10:00 +03:00
break ;
2023-03-13 15:39:15 +03:00
2023-01-22 19:12:03 +06:00
case 6 :
graph . toggleFlags ( NodeFlag : : Goal ) ;
showMenu ( Menu : : NodeFlag ) ;
break ;
2023-03-13 15:39:15 +03:00
2023-01-22 19:12:03 +06:00
case 7 :
graph . toggleFlags ( NodeFlag : : Rescue ) ;
showMenu ( Menu : : NodeFlag ) ;
break ;
case 8 :
if ( graph [ nearest ] . flags ! = NodeFlag : : Crouch ) {
graph . toggleFlags ( NodeFlag : : Crouch ) ;
graph [ nearest ] . origin . z + = - 18.0f ;
}
else {
graph . toggleFlags ( NodeFlag : : Crouch ) ;
graph [ nearest ] . origin . z + = 18.0f ;
}
2023-03-13 15:39:15 +03:00
2023-01-22 19:12:03 +06:00
showMenu ( Menu : : NodeFlag ) ;
break ;
2023-03-13 15:39:15 +03:00
2023-01-22 19:12:03 +06:00
case 9 :
// if the node doesn't have a camp flag, set it and open the camp directions selection menu
2023-02-07 15:17:52 +06:00
if ( ! ( graph [ nearest ] . flags & NodeFlag : : Camp ) ) {
2023-01-22 19:12:03 +06:00
graph . toggleFlags ( NodeFlag : : Camp ) ;
showMenu ( Menu : : CampDirections ) ;
break ;
}
// otherwise remove the flag, and don't show the camp directions selection menu
else {
graph . toggleFlags ( NodeFlag : : Camp ) ;
showMenu ( Menu : : NodeFlag ) ;
break ;
}
}
return BotCommandResult : : Handled ;
}
int BotControl : : menuCampDirections ( int item ) {
closeMenu ( ) ; // reset menu display
switch ( item ) {
case 1 :
graph . add ( NodeAddFlag : : Camp ) ;
showMenu ( Menu : : CampDirections ) ;
break ;
case 2 :
graph . add ( NodeAddFlag : : CampEnd ) ;
showMenu ( Menu : : CampDirections ) ;
break ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuAutoPathDistance ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
if ( item > = 1 & & item < = 7 ) {
2024-01-26 19:52:00 +03:00
constexpr float kDistanceValues [ ] = { 0.0f , 100.0f , 130.0f , 160.0f , 190.0f , 220.0f , 250.0f } ;
graph . setAutoPathDistance ( kDistanceValues [ item - 1 ] ) ;
2019-07-01 21:10:00 +03:00
}
2020-08-23 11:08:27 +03:00
switch ( item ) {
default :
showMenu ( Menu : : NodeAutoPath ) ;
break ;
2019-07-01 21:10:00 +03:00
2020-08-23 11:08:27 +03:00
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2020-08-23 11:08:27 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuKickPage1 ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
bots . kickBot ( item - 1 ) ;
kickBotByMenu ( 1 ) ;
break ;
case 9 :
kickBotByMenu ( 2 ) ;
break ;
case 10 :
2019-07-27 17:36:24 +03:00
showMenu ( Menu : : Control ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuKickPage2 ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
bots . kickBot ( item + 8 - 1 ) ;
kickBotByMenu ( 2 ) ;
break ;
case 9 :
kickBotByMenu ( 3 ) ;
break ;
case 10 :
kickBotByMenu ( 1 ) ;
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuKickPage3 ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
bots . kickBot ( item + 16 - 1 ) ;
kickBotByMenu ( 3 ) ;
break ;
case 9 :
kickBotByMenu ( 4 ) ;
break ;
case 10 :
kickBotByMenu ( 2 ) ;
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
int BotControl : : menuKickPage4 ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
bots . kickBot ( item + 24 - 1 ) ;
kickBotByMenu ( 4 ) ;
break ;
case 10 :
kickBotByMenu ( 3 ) ;
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
int BotControl : : menuGraphPath ( int item ) {
2020-10-11 14:01:19 +03:00
closeMenu ( ) ; // reset menu display
2019-07-01 21:10:00 +03:00
switch ( item ) {
case 1 :
2019-07-27 17:36:24 +03:00
graph . pathCreate ( PathConnection : : Outgoing ) ;
showMenu ( Menu : : NodePath ) ;
2019-07-01 21:10:00 +03:00
break ;
case 2 :
2019-07-27 17:36:24 +03:00
graph . pathCreate ( PathConnection : : Incoming ) ;
showMenu ( Menu : : NodePath ) ;
2019-07-01 21:10:00 +03:00
break ;
case 3 :
2019-07-27 17:36:24 +03:00
graph . pathCreate ( PathConnection : : Bidirectional ) ;
showMenu ( Menu : : NodePath ) ;
2019-07-01 21:10:00 +03:00
break ;
2023-05-13 00:19:07 +06:00
case 4 :
graph . pathCreate ( PathConnection : : Jumping ) ;
showMenu ( Menu : : NodePath ) ;
break ;
2019-07-01 21:10:00 +03:00
case 10 :
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
break ;
}
2019-07-27 17:36:24 +03:00
return BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
2019-07-27 17:36:24 +03:00
bool BotControl : : executeCommands ( ) {
2019-07-01 21:10:00 +03:00
if ( m_args . empty ( ) ) {
return false ;
}
2023-05-02 09:42:43 +03:00
const auto & prefix = m_args . first ( ) ;
2020-06-15 11:28:42 +03:00
// no handling if not for us
2020-09-10 13:54:00 +03:00
if ( prefix ! = product . cmdPri & & prefix ! = product . cmdSec ) {
2020-06-15 11:28:42 +03:00
return false ;
}
2023-06-24 03:23:22 +03:00
const auto & client = util . getClient ( game . indexOfPlayer ( m_ent ) ) ;
2019-07-01 21:10:00 +03:00
// do not allow to execute stuff for non admins
2019-07-27 17:36:24 +03:00
if ( m_ent ! = game . getLocalEntity ( ) & & ! ( client . flags & ClientFlags : : Admin ) ) {
2020-06-12 18:52:38 +03:00
msg ( " Access to %s commands is restricted. " , product . name ) ;
2022-09-10 15:47:41 +03:00
// reset issuer, but returns "true" to suppress "unknown command" message
setIssuer ( nullptr ) ;
2019-07-01 21:10:00 +03:00
return true ;
}
auto aliasMatch = [ ] ( String & test , const String & cmd , String & aliasName ) - > bool {
2019-07-27 17:36:24 +03:00
for ( auto & alias : test . split ( " / " ) ) {
2019-07-01 21:10:00 +03:00
if ( alias = = cmd ) {
aliasName = alias ;
return true ;
}
}
return false ;
} ;
String cmd ;
// give some help
2020-09-29 19:23:26 +03:00
if ( hasArg ( 1 ) & & strValue ( 1 ) = = " help " ) {
2020-08-31 14:30:09 +03:00
const auto hasSecondArg = hasArg ( 2 ) ;
2019-07-01 21:10:00 +03:00
for ( auto & item : m_cmds ) {
2020-08-31 14:30:09 +03:00
if ( ! hasSecondArg ) {
2023-05-06 20:14:03 +03:00
cmd = item . name . split ( " / " ) . first ( ) ;
2020-08-31 14:30:09 +03:00
}
2020-09-29 19:23:26 +03:00
if ( ! hasSecondArg | | aliasMatch ( item . name , strValue ( 2 ) , cmd ) ) {
2020-09-11 16:01:33 +03:00
msg ( " Command: \" %s %s \" " , prefix , cmd ) ;
msg ( " Format: %s " , item . format ) ;
msg ( " Help: %s " , conf . translate ( item . help ) ) ;
2019-07-01 21:10:00 +03:00
2020-08-31 14:30:09 +03:00
auto aliases = item . name . split ( " / " ) ;
if ( aliases . length ( ) > 1 ) {
msg ( " Aliases: %s " , String : : join ( aliases , " , " ) ) ;
}
if ( hasSecondArg ) {
return true ;
}
else {
msg ( " \n " ) ;
}
2019-07-01 21:10:00 +03:00
}
}
2020-08-31 14:30:09 +03:00
if ( ! hasSecondArg ) {
2019-07-01 21:10:00 +03:00
return true ;
}
else {
2020-09-29 19:23:26 +03:00
msg ( " No help found for \" %s \" " , strValue ( 2 ) ) ;
2019-07-01 21:10:00 +03:00
}
return true ;
}
cmd . clear ( ) ;
// if no args passed just print all the commands
if ( m_args . length ( ) = = 1 ) {
2020-06-12 18:52:38 +03:00
msg ( " usage %s <command> [arguments] " , prefix ) ;
2019-07-01 21:10:00 +03:00
msg ( " valid commands are: " ) ;
for ( auto & item : m_cmds ) {
2023-05-06 20:14:03 +03:00
msg ( " %-14.11s - %s " , item . name . split ( " / " ) . first ( ) , String ( conf . translate ( item . help ) ) . lowercase ( ) ) ;
2019-07-01 21:10:00 +03:00
}
return true ;
}
// first search for a actual cmd
for ( auto & item : m_cmds ) {
if ( aliasMatch ( item . name , m_args [ 1 ] , cmd ) ) {
switch ( ( this - > * item . handler ) ( ) ) {
2019-07-27 17:36:24 +03:00
case BotCommandResult : : Handled :
2019-07-01 21:10:00 +03:00
default :
break ;
2019-07-27 17:36:24 +03:00
case BotCommandResult : : ListenServer :
2020-06-12 18:52:38 +03:00
msg ( " Command \" %s %s \" is only available from the listenserver console. " , prefix , cmd ) ;
2019-07-01 21:10:00 +03:00
break ;
2019-07-27 17:36:24 +03:00
case BotCommandResult : : BadFormat :
2020-09-02 18:10:54 +06:00
msg ( " Incorrect usage of \" %s %s \" command. Correct usage is: " , prefix , cmd ) ;
msg ( " \n \t %s \n " , item . format ) ;
msg ( " Please type \" %s help %s \" to get more information. " , prefix , cmd ) ;
2019-07-01 21:10:00 +03:00
break ;
}
m_isFromConsole = false ;
return true ;
}
}
2020-06-12 18:52:38 +03:00
msg ( " Unknown command: %s " , m_args [ 1 ] ) ;
// clear all the arguments upon finish
m_args . clear ( ) ;
2019-07-01 21:10:00 +03:00
return true ;
}
2019-07-27 17:36:24 +03:00
bool BotControl : : executeMenus ( ) {
2019-07-01 21:10:00 +03:00
if ( ! util . isPlayer ( m_ent ) | | game . isBotCmd ( ) ) {
return false ;
}
2023-06-24 03:23:22 +03:00
const auto & issuer = util . getClient ( game . indexOfPlayer ( m_ent ) ) ;
2019-07-01 21:10:00 +03:00
// check if it's menu select, and some key pressed
2020-06-12 18:52:38 +03:00
if ( strValue ( 0 ) ! = " menuselect " | | strValue ( 1 ) . empty ( ) | | issuer . menu = = Menu : : None ) {
2019-07-01 21:10:00 +03:00
return false ;
}
// let's get handle
for ( auto & menu : m_menus ) {
if ( menu . ident = = issuer . menu ) {
2022-01-15 23:18:58 +03:00
return ( this - > * menu . handler ) ( strValue ( 1 ) . int_ ( ) ) = = BotCommandResult : : Handled ;
2019-07-01 21:10:00 +03:00
}
}
return false ;
}
void BotControl : : showMenu ( int id ) {
2020-10-11 14:01:19 +03:00
static bool menusParsed = false ;
2019-07-01 21:10:00 +03:00
// make menus looks like we need only once
2020-10-11 14:01:19 +03:00
if ( ! menusParsed ) {
2021-09-10 20:12:23 +03:00
m_ignoreTranslate = false ; // always translate menus
2019-07-01 21:10:00 +03:00
for ( auto & parsed : m_menus ) {
2020-06-12 18:52:38 +03:00
StringRef translated = conf . translate ( parsed . text ) ;
2019-07-01 21:10:00 +03:00
// translate all the things
parsed . text = translated ;
2020-11-03 08:57:12 +03:00
// make menu looks best
2019-07-27 17:36:24 +03:00
if ( ! ( game . is ( GameFlags : : Legacy ) ) ) {
for ( int j = 0 ; j < 10 ; + + j ) {
parsed . text . replace ( strings . format ( " %d. " , j ) , strings . format ( " \\ r%d. \\ w " , j ) ) ;
2019-07-01 21:10:00 +03:00
}
}
}
2020-10-11 14:01:19 +03:00
menusParsed = true ;
2019-07-01 21:10:00 +03:00
}
if ( ! util . isPlayer ( m_ent ) ) {
return ;
}
2020-10-11 14:01:19 +03:00
auto & client = util . getClient ( game . indexOfPlayer ( m_ent ) ) ;
2020-11-03 08:57:12 +03:00
aim: verify camp angles from nav data before using them
aim: tweaked a bit grenade handling, so bots should use them more
aim: reduce time between selecting grenade and throwing it away
aim: removed hacks in look angles code, due to removing yb_whoose_your_daddy cvar
aim: use direct enemy origin from visibility check, and not re-calculate it
aim: update enemy prediction, so it now depends on frame interval for a bot
aim: additional height offset are tweaked, and now used only for difficulty 4
nav: tweaked a bit player avoidance code, and it's not preventing bot from checking terrain
nav: do not check banned nodes, when bucket sizes re too low
nav: cover nodes are now selected depending on total bots on server
nav: let bot enter pause task after long jump
nav: extend velocity by a little for a jump, like it was in first versions of bot
nav: stuck checking is now taken in account lower minimal speed if bot is ducking
fix: navigation reachability timers, so bots will have correct current node index while camping
fix: bots are unable to finish pickup or destroy breakable task, if target is not reachable
fix: cover nodes are now calculated as they should
fix: manual calling bots add_[t/ct] now ignores yb_join_team cvar
bot: tweaked a little difficulty levels, so level 4 is now nightmare level, and 3 is very heard
bot: minor refactoring and moving functions to correct source file
bot: add yb_economics_disrespect_percent, so bots can ignore economics and buy more different guns
bot: add yb_check_darkness that allows to disable darkness checks for bot, thus disallowing usage of flashlight
bot: camp buttons are now lightly depends on bot health
chat: welcome chat message from bots is now sent during first freeze time period
crlib: switch over to stdint.h and remove crlib-own types
crlib: fixed alignment in sse code
2023-04-07 14:46:49 +03:00
auto sendMenu = [ & ] ( int32_t slots , bool last , StringRef text ) {
2020-10-12 20:59:48 +03:00
MessageWriter ( MSG_ONE , msgs . id ( NetMsg : : ShowMenu ) , nullptr , m_ent )
. writeShort ( slots )
. writeChar ( - 1 )
. writeByte ( last ? HLFalse : HLTrue )
. writeString ( text . chars ( ) ) ;
} ;
2020-10-11 14:01:19 +03:00
constexpr size_t maxMenuSentLength = 140 ;
2019-07-01 21:10:00 +03:00
2020-10-11 14:01:19 +03:00
for ( const auto & display : m_menus ) {
if ( display . ident = = id ) {
2020-10-12 20:59:48 +03:00
String text = ( game . is ( GameFlags : : Xash3D | GameFlags : : Mobility ) & & ! cv_display_menu_text . bool_ ( ) ) ? " " : display . text . chars ( ) ;
2019-07-01 21:10:00 +03:00
2020-10-12 20:59:48 +03:00
// split if needed
if ( text . length ( ) > maxMenuSentLength ) {
auto chunks = text . split ( maxMenuSentLength ) ;
2019-07-01 21:10:00 +03:00
2020-10-12 20:59:48 +03:00
// send in chunks
for ( size_t i = 0 ; i < chunks . length ( ) ; + + i ) {
sendMenu ( display . slots , i = = chunks . length ( ) - 1 , chunks [ i ] ) ;
}
}
else {
sendMenu ( display . slots , true , text ) ;
}
2019-07-01 21:10:00 +03:00
client . menu = id ;
2020-10-12 20:59:48 +03:00
engfuncs . pfnClientCommand ( m_ent , " speak \" player/geiger1 \" \n " ) ; // stops others from hearing menu sounds..
break ;
2019-07-01 21:10:00 +03:00
}
}
}
2020-10-11 14:01:19 +03:00
void BotControl : : closeMenu ( ) {
if ( ! util . isPlayer ( m_ent ) ) {
return ;
}
auto & client = util . getClient ( game . indexOfPlayer ( m_ent ) ) ;
// do not reset menu if already none
if ( client . menu = = Menu : : None ) {
return ;
}
MessageWriter ( MSG_ONE , msgs . id ( NetMsg : : ShowMenu ) , nullptr , m_ent )
. writeShort ( 0 )
. writeChar ( 0 )
. writeByte ( 0 )
. writeString ( " " ) ;
client . menu = Menu : : None ;
}
2019-07-01 21:10:00 +03:00
void BotControl : : kickBotByMenu ( int page ) {
if ( page > 4 | | page < 1 ) {
return ;
}
2020-08-22 01:38:59 +03:00
static StringRef headerTitle = conf . translate ( " Bots Remove Menu " ) ;
static StringRef notABot = conf . translate ( " Not a Bot " ) ;
static StringRef backKey = conf . translate ( " Back " ) ;
static StringRef moreKey = conf . translate ( " More " ) ;
2019-07-01 21:10:00 +03:00
String menus ;
2020-08-22 01:38:59 +03:00
menus . assignf ( " \\ y%s (%d/4): \\ w \n \n " , headerTitle , page ) ;
2019-07-01 21:10:00 +03:00
int menuKeys = ( page = = 4 ) ? cr : : bit ( 9 ) : ( cr : : bit ( 8 ) | cr : : bit ( 9 ) ) ;
int menuKey = ( page - 1 ) * 8 ;
2019-07-27 17:36:24 +03:00
for ( int i = menuKey ; i < page * 8 ; + + i ) {
auto bot = bots [ i ] ;
2019-07-01 21:10:00 +03:00
2019-08-24 12:43:42 +03:00
// check for fakeclient bit, since we're clear it upon kick, but actual bot struct destroyed after client disconnected
if ( bot ! = nullptr & & ( bot - > pev - > flags & FL_FAKECLIENT ) ) {
2019-07-01 21:10:00 +03:00
menuKeys | = cr : : bit ( cr : : abs ( i - menuKey ) ) ;
2019-09-14 23:13:55 +03:00
menus . appendf ( " %1.1d. %s%s \n " , i - menuKey + 1 , bot - > pev - > netname . chars ( ) , bot - > m_team = = Team : : CT ? " \\ y(CT) \\ w " : " \\ r(T) \\ w " ) ;
2019-07-01 21:10:00 +03:00
}
else {
2020-08-22 01:38:59 +03:00
menus . appendf ( " \\ d %1.1d. %s \\ w \n " , i - menuKey + 1 , notABot ) ;
2019-07-01 21:10:00 +03:00
}
}
2020-08-22 01:38:59 +03:00
menus . appendf ( " \n %s 0. %s " , ( page = = 4 ) ? " " : strings . format ( " 9. %s... \n " , moreKey ) , backKey ) ;
2019-07-01 21:10:00 +03:00
// force to clear current menu
2020-10-11 14:01:19 +03:00
closeMenu ( ) ;
2019-07-01 21:10:00 +03:00
2019-07-27 17:36:24 +03:00
auto id = Menu : : KickPage1 - 1 + page ;
2019-07-01 21:10:00 +03:00
for ( auto & menu : m_menus ) {
if ( menu . ident = = id ) {
aim: verify camp angles from nav data before using them
aim: tweaked a bit grenade handling, so bots should use them more
aim: reduce time between selecting grenade and throwing it away
aim: removed hacks in look angles code, due to removing yb_whoose_your_daddy cvar
aim: use direct enemy origin from visibility check, and not re-calculate it
aim: update enemy prediction, so it now depends on frame interval for a bot
aim: additional height offset are tweaked, and now used only for difficulty 4
nav: tweaked a bit player avoidance code, and it's not preventing bot from checking terrain
nav: do not check banned nodes, when bucket sizes re too low
nav: cover nodes are now selected depending on total bots on server
nav: let bot enter pause task after long jump
nav: extend velocity by a little for a jump, like it was in first versions of bot
nav: stuck checking is now taken in account lower minimal speed if bot is ducking
fix: navigation reachability timers, so bots will have correct current node index while camping
fix: bots are unable to finish pickup or destroy breakable task, if target is not reachable
fix: cover nodes are now calculated as they should
fix: manual calling bots add_[t/ct] now ignores yb_join_team cvar
bot: tweaked a little difficulty levels, so level 4 is now nightmare level, and 3 is very heard
bot: minor refactoring and moving functions to correct source file
bot: add yb_economics_disrespect_percent, so bots can ignore economics and buy more different guns
bot: add yb_check_darkness that allows to disable darkness checks for bot, thus disallowing usage of flashlight
bot: camp buttons are now lightly depends on bot health
chat: welcome chat message from bots is now sent during first freeze time period
crlib: switch over to stdint.h and remove crlib-own types
crlib: fixed alignment in sse code
2023-04-07 14:46:49 +03:00
menu . slots = static_cast < int > ( static_cast < uint32_t > ( menuKeys ) & static_cast < uint32_t > ( - 1 ) ) ;
2019-07-01 21:10:00 +03:00
menu . text = menus ;
break ;
}
}
showMenu ( id ) ;
}
void BotControl : : assignAdminRights ( edict_t * ent , char * infobuffer ) {
if ( ! game . isDedicated ( ) | | util . isFakeClient ( ent ) ) {
return ;
}
2020-06-12 18:52:38 +03:00
StringRef key = cv_password_key . str ( ) ;
StringRef password = cv_password . str ( ) ;
2019-07-01 21:10:00 +03:00
if ( ! key . empty ( ) & & ! password . empty ( ) ) {
2019-07-27 17:36:24 +03:00
auto & client = util . getClient ( game . indexOfPlayer ( ent ) ) ;
2019-07-01 21:10:00 +03:00
if ( password = = engfuncs . pfnInfoKeyValue ( infobuffer , key . chars ( ) ) ) {
2019-07-27 17:36:24 +03:00
client . flags | = ClientFlags : : Admin ;
2019-07-01 21:10:00 +03:00
}
else {
2019-07-27 17:36:24 +03:00
client . flags & = ~ ClientFlags : : Admin ;
2019-07-01 21:10:00 +03:00
}
}
}
2019-07-27 17:36:24 +03:00
void BotControl : : maintainAdminRights ( ) {
2019-07-01 21:10:00 +03:00
if ( ! game . isDedicated ( ) ) {
return ;
}
2020-10-12 20:59:48 +03:00
StringRef key = cv_password_key . str ( ) ;
StringRef password = cv_password . str ( ) ;
2019-07-01 21:10:00 +03:00
2020-10-12 20:59:48 +03:00
for ( auto & client : util . getClients ( ) ) {
if ( ! ( client . flags & ClientFlags : : Used ) | | util . isFakeClient ( client . ent ) ) {
continue ;
}
auto ent = client . ent ;
2019-07-01 21:10:00 +03:00
2020-10-12 20:59:48 +03:00
if ( client . flags & ClientFlags : : Admin ) {
if ( key . empty ( ) | | password . empty ( ) ) {
client . flags & = ~ ClientFlags : : Admin ;
2019-07-01 21:10:00 +03:00
}
2020-10-12 20:59:48 +03:00
else if ( password ! = engfuncs . pfnInfoKeyValue ( engfuncs . pfnGetInfoKeyBuffer ( ent ) , key . chars ( ) ) ) {
client . flags & = ~ ClientFlags : : Admin ;
ctrl . msg ( " Player %s had lost remote access to %s. " , ent - > v . netname . chars ( ) , product . name ) ;
}
}
else if ( ! ( client . flags & ClientFlags : : Admin ) & & ! key . empty ( ) & & ! password . empty ( ) ) {
if ( password = = engfuncs . pfnInfoKeyValue ( engfuncs . pfnGetInfoKeyBuffer ( ent ) , key . chars ( ) ) ) {
client . flags | = ClientFlags : : Admin ;
ctrl . msg ( " Player %s had gained full remote access to %s. " , ent - > v . netname . chars ( ) , product . name ) ;
2019-07-01 21:10:00 +03:00
}
}
}
}
2020-10-13 15:43:25 +03:00
void BotControl : : flushPrintQueue ( ) {
if ( m_printQueueFlushTimestamp > game . time ( ) | | m_printQueue . empty ( ) ) {
return ;
}
auto printable = m_printQueue . popFront ( ) ;
// send to needed destination
if ( printable . destination = = PrintQueueDestination : : ServerConsole ) {
game . print ( printable . text . chars ( ) ) ;
}
else if ( ! game . isNullEntity ( m_ent ) ) {
game . clientPrint ( m_ent , printable . text . chars ( ) ) ;
}
m_printQueueFlushTimestamp = game . time ( ) + 0.05f ;
}
2019-07-27 17:36:24 +03:00
BotControl : : BotControl ( ) {
2019-07-01 21:10:00 +03:00
m_ent = nullptr ;
2019-08-18 21:00:00 +03:00
m_djump = nullptr ;
2020-11-03 08:57:12 +03:00
m_ignoreTranslate = false ;
2019-07-01 21:10:00 +03:00
m_isFromConsole = false ;
m_isMenuFillCommand = false ;
2019-07-27 17:36:24 +03:00
m_rapidOutput = false ;
2019-07-01 21:10:00 +03:00
m_menuServerFillTeam = 5 ;
2020-10-13 15:43:25 +03:00
m_printQueueFlushTimestamp = 0.0f ;
2019-07-01 21:10:00 +03:00
2020-11-02 20:12:52 +06:00
m_cmds . emplace ( " add/addbot/add_ct/addbot_ct/add_t/addbot_t/addhs/addhs_t/addhs_ct " , " add [difficulty] [personality] [team] [model] [name] " , " Adding specific bot into the game. " , & BotControl : : cmdAddBot ) ;
2019-07-27 17:36:24 +03:00
m_cmds . emplace ( " kick/kickone/kick_ct/kick_t/kickbot_ct/kickbot_t " , " kick [team] " , " Kicks off the random bot from the game. " , & BotControl : : cmdKickBot ) ;
2023-05-02 09:42:43 +03:00
m_cmds . emplace ( " removebots/kickbots/kickall/kickall_ct/kickall_t " , " removebots [instant] [team] " , " Kicks all the bots from the game. " , & BotControl : : cmdKickBots ) ;
2024-01-29 08:08:07 +03:00
m_cmds . emplace ( " kill/killbots/killall/kill_ct/kill_t " , " kill [team] [silent] " , " Kills the specified team / all the bots. " , & BotControl : : cmdKillBots ) ;
2023-01-25 10:39:52 +00:00
m_cmds . emplace ( " fill/fillserver " , " fill [team] [count] [difficulty] [personality] " , " Fill the server (add bots) with specified parameters. " , & BotControl : : cmdFill ) ;
2019-07-27 17:36:24 +03:00
m_cmds . emplace ( " vote/votemap " , " vote [map_id] " , " Forces all the bot to vote to specified map. " , & BotControl : : cmdVote ) ;
m_cmds . emplace ( " weapons/weaponmode " , " weapons [knife|pistol|shotgun|smg|rifle|sniper|standard] " , " Sets the bots weapon mode to use " , & BotControl : : cmdWeaponMode ) ;
m_cmds . emplace ( " menu/botmenu " , " menu [cmd] " , " Opens the main bot menu, or command menu if specified. " , & BotControl : : cmdMenu ) ;
m_cmds . emplace ( " version/ver/about " , " version [no arguments] " , " Displays version information about bot build. " , & BotControl : : cmdVersion ) ;
2020-11-02 20:12:52 +06:00
m_cmds . emplace ( " graphmenu/wpmenu/wptmenu " , " graphmenu [noarguments] " , " Opens and displays bots graph editor. " , & BotControl : : cmdNodeMenu ) ;
2019-07-27 17:36:24 +03:00
m_cmds . emplace ( " list/listbots " , " list [noarguments] " , " Lists the bots currently playing on server. " , & BotControl : : cmdList ) ;
2019-08-18 21:00:00 +03:00
m_cmds . emplace ( " graph/g/wp/wpt/waypoint " , " graph [help] " , " Handles graph operations. " , & BotControl : : cmdNode ) ;
2023-07-10 14:42:40 +00:00
m_cmds . emplace ( " cvars " , " cvars [save|save_map|cvar] " , " Display all the cvars with their descriptions. " , & BotControl : : cmdCvars ) ;
2022-12-27 12:13:29 +00:00
m_cmds . emplace ( " show_custom " , " show_custom [noarguments] " , " Shows the current values from custom.cfg. " , & BotControl : : cmdShowCustom ) ;
2019-07-01 21:10:00 +03:00
// declare the menus
createMenus ( ) ;
}
2019-07-27 17:36:24 +03:00
void BotControl : : handleEngineCommands ( ) {
2019-08-18 21:00:00 +03:00
collectArgs ( ) ;
setIssuer ( game . getLocalEntity ( ) ) ;
2019-07-01 21:10:00 +03:00
2019-08-18 21:00:00 +03:00
setFromConsole ( true ) ;
executeCommands ( ) ;
2019-07-01 21:10:00 +03:00
}
2022-09-10 15:47:41 +03:00
bool BotControl : : handleClientSideCommandsWrapper ( edict_t * ent , bool isMenus ) {
2019-08-18 21:00:00 +03:00
collectArgs ( ) ;
2019-07-01 21:10:00 +03:00
setIssuer ( ent ) ;
2022-09-10 15:47:41 +03:00
setFromConsole ( ! isMenus ) ;
auto result = isMenus ? executeMenus ( ) : executeCommands ( ) ;
if ( ! result ) {
setIssuer ( nullptr ) ;
}
return result ;
2019-07-01 21:10:00 +03:00
}
2022-09-10 15:47:41 +03:00
bool BotControl : : handleClientCommands ( edict_t * ent ) {
return handleClientSideCommandsWrapper ( ent , false ) ;
}
2019-07-01 21:10:00 +03:00
2022-09-10 15:47:41 +03:00
bool BotControl : : handleMenuCommands ( edict_t * ent ) {
return handleClientSideCommandsWrapper ( ent , true ) ;
2019-07-01 21:10:00 +03:00
}
void BotControl : : enableDrawModels ( bool enable ) {
2024-01-19 00:03:45 +03:00
static StringArray entities {
" info_player_start " , " info_player_deathmatch " , " info_vip_start "
} ;
2019-07-01 21:10:00 +03:00
2020-11-03 08:57:12 +03:00
if ( enable ) {
game . setPlayerStartDrawModels ( ) ;
}
2019-07-01 21:10:00 +03:00
for ( auto & entity : entities ) {
2019-08-18 21:00:00 +03:00
game . searchEntities ( " classname " , entity , [ & enable ] ( edict_t * ent ) {
2019-07-01 21:10:00 +03:00
if ( enable ) {
ent - > v . effects & = ~ EF_NODRAW ;
}
else {
ent - > v . effects | = EF_NODRAW ;
}
2019-08-18 21:00:00 +03:00
return EntitySearchResult : : Continue ;
2023-03-13 15:39:15 +03:00
} ) ;
2019-07-01 21:10:00 +03:00
}
}
2019-07-27 17:36:24 +03:00
void BotControl : : createMenus ( ) {
2019-07-01 21:10:00 +03:00
auto keys = [ ] ( int numKeys ) - > int {
int result = 0 ;
2019-07-27 17:36:24 +03:00
for ( int i = 0 ; i < numKeys ; + + i ) {
2019-07-01 21:10:00 +03:00
result | = cr : : bit ( i ) ;
}
result | = cr : : bit ( 9 ) ;
return result ;
} ;
// bots main menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : Main , keys ( 4 ) ,
2019-07-01 21:10:00 +03:00
" \\ yMain Menu \\ w \n \n "
" 1. Control Bots \n "
" 2. Features \n \n "
" 3. Fill Server \n "
" 4. End Round \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuMain ) ;
2019-07-01 21:10:00 +03:00
// bots features menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : Features , keys ( 5 ) ,
2019-07-01 21:10:00 +03:00
" \\ yBots Features \\ w \n \n "
" 1. Weapon Mode Menu \n "
" 2. Waypoint Menu \n "
" 3. Select Personality \n \n "
" 4. Toggle Debug Mode \n "
" 5. Command Menu \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuFeatures ) ;
2019-07-01 21:10:00 +03:00
// bot control menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : Control , keys ( 5 ) ,
2019-07-01 21:10:00 +03:00
" \\ yBots Control Menu \\ w \n \n "
" 1. Add a Bot, Quick \n "
" 2. Add a Bot, Specified \n \n "
" 3. Remove Random Bot \n "
" 4. Remove All Bots \n \n "
" 5. Remove Bot Menu \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuControl ) ;
2019-07-01 21:10:00 +03:00
// weapon mode select menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : WeaponMode , keys ( 7 ) ,
2019-07-01 21:10:00 +03:00
" \\ yBots Weapon Mode \\ w \n \n "
" 1. Knives only \n "
" 2. Pistols only \n "
" 3. Shotguns only \n "
" 4. Machine Guns only \n "
" 5. Rifles only \n "
" 6. Sniper Weapons only \n "
" 7. All Weapons \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuWeaponMode ) ;
2019-07-01 21:10:00 +03:00
// personality select menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : Personality , keys ( 4 ) ,
2019-07-01 21:10:00 +03:00
" \\ yBots Personality \\ w \n \n "
" 1. Random \n "
" 2. Normal \n "
" 3. Aggressive \n "
" 4. Careful \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuPersonality ) ;
2019-07-01 21:10:00 +03:00
// difficulty select menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : Difficulty , keys ( 5 ) ,
2019-07-01 21:10:00 +03:00
" \\ yBots Difficulty Level \\ w \n \n "
" 1. Newbie \n "
" 2. Average \n "
" 3. Normal \n "
" 4. Professional \n "
" 5. Godlike \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuDifficulty ) ;
2019-07-01 21:10:00 +03:00
// team select menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : TeamSelect , keys ( 5 ) ,
2019-07-01 21:10:00 +03:00
" \\ ySelect a team \\ w \n \n "
" 1. Terrorist Force \n "
" 2. Counter-Terrorist Force \n \n "
" 5. Auto-select \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuTeamSelect ) ;
2019-07-01 21:10:00 +03:00
// terrorist model select menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : TerroristSelect , keys ( 5 ) ,
2019-07-01 21:10:00 +03:00
" \\ ySelect an appearance \\ w \n \n "
" 1. Phoenix Connexion \n "
" 2. L337 Krew \n "
" 3. Arctic Avengers \n "
" 4. Guerilla Warfare \n \n "
" 5. Auto-select \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuClassSelect ) ;
2019-07-01 21:10:00 +03:00
// counter-terrorist model select menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : CTSelect , keys ( 5 ) ,
2019-07-01 21:10:00 +03:00
" \\ ySelect an appearance \\ w \n \n "
" 1. Seal Team 6 (DEVGRU) \n "
" 2. German GSG-9 \n "
" 3. UK SAS \n "
" 4. French GIGN \n \n "
" 5. Auto-select \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuClassSelect ) ;
2019-07-01 21:10:00 +03:00
2023-02-07 10:19:40 +00:00
// condition zero terrorist model select menu
m_menus . emplace (
Menu : : TerroristSelectCZ , keys ( 6 ) ,
" \\ ySelect an appearance \\ w \n \n "
" 1. Phoenix Connexion \n "
" 2. L337 Krew \n "
" 3. Arctic Avengers \n "
" 4. Guerilla Warfare \n "
" 5. Midwest Militia \n \n "
" 6. Auto-select \n \n "
" 0. Exit " ,
& BotControl : : menuClassSelect ) ;
// condition zero counter-terrorist model select menu
m_menus . emplace (
Menu : : CTSelectCZ , keys ( 6 ) ,
" \\ ySelect an appearance \\ w \n \n "
" 1. Seal Team 6 (DEVGRU) \n "
" 2. German GSG-9 \n "
" 3. UK SAS \n "
" 4. French GIGN \n "
" 5. Russian Spetsnaz \n \n "
" 6. Auto-select \n \n "
" 0. Exit " ,
& BotControl : : menuClassSelect ) ;
2019-07-01 21:10:00 +03:00
// command menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : Commands , keys ( 4 ) ,
2019-07-01 21:10:00 +03:00
" \\ yBot Command Menu \\ w \n \n "
" 1. Make Double Jump \n "
" 2. Finish Double Jump \n \n "
" 3. Drop the C4 Bomb \n "
" 4. Drop the Weapon \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuCommands ) ;
2019-07-01 21:10:00 +03:00
// main waypoint menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : NodeMainPage1 , keys ( 9 ) ,
2019-07-01 21:10:00 +03:00
" \\ yWaypoint Operations (Page 1) \\ w \n \n "
" 1. Show/Hide waypoints \n "
" 2. Cache waypoint \n "
" 3. Create path \n "
" 4. Delete path \n "
" 5. Add waypoint \n "
" 6. Delete waypoint \n "
" 7. Set Autopath Distance \n "
" 8. Set Radius \n \n "
" 9. Next... \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuGraphPage1 ) ;
2019-07-01 21:10:00 +03:00
// main waypoint menu (page 2)
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : NodeMainPage2 , keys ( 9 ) ,
2019-07-01 21:10:00 +03:00
" \\ yWaypoint Operations (Page 2) \\ w \n \n "
2023-01-22 19:12:03 +06:00
" 1. Debug goal \n "
2019-07-01 21:10:00 +03:00
" 2. Autowaypoint on/off \n "
" 3. Set flags \n "
" 4. Save waypoints \n "
" 5. Save without checking \n "
" 6. Load waypoints \n "
" 7. Check waypoints \n "
" 8. Noclip cheat on/off \n \n "
" 9. Previous... \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuGraphPage2 ) ;
2019-07-01 21:10:00 +03:00
2023-05-12 22:12:22 +03:00
// select nodes radius menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : NodeRadius , keys ( 9 ) ,
2019-07-01 21:10:00 +03:00
" \\ yWaypoint Radius \\ w \n \n "
" 1. SetRadius 0 \n "
" 2. SetRadius 8 \n "
" 3. SetRadius 16 \n "
" 4. SetRadius 32 \n "
" 5. SetRadius 48 \n "
" 6. SetRadius 64 \n "
" 7. SetRadius 80 \n "
" 8. SetRadius 96 \n "
" 9. SetRadius 128 \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuGraphRadius ) ;
2019-07-01 21:10:00 +03:00
2023-05-12 22:12:22 +03:00
// nodes add menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : NodeType , keys ( 9 ) ,
2019-07-01 21:10:00 +03:00
" \\ yWaypoint Type \\ w \n \n "
" 1. Normal \n "
" \\ r2. Terrorist Important \n "
" 3. Counter-Terrorist Important \n "
" \\ w4. Block with hostage / Ladder \n "
" \\ y5. Rescue Zone \n "
" \\ w6. Camping \n "
" 7. Camp End \n "
" \\ r8. Map Goal \n "
" \\ w9. Jump \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuGraphType ) ;
2023-03-13 15:39:15 +03:00
2023-01-22 19:12:03 +06:00
// debug goal menu
m_menus . emplace (
Menu : : NodeDebug , keys ( 3 ) ,
" \\ yDebug goal \\ w \n \n "
" 1. Debug nearest node \n "
" 2. Debug facing node \n "
" 3. Stop debugging \n \n "
" 0. Exit " ,
& BotControl : : menuGraphDebug ) ;
2019-07-01 21:10:00 +03:00
// set waypoint flag menu
2019-07-27 17:36:24 +03:00
m_menus . emplace (
2023-01-22 19:12:03 +06:00
Menu : : NodeFlag , keys ( 9 ) ,
2019-07-01 21:10:00 +03:00
" \\ yToggle Waypoint Flags \\ w \n \n "
" 1. Block with Hostage \n "
" 2. Terrorists Specific \n "
" 3. CTs Specific \n "
" 4. Use Elevator \n "
2023-01-22 19:12:03 +06:00
" 5. Sniper Point ( \\ yFor Camp Points Only! \\ w) \n "
" 6. Map Goal \n "
" 7. Rescue Zone \n "
" 8. Crouch Down \n "
" 9. Camp Point \n \n "
2019-07-01 21:10:00 +03:00
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuGraphFlag ) ;
2023-03-13 15:39:15 +03:00
2023-01-22 19:12:03 +06:00
// set camp directions menu
m_menus . emplace (
Menu : : CampDirections , keys ( 2 ) ,
" \\ ySet Camp Point directions \\ w \n \n "
" 1. Camp Start \n "
" 2. Camp End \n \n "
" 0. Exit " ,
& BotControl : : menuCampDirections ) ;
2019-07-01 21:10:00 +03:00
// auto-path max distance
2019-07-27 17:36:24 +03:00
m_menus . emplace (
Menu : : NodeAutoPath , keys ( 7 ) ,
2019-07-01 21:10:00 +03:00
" \\ yAutoPath Distance \\ w \n \n "
" 1. Distance 0 \n "
" 2. Distance 100 \n "
" 3. Distance 130 \n "
" 4. Distance 160 \n "
" 5. Distance 190 \n "
" 6. Distance 220 \n "
" 7. Distance 250 (Default) \n \n "
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuAutoPathDistance ) ;
2019-07-01 21:10:00 +03:00
// path connections
2019-07-27 17:36:24 +03:00
m_menus . emplace (
2023-05-13 00:19:07 +06:00
Menu : : NodePath , keys ( 4 ) ,
2019-07-01 21:10:00 +03:00
" \\ yCreate Path (Choose Direction) \\ w \n \n "
" 1. Outgoing Path \n "
" 2. Incoming Path \n "
2023-05-13 00:19:07 +06:00
" 3. Bidirectional (Both Ways) \n "
" 4. Jumping Path \n \n "
2019-07-01 21:10:00 +03:00
" 0. Exit " ,
2019-07-27 17:36:24 +03:00
& BotControl : : menuGraphPath ) ;
2019-07-01 21:10:00 +03:00
// kick menus
2019-07-27 17:36:24 +03:00
m_menus . emplace ( Menu : : KickPage1 , 0x0 , " " , & BotControl : : menuKickPage1 ) ;
m_menus . emplace ( Menu : : KickPage2 , 0x0 , " " , & BotControl : : menuKickPage2 ) ;
m_menus . emplace ( Menu : : KickPage3 , 0x0 , " " , & BotControl : : menuKickPage3 ) ;
m_menus . emplace ( Menu : : KickPage4 , 0x0 , " " , & BotControl : : menuKickPage4 ) ;
2019-07-01 21:10:00 +03:00
}