yapb-noob-edition/inc/control.h
jeefo 075bff2988
Custom.cfg (#213)
Added custom configs.

These are used for replacing some hardcoded strings inside bot code, currently custom cvar for parachute detection is available, as well as custom c4 model names.

Added editorconfig, and fixed CRLF for files (was a mix between LF & CRLF).
Fixed use-after-free sanitizer error with chatlib.
Fixed configs files loaded with memory-loader does not process last line in config files.
2020-12-15 15:28:58 +03:00

256 lines
6.1 KiB
C++

//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
// command handler status
CR_DECLARE_SCOPED_ENUM (BotCommandResult,
Handled = 0, // command successfully handled
ListenServer, // command is only avaialble on listen server
BadFormat // wrong params
)
// print queue destination
CR_DECLARE_SCOPED_ENUM (PrintQueueDestination,
ServerConsole, // use server console
ClientConsole // use client console
);
// bot command manager
class BotControl final : public Singleton <BotControl> {
public:
using Handler = int (BotControl::*) ();
using MenuHandler = int (BotControl::*) (int);
public:
// generic bot command
struct BotCmd {
String name, format, help;
Handler handler = nullptr;
public:
explicit BotCmd () = default;
BotCmd (StringRef name, StringRef format, StringRef help, Handler handler) : name (name), format (format), help (help), handler (cr::move (handler))
{ }
};
// single bot menu
struct BotMenu {
int ident, slots;
String text;
MenuHandler handler;
public:
explicit BotMenu (int ident, int slots, StringRef text, MenuHandler handler) : ident (ident), slots (slots), text (text), handler (cr::move (handler))
{ }
};
// queued text message to prevent overflow with rapid output
struct PrintQueue {
int32 destination {};
String text;
public:
explicit PrintQueue () = default;
PrintQueue (int32 destination, StringRef text) : destination (destination), text (text)
{ }
};
private:
StringArray m_args;
Array <BotCmd> m_cmds;
Array <BotMenu> m_menus;
Deque <PrintQueue> m_printQueue;
IntArray m_campIterator;
edict_t *m_ent;
Bot *m_djump;
bool m_isFromConsole;
bool m_rapidOutput;
bool m_isMenuFillCommand;
bool m_ignoreTranslate;
int m_menuServerFillTeam;
int m_interMenuData[4] = { 0, };
float m_printQueueFlushTimestamp {};
public:
BotControl ();
~BotControl () = default;
private:
int cmdAddBot ();
int cmdKickBot ();
int cmdKickBots ();
int cmdKillBots ();
int cmdFill ();
int cmdVote ();
int cmdWeaponMode ();
int cmdVersion ();
int cmdNodeMenu ();
int cmdMenu ();
int cmdList ();
int cmdCvars ();
int cmdShowCustom ();
int cmdNode ();
int cmdNodeOn ();
int cmdNodeOff ();
int cmdNodeAdd ();
int cmdNodeAddBasic ();
int cmdNodeSave ();
int cmdNodeLoad ();
int cmdNodeErase ();
int cmdNodeDelete ();
int cmdNodeCheck ();
int cmdNodeCache ();
int cmdNodeClean ();
int cmdNodeSetRadius ();
int cmdNodeSetFlags ();
int cmdNodeTeleport ();
int cmdNodePathCreate ();
int cmdNodePathDelete ();
int cmdNodePathSetAutoDistance ();
int cmdNodeAcquireEditor ();
int cmdNodeReleaseEditor ();
int cmdNodeUpload ();
int cmdNodeIterateCamp ();
int cmdNodeShowStats ();
private:
int menuMain (int item);
int menuFeatures (int item);
int menuControl (int item);
int menuWeaponMode (int item);
int menuPersonality (int item);
int menuDifficulty (int item);
int menuTeamSelect (int item);
int menuClassSelect (int item);
int menuCommands (int item);
int menuGraphPage1 (int item);
int menuGraphPage2 (int item);
int menuGraphRadius (int item);
int menuGraphType (int item);
int menuGraphFlag (int item);
int menuGraphPath (int item);
int menuAutoPathDistance (int item);
int menuKickPage1 (int item);
int menuKickPage2 (int item);
int menuKickPage3 (int item);
int menuKickPage4 (int item);
private:
void enableDrawModels (bool enable);
void createMenus ();
public:
bool executeCommands ();
bool executeMenus ();
void showMenu (int id);
void closeMenu ();
void kickBotByMenu (int page);
void assignAdminRights (edict_t *ent, char *infobuffer);
void maintainAdminRights ();
void flushPrintQueue ();
public:
void setFromConsole (bool console) {
m_isFromConsole = console;
}
void setRapidOutput (bool force) {
m_rapidOutput = force;
}
void setIssuer (edict_t *ent) {
m_ent = ent;
}
int intValue (size_t arg) const {
if (!hasArg (arg)) {
return 0;
}
return m_args[arg].int_ ();
}
StringRef strValue (size_t arg) {
if (!hasArg (arg)) {
return "";
}
return m_args[arg];
}
bool hasArg (size_t arg) const {
return arg < m_args.length ();
}
bool ignoreTranslate () const {
return m_ignoreTranslate;
}
void collectArgs () {
m_args.clear ();
for (int i = 0; i < engfuncs.pfnCmd_Argc (); ++i) {
m_args.emplace (engfuncs.pfnCmd_Argv (i));
}
}
// global heloer for sending message to correct channel
template <typename ...Args> void msg (const char *fmt, Args &&...args);
public:
// for the server commands
void handleEngineCommands ();
// for the client commands
bool handleClientCommands (edict_t *ent);
// for the client menu commands
bool handleMenuCommands (edict_t *ent);
};
// global heloer for sending message to correct channel
template <typename ...Args> inline void BotControl::msg (const char *fmt, Args &&...args) {
m_ignoreTranslate = game.isDedicated () && game.isNullEntity (m_ent);
auto result = strings.format (conf.translate (fmt), cr::forward <Args> (args)...);
// if no receiver or many message have to appear, just print to server console
if (game.isNullEntity (m_ent)) {
if (m_rapidOutput) {
m_printQueue.emplaceLast (PrintQueueDestination::ServerConsole, result);
}
else {
game.print (result); // print the info
}
return;
}
if (m_isFromConsole || strlen (result) > 56 || m_rapidOutput) {
if (m_rapidOutput) {
m_printQueue.emplaceLast (PrintQueueDestination::ClientConsole, result);
}
else {
game.clientPrint (m_ent, result);
}
}
else {
game.centerPrint (m_ent, result);
game.clientPrint (m_ent, result);
}
}
// explose global
CR_EXPOSE_GLOBAL_SINGLETON (BotControl, ctrl);