// // Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd"). // Copyright (c) YaPB Development Team. // // This software is licensed under the BSD-style license. // Additional exceptions apply. For full license details, see LICENSE.txt or visit: // https://yapb.ru/license // #pragma once #include #include #include #include using namespace cr::types; using namespace cr::classes; #include #include #include #include #include #include // defines bots tasks enum TaskID : int { TASK_NORMAL, TASK_PAUSE, TASK_MOVETOPOSITION, TASK_FOLLOWUSER, TASK_PICKUPITEM, TASK_CAMP, TASK_PLANTBOMB, TASK_DEFUSEBOMB, TASK_ATTACK, TASK_HUNTENEMY, TASK_SEEKCOVER, TASK_THROWHEGRENADE, TASK_THROWFLASHBANG, TASK_THROWSMOKE, TASK_DOUBLEJUMP, TASK_ESCAPEFROMBOMB, TASK_SHOOTBREAKABLE, TASK_HIDE, TASK_BLINDED, TASK_SPRAY, TASK_MAX }; // bot menu ids enum MenuId : int { BOT_MENU_INVALID = 0, BOT_MENU_MAIN, BOT_MENU_FEATURES, BOT_MENU_CONTROL, BOT_MENU_WEAPON_MODE, BOT_MENU_PERSONALITY, BOT_MENU_DIFFICULTY, BOT_MENU_TEAM_SELECT, BOT_MENU_TERRORIST_SELECT, BOT_MENU_CT_SELECT, BOT_MENU_COMMANDS, BOT_MENU_WAYPOINT_MAIN_PAGE1, BOT_MENU_WAYPOINT_MAIN_PAGE2, BOT_MENU_WAYPOINT_RADIUS, BOT_MENU_WAYPOINT_TYPE, BOT_MENU_WAYPOINT_FLAG, BOT_MENU_WAYPOINT_AUTOPATH, BOT_MENU_WAYPOINT_PATH, BOT_MENU_KICK_PAGE_1, BOT_MENU_KICK_PAGE_2, BOT_MENU_KICK_PAGE_3, BOT_MENU_KICK_PAGE_4, BOT_MENU_TOTAL_MENUS }; // bomb say string enum BombSayStr : int { BSS_NEED_TO_FIND_CHAT = cr::bit (1), BSS_NEED_TO_FIND_CHATTER = cr::bit (2) }; // log levels enum LogLevel : int { LL_DEFAULT = cr::bit (0), // default log message LL_WARNING = cr::bit (1), // warning log message LL_ERROR = cr::bit (2), // error log message LL_IGNORE = cr::bit (3), // additional flag LL_FATAL = cr::bit (4) // fatal error log message (terminate the game!) }; // chat types id's enum ChatType : int { CHAT_KILLING = 0, // id to kill chat array CHAT_DEAD, // id to dead chat array CHAT_BOMBPLANT, // id to bomb chat array CHAT_TEAMATTACK, // id to team-attack chat array CHAT_TEAMKILL, // id to team-kill chat array CHAT_WELCOME, // id to welcome chat array CHAT_NOKW, // id to no keyword chat array CHAT_TOTAL // number for array }; // personalities defines enum Personality : int { PERSONALITY_NORMAL = 0, PERSONALITY_RUSHER, PERSONALITY_CAREFUL }; // bot difficulties enum Difficulty : int { DIFFICULTY_VERY_EASY, DIFFICULTY_EASY, DIFFICULTY_NORMAL, DIFFICULTY_HARD, DIFFICULTY_VERY_HARD }; // collision states enum CollisionState : int { COLLISION_NOTDECICED, COLLISION_PROBING, COLLISION_NOMOVE, COLLISION_JUMP, COLLISION_DUCK, COLLISION_STRAFELEFT, COLLISION_STRAFERIGHT }; // counter-strike team id's enum Team : int { TEAM_TERRORIST = 0, TEAM_COUNTER, TEAM_SPECTATOR, TEAM_UNASSIGNED }; // client flags enum ClientFlags : int { CF_USED = cr::bit (0), CF_ALIVE = cr::bit (1), CF_ADMIN = cr::bit (2), CF_ICON = cr::bit (3) }; // bot create status enum BotCreationResult : int { BOT_RESULT_CREATED, BOT_RESULT_MAX_PLAYERS_REACHED, BOT_RESULT_NAV_ERROR, BOT_RESULT_TEAM_STACKED }; // radio messages enum RadioMessage : int { RADIO_COVER_ME = 1, RADIO_YOU_TAKE_THE_POINT = 2, RADIO_HOLD_THIS_POSITION = 3, RADIO_REGROUP_TEAM = 4, RADIO_FOLLOW_ME = 5, RADIO_TAKING_FIRE = 6, RADIO_GO_GO_GO = 11, RADIO_TEAM_FALLBACK = 12, RADIO_STICK_TOGETHER_TEAM = 13, RADIO_GET_IN_POSITION = 14, RADIO_STORM_THE_FRONT = 15, RADIO_REPORT_TEAM = 16, RADIO_AFFIRMATIVE = 21, RADIO_ENEMY_SPOTTED = 22, RADIO_NEED_BACKUP = 23, RADIO_SECTOR_CLEAR = 24, RADIO_IN_POSITION = 25, RADIO_REPORTING_IN = 26, RADIO_SHES_GONNA_BLOW = 27, RADIO_NEGATIVE = 28, RADIO_ENEMY_DOWN = 29 }; // chatter system (extending enum above, messages 30-39 is reserved) enum ChatterMessage : int { CHATTER_SPOT_THE_BOMBER = 40, CHATTER_FRIENDLY_FIRE, CHATTER_PAIN_DIED, CHATTER_BLINDED, CHATTER_GOING_TO_PLANT_BOMB, CHATTER_RESCUING_HOSTAGES, CHATTER_GOING_TO_CAMP, CHATTER_HEARD_NOISE, CHATTER_TEAM_ATTACK, CHATTER_REPORTING_IN, CHATTER_GUARDING_DROPPED_BOMB, CHATTER_CAMP, CHATTER_PLANTING_BOMB, CHATTER_DEFUSING_BOMB, CHATTER_IN_COMBAT, CHATTER_SEEK_ENEMY, CHATTER_NOTHING, CHATTER_ENEMY_DOWN, CHATTER_USING_HOSTAGES, CHATTER_FOUND_BOMB, CHATTER_WON_THE_ROUND, CHATTER_SCARED_EMOTE, CHATTER_HEARD_ENEMY, CHATTER_SNIPER_WARNING, CHATTER_SNIPER_KILLED, CHATTER_VIP_SPOTTED, CHATTER_GUARDING_VIP_SAFETY, CHATTER_GOING_TO_GUARD_VIP_SAFETY, CHATTER_QUICK_WON_ROUND, CHATTER_ONE_ENEMY_LEFT, CHATTER_TWO_ENEMIES_LEFT, CHATTER_THREE_ENEMIES_LEFT, CHATTER_NO_ENEMIES_LEFT, CHATTER_FOUND_BOMB_PLACE, CHATTER_WHERE_IS_THE_BOMB, CHATTER_DEFENDING_BOMBSITE, CHATTER_BARELY_DEFUSED, CHATTER_NICESHOT_COMMANDER, CHATTER_NICESHOT_PALL, CHATTER_GOING_TO_GUARD_HOSTAGES, CHATTER_GOING_TO_GUARD_DROPPED_BOMB, CHATTER_ON_MY_WAY, CHATTER_LEAD_ON_SIR, CHATTER_PINNED_DOWN, CHATTER_GOTTA_FIND_BOMB, CHATTER_YOU_HEARD_THE_MAN, CHATTER_LOST_COMMANDER, CHATTER_NEW_ROUND, CHATTER_COVER_ME, CHATTER_BEHIND_SMOKE, CHATTER_BOMB_SITE_SECURED, CHATTER_MAX }; // counter-strike weapon id's enum Weapon : int { WEAPON_P228 = 1, WEAPON_SHIELD = 2, WEAPON_SCOUT = 3, WEAPON_EXPLOSIVE = 4, WEAPON_XM1014 = 5, WEAPON_C4 = 6, WEAPON_MAC10 = 7, WEAPON_AUG = 8, WEAPON_SMOKE = 9, WEAPON_ELITE = 10, WEAPON_FIVESEVEN = 11, WEAPON_UMP45 = 12, WEAPON_SG550 = 13, WEAPON_GALIL = 14, WEAPON_FAMAS = 15, WEAPON_USP = 16, WEAPON_GLOCK = 17, WEAPON_AWP = 18, WEAPON_MP5 = 19, WEAPON_M249 = 20, WEAPON_M3 = 21, WEAPON_M4A1 = 22, WEAPON_TMP = 23, WEAPON_G3SG1 = 24, WEAPON_FLASHBANG = 25, WEAPON_DEAGLE = 26, WEAPON_SG552 = 27, WEAPON_AK47 = 28, WEAPON_KNIFE = 29, WEAPON_P90 = 30, WEAPON_ARMOR = 31, WEAPON_ARMORHELM = 32, WEAPON_DEFUSER = 33 }; // buy counts enum BuyState : int { BUYSTATE_PRIMARY_WEAPON = 0, BUYSTATE_ARMOR_VESTHELM, BUYSTATE_SECONDARY_WEAPON, BUYSTATE_GRENADES, BUYSTATE_DEFUSER, BUYSTATE_AMMO, BUYSTATE_NIGHTVISION, BUYSTATE_FINISHED }; // economics limits enum EconomyLimit : int { ECO_PRIMARY_GT = 0, ECO_SMG_GT_CT, ECO_SMG_GT_TE, ECO_SHOTGUN_GT, ECO_SHOTGUN_LT, ECO_HEAVY_GT, ECO_HEAVY_LT, ECO_PROSTOCK_NORMAL, ECO_PROSTOCK_RUSHER, ECO_PROSTOCK_CAREFUL, ECO_SHIELDGUN_GT }; // defines for pickup items enum PickupType : int { PICKUP_NONE, PICKUP_WEAPON, PICKUP_DROPPED_C4, PICKUP_PLANTED_C4, PICKUP_HOSTAGE, PICKUP_BUTTON, PICKUP_SHIELD, PICKUP_DEFUSEKIT }; // fight style type enum FightStyle : int { FIGHT_NONE, FIGHT_STRAFE, FIGHT_STAY }; // dodge type enum StrafeDir : int { STRAFE_DIR_NONE, STRAFE_DIR_LEFT, STRAFE_DIR_RIGHT }; // reload state enum ReloadState : int { RELOAD_NONE = 0, // no reload state currently RELOAD_PRIMARY = 1, // primary weapon reload state RELOAD_SECONDARY = 2 // secondary weapon reload state }; // collision probes enum CollisionProbe : int { PROBE_JUMP = cr::bit (0), // probe jump when colliding PROBE_DUCK = cr::bit (1), // probe duck when colliding PROBE_STRAFE = cr::bit (2) // probe strafing when colliding }; // vgui menus (since latest steam updates is obsolete, but left for old cs) enum VGuiMenu : int { VMS_TEAM = 2, // menu select team VMS_TF = 26, // terrorist select menu VMS_CT = 27 // ct select menu }; // lift usage states enum LiftState : int { LIFT_NO_NEARBY = 0, LIFT_LOOKING_BUTTON_OUTSIDE, LIFT_WAITING_FOR, LIFT_ENTERING_IN, LIFT_WAIT_FOR_TEAMMATES, LIFT_LOOKING_BUTTON_INSIDE, LIFT_TRAVELING_BY, LIFT_LEAVING }; // wayponit auto-downloader enum WaypointDownloadError : int { WDE_SOCKET_ERROR, WDE_CONNECT_ERROR, WDE_NOTFOUND_ERROR, WDE_NOERROR }; // game start messages for counter-strike... enum GameMessage : int { GAME_MSG_NONE = 1, GAME_MSG_TEAM_SELECT = 2, GAME_MSG_CLASS_SELECT = 3, GAME_MSG_PURCHASE = 100, GAME_MSG_RADIO = 200, GAME_MSG_SAY_CMD = 10000, GAME_MSG_SAY_TEAM_MSG = 10001 }; // sensing states enum SensingState : int { STATE_SEEING_ENEMY = cr::bit (0), // seeing an enemy STATE_HEARING_ENEMY = cr::bit (1), // hearing an enemy STATE_SUSPECT_ENEMY = cr::bit (2), // suspect enemy behind obstacle STATE_PICKUP_ITEM = cr::bit (3), // pickup item nearby STATE_THROW_HE = cr::bit (4), // could throw he grenade STATE_THROW_FB = cr::bit (5), // could throw flashbang STATE_THROW_SG = cr::bit (6) // could throw smokegrenade }; // positions to aim at enum AimPosition : int { AIM_NAVPOINT = cr::bit (0), // aim at nav point AIM_CAMP = cr::bit (1), // aim at camp vector AIM_PREDICT_PATH = cr::bit (2), // aim at predicted path AIM_LAST_ENEMY = cr::bit (3), // aim at last enemy AIM_ENTITY = cr::bit (4), // aim at entity like buttons, hostages AIM_ENEMY = cr::bit (5), // aim at enemy AIM_GRENADE = cr::bit (6), // aim for grenade throw AIM_OVERRIDE = cr::bit (7) // overrides all others (blinded) }; // famas/glock burst mode status + m4a1/usp silencer enum BurstMode : int { BURST_ON = cr::bit (0), BURST_OFF = cr::bit (1) }; // visibility flags enum Visibility : int { VISIBLE_HEAD = cr::bit (1), VISIBLE_BODY = cr::bit (2), VISIBLE_OTHER = cr::bit (3) }; // command handler status enum BotCommandStatus : int { CMD_STATUS_HANDLED = 0, // command successfully handled CMD_STATUS_LISTENSERV, // command is only avaialble on listen server CMD_STATUS_BADFORMAT // wrong params }; // defines for waypoint flags field (32 bits are available) enum WaypointFlag : int32 { FLAG_LIFT = cr::bit (1), // wait for lift to be down before approaching this waypoint FLAG_CROUCH = cr::bit (2), // must crouch to reach this waypoint FLAG_CROSSING = cr::bit (3), // a target waypoint FLAG_GOAL = cr::bit (4), // mission goal point (bomb, hostage etc.) FLAG_LADDER = cr::bit (5), // waypoint is on ladder FLAG_RESCUE = cr::bit (6), // waypoint is a hostage rescue point FLAG_CAMP = cr::bit (7), // waypoint is a camping point FLAG_NOHOSTAGE = cr::bit (8), // only use this waypoint if no hostage FLAG_DOUBLEJUMP = cr::bit (9), // bot help's another bot (requster) to get somewhere (using djump) FLAG_SNIPER = cr::bit (28), // it's a specific sniper point FLAG_TF_ONLY = cr::bit (29), // it's a specific terrorist point FLAG_CF_ONLY = cr::bit (30), // it's a specific ct point }; // defines for waypoint connection flags field (16 bits are available) enum PathFlag : int { PATHFLAG_JUMP = cr::bit (0) // must jump for this connection }; // enum pathfind search type enum SearchPathType : int { SEARCH_PATH_FASTEST = 0, SEARCH_PATH_SAFEST_FASTER, SEARCH_PATH_SAFEST }; // defines waypoint connection types enum PathConnection : int { CONNECTION_OUTGOING = 0, CONNECTION_INCOMING, CONNECTION_BOTHWAYS }; // a* route state enum RouteState : int { ROUTE_OPEN = 0, ROUTE_CLOSED, ROUTE_NEW }; // waypoint edit states enum WaypointEditState : int { WS_EDIT_ENABLED = cr::bit (1), WS_EDIT_NOCLIP = cr::bit (2), WS_EDIT_AUTO = cr::bit (3) }; // bot known file headers constexpr char FH_WAYPOINT[8] = "PODWAY!"; constexpr char FH_EXPERIENCE[8] = "SKYEXP!"; constexpr char FH_VISTABLE[8] = "SKYVIS!"; constexpr char FH_MATRIX[8] = "SKYPMX!"; constexpr int FV_WAYPOINT = 7; constexpr int FV_EXPERIENCE = 5; constexpr int FV_VISTABLE = 4; constexpr int FV_MATRIX = 4; // some hardcoded desire defines used to override calculated ones constexpr float TASKPRI_NORMAL = 35.0f; constexpr float TASKPRI_PAUSE = 36.0f; constexpr float TASKPRI_CAMP = 37.0f; constexpr float TASKPRI_SPRAYLOGO = 38.0f; constexpr float TASKPRI_FOLLOWUSER = 39.0f; constexpr float TASKPRI_MOVETOPOSITION = 50.0f; constexpr float TASKPRI_DEFUSEBOMB = 89.0f; constexpr float TASKPRI_PLANTBOMB = 89.0f; constexpr float TASKPRI_ATTACK = 90.0f; constexpr float TASKPRI_SEEKCOVER = 91.0f; constexpr float TASKPRI_HIDE = 92.0f; constexpr float TASKPRI_THROWGRENADE = 99.0f; constexpr float TASKPRI_DOUBLEJUMP = 99.0f; constexpr float TASKPRI_BLINDED = 100.0f; constexpr float TASKPRI_SHOOTBREAKABLE = 100.0f; constexpr float TASKPRI_ESCAPEFROMBOMB = 100.0f; constexpr float MAX_GRENADE_TIMER = 2.15f; constexpr float MAX_SPRAY_DISTANCE = 260.0f; constexpr float MAX_SPRAY_DISTANCE_X2 = MAX_SPRAY_DISTANCE * 2; constexpr float MAX_CHATTER_REPEAT = 99.0f; constexpr int MAX_PATH_INDEX = 8; constexpr int MAX_DAMAGE_VALUE = 2040; constexpr int MAX_GOAL_VALUE = 2040; constexpr int MAX_WAYPOINTS = 2048; constexpr int MAX_ROUTE_LENGTH = MAX_WAYPOINTS / 2; constexpr int MAX_WEAPONS = 32; constexpr int NUM_WEAPONS = 26; constexpr int MAX_COLLIDE_MOVES = 3; constexpr int MAX_ENGINE_PLAYERS = 32; constexpr int MAX_PRINT_BUFFER = 1024; constexpr int MAX_TEAM_COUNT = 2; constexpr int INVALID_WAYPOINT_INDEX = -1; constexpr int MAX_WAYPOINT_BUCKET_SIZE = static_cast (MAX_WAYPOINTS * 0.65); constexpr int MAX_WAYPOINT_BUCKET_MAX = MAX_WAYPOINTS * 8 / MAX_WAYPOINT_BUCKET_SIZE + 1; constexpr int MAX_WAYPOINT_BUCKET_WPTS = MAX_WAYPOINT_BUCKET_SIZE / MAX_WAYPOINT_BUCKET_MAX; // weapon masks constexpr int WEAPON_PRIMARY = ((1 << WEAPON_XM1014) | (1 << WEAPON_M3) | (1 << WEAPON_MAC10) | (1 << WEAPON_UMP45) | (1 << WEAPON_MP5) | (1 << WEAPON_TMP) | (1 << WEAPON_P90) | (1 << WEAPON_AUG) | (1 << WEAPON_M4A1) | (1 << WEAPON_SG552) | (1 << WEAPON_AK47) | (1 << WEAPON_SCOUT) | (1 << WEAPON_SG550) | (1 << WEAPON_AWP) | (1 << WEAPON_G3SG1) | (1 << WEAPON_M249) | (1 << WEAPON_FAMAS) | (1 << WEAPON_GALIL)); constexpr int WEAPON_SECONDARY = ((1 << WEAPON_P228) | (1 << WEAPON_ELITE) | (1 << WEAPON_USP) | (1 << WEAPON_GLOCK) | (1 << WEAPON_DEAGLE) | (1 << WEAPON_FIVESEVEN)); // a* route struct Route { float g, f; int parent; RouteState state; }; // links keywords and replies together struct Keywords { StringArray keywords; StringArray replies; StringArray usedReplies; }; // tasks definition struct Task { TaskID id; // major task/action carried out float desire; // desire (filled in) for this task int data; // additional data (waypoint index) float time; // time task expires bool resume; // if task can be continued if interrupted }; // botname structure definition struct BotName { String steamId; String name; int usedBy; }; // voice config structure definition struct ChatterItem { String name; float repeat; float duration; }; // weapon properties structure struct WeaponProp { char classname[64]; int ammo1; // ammo index for primary ammo int ammo1Max; // max primary ammo int slot; // HUD slot (0 based) int pos; // slot position int id; // weapon ID int flags; // flags??? }; // weapon info structure struct WeaponInfo { int id; // the weapon id value const char *name; // name of the weapon when selecting it const char *model; // model name to separate cs weapons int price; // price when buying int minPrimaryAmmo; // minimum primary ammo int teamStandard; // used by team (number) (standard map) int teamAS; // used by team (as map) int buyGroup; // group in buy menu (standard map) int buySelect; // select item in buy menu (standard map) int newBuySelectT; // for counter-strike v1.6 int newBuySelectCT; // for counter-strike v1.6 int penetratePower; // penetrate power int maxClip; // max ammo in clip bool primaryFireHold; // hold down primary fire button to use? }; // array of clients struct struct Client { edict_t *ent; // pointer to actual edict Vector origin; // position in the world Vector sound; // position sound was played int team; // bot team int team2; // real bot team in free for all mode (csdm) int flags; // client flags int radio; // radio orders int menu; // identifier to openen menu float hearingDistance; // distance this sound is heared float timeSoundLasting; // time sound is played/heared int iconFlags[MAX_ENGINE_PLAYERS]; // flag holding chatter icons float iconTimestamp[MAX_ENGINE_PLAYERS]; // timers for chatter icons }; // experience data hold in memory while playing struct Experience { int damage[MAX_TEAM_COUNT]; int index[MAX_TEAM_COUNT]; int value[MAX_TEAM_COUNT]; }; // bot creation tab struct CreateQueue { bool manual; int difficulty; int team; int member; int personality; String name; }; // define chatting collection structure struct ChatCollection { int chatProbability; float chatDelay; float timeNextChat; int entityIndex; String sayText; StringArray lastUsedSentences; }; // general waypoint header information structure struct WaypointHeader { char header[8]; int32 fileVersion; int32 pointNumber; char mapName[32]; char author[32]; }; // general experience & vistable header information structure struct ExtHeader { char header[8]; int32 fileVersion; int32 pointNumber; int32 compressed; int32 uncompressed; }; // floyd-warshall matrices struct FloydMatrix { int dist; int index; }; // define general waypoint structure struct Path { int32 pathNumber; int32 flags; Vector origin; float radius; float campStartX; float campStartY; float campEndX; float campEndY; int16 index[MAX_PATH_INDEX]; uint16 connectionFlags[MAX_PATH_INDEX]; Vector connectionVelocity[MAX_PATH_INDEX]; int32 distances[MAX_PATH_INDEX]; struct Vis { uint16 stand, crouch; } vis; }; // this structure links waypoints returned from pathfinder class PathWalk : public IntArray { public: PathWalk (void) { reserve (MAX_ROUTE_LENGTH); clear (); } ~PathWalk (void) = default; public: inline int &next (void) { return at (1); } inline int &first (void) { return at (0); } inline bool hasNext (void) const { if (empty ()) { return false; } return length () > 1; } }; // main bot class class Bot final { friend class BotManager; private: uint32 m_states; // sensing bitstates uint32 m_collideMoves[MAX_COLLIDE_MOVES]; // sorted array of movements uint32 m_collisionProbeBits; // bits of possible collision moves uint32 m_collStateIndex; // index into collide moves uint32 m_aimFlags; // aiming conditions uint32 m_currentTravelFlags; // connection flags like jumping int m_messageQueue[32]; // stack for messages int m_oldButtons; // our old buttons int m_reloadState; // current reload state int m_voicePitch; // bot voice pitch int m_rechoiceGoalCount; // multiple failed goals? int m_loosedBombWptIndex; // nearest to loosed bomb waypoint int m_plantedBombWptIndex; // nearest to planted bomb waypoint int m_currentWaypointIndex; // current waypoint index int m_travelStartIndex; // travel start index to double jump action int m_prevWptIndex[5]; // previous waypoint indices from waypoint find int m_waypointFlags; // current waypoint flags int m_needAvoidGrenade; // which direction to strafe away int m_campDirection; // camp Facing direction int m_campButtons; // buttons to press while camping int m_tryOpenDoor; // attempt's to open the door int m_liftState; // state of lift handling int m_radioSelect; // radio entry int m_pingOffset[2]; int m_ping[3]; // bots pings in scoreboard float m_headedTime; float m_prevTime; // time previously checked movement speed float m_prevSpeed; // speed some frames before float m_timeDoorOpen; // time to next door open check float m_lastChatTime; // time bot last chatted float m_timeLogoSpray; // time bot last spray logo float m_knifeAttackTime; // time to rush with knife (at the beginning of the round) float m_duckDefuseCheckTime; // time to check for ducking for defuse float m_frameInterval; // bot's frame interval float m_lastCommandTime; // time bot last thinked float m_reloadCheckTime; // time to check reloading float m_zoomCheckTime; // time to check zoom again float m_shieldCheckTime; // time to check shiled drawing again float m_grenadeCheckTime; // time to check grenade usage float m_sniperStopTime; // bot switched to other weapon? float m_lastEquipTime; // last time we equipped in buyzone float m_duckTime; // time to duck float m_jumpTime; // time last jump happened float m_soundUpdateTime; // time to update the sound float m_heardSoundTime; // last time noise is heard float m_buttonPushTime; // time to push the button float m_liftUsageTime; // time to use lift float m_askCheckTime; // time to ask team float m_collideTime; // time last collision float m_firstCollideTime; // time of first collision float m_probeTime; // time of probing different moves float m_lastCollTime; // time until next collision check float m_jumpStateTimer; // timer for jumping collision check float m_lookYawVel; // look yaw velocity float m_lookPitchVel; // look pitch velocity float m_lookUpdateTime; // lookangles update time float m_aimErrorTime; // time to update error vector float m_nextCampDirTime; // time next camp direction change float m_lastFightStyleCheck; // time checked style float m_strafeSetTime; // time strafe direction was set float m_randomizeAnglesTime; // time last randomized location float m_playerTargetTime; // time last targeting float m_timeCamping; // time to camp float m_timeWaypointMove; // last time bot followed waypoints float m_shootAtDeadTime; // time to shoot at dying players float m_followWaitTime; // wait to follow time float m_chatterTimes[CHATTER_MAX]; // chatter command timers float m_navTimeset; // time waypoint chosen by Bot float m_moveSpeed; // current speed forward/backward float m_strafeSpeed; // current speed sideways float m_minSpeed; // minimum speed in normal mode float m_oldCombatDesire; // holds old desire for filtering float m_avoidTime; // time to avoid players around float m_itemCheckTime; // time next search for items needs to be done bool m_moveToGoal; // bot currently moving to goal?? bool m_isStuck; // bot is stuck bool m_isReloading; // bot is reloading a gun bool m_forceRadio; // should bot use radio anyway? bool m_defendedBomb; // defend action issued bool m_defendHostage; // defend action issued bool m_duckDefuse; // should or not bot duck to defuse bomb bool m_checkKnifeSwitch; // is time to check switch to knife action bool m_checkWeaponSwitch; // is time to check weapon switch bool m_isUsingGrenade; // bot currently using grenade?? bool m_bombSearchOverridden; // use normal waypoint if applicable when near the bomb bool m_wantsToFire; // bot needs consider firing bool m_jumpFinished; // has bot finished jumping bool m_isLeader; // bot is leader of his team bool m_checkTerrain; // check for terrain bool m_moveToC4; // ct is moving to bomb bool m_grenadeRequested; // bot requested change to grenade PickupType m_pickupType; // type of entity which needs to be used/picked up PathWalk m_path; // pointer to current node from path StrafeDir m_combatStrafeDir; // direction to strafe FightStyle m_fightStyle; // combat style to use CollisionState m_collisionState; // collision State SearchPathType m_pathType; // which pathfinder to use uint8 m_visibility; // visibility flags edict_t *m_pickupItem; // pointer to entity of item to use/pickup edict_t *m_itemIgnore; // pointer to entity to ignore for pickup edict_t *m_liftEntity; // pointer to lift entity edict_t *m_breakableEntity; // pointer to breakable entity edict_t *m_targetEntity; // the entity that the bot is trying to reach edict_t *m_avoidGrenade; // pointer to grenade entity to avoid edict_t *m_avoid; // avoid players on our way Vector m_liftTravelPos; // lift travel position Vector m_moveAngles; // bot move angles Vector m_idealAngles; // angle wanted Vector m_randomizedIdealAngles; // angle wanted with noise Vector m_angularDeviation; // angular deviation from current to ideal angles Vector m_aimSpeed; // aim speed calculated Vector m_aimLastError; // last calculated aim error Vector m_prevOrigin; // origin some frames before Vector m_lookAt; // vector bot should look at Vector m_throw; // origin of waypoint to throw grenades Vector m_enemyOrigin; // target origin chosen for shooting Vector m_grenade; // calculated vector for grenades Vector m_entity; // origin of entities like buttons etc. Vector m_camp; // aiming vector when camping. Vector m_desiredVelocity; // desired velocity for jump waypoints Vector m_breakableOrigin; // origin of breakable Array m_hostages; // pointer to used hostage entities Array m_routes; // pointer BinaryHeap m_routeQue; Path *m_currentPath; // pointer to the current path waypoint String m_chatBuffer; // space for strings (say text...) private: int pickBestWeapon (int *vec, int count, int moneySave); int getBombPoint (void); int getCoverPoint (float maxDistance); int getDefendPoint (const Vector &origin); int searchGoal (void); int getGoalProcess (int tactic, IntArray *defensive, IntArray *offsensive); int getMsgQueue (void); int bestPrimaryCarried (void); int bestSecondaryCarried (void); int bestGrenadeCarried (void); int bestWeaponCarried (void); int changePointIndex (int index); int getNearestPoint (void); int numEnemiesNear (const Vector &origin, float radius); int numFriendsNear (const Vector &origin, float radius); int searchCampDir (void); int searchAimingPoint (const Vector &to); float getBombTimeleft (void); float getReachTime (void); float isInFOV (const Vector &dest); float getShiftSpeed (void); float getEnemyBodyOffsetCorrection (float distance); bool canReplaceWeapon (void); bool canDuckUnder (const Vector &normal); bool canJumpUp (const Vector &normal); bool doneCanJumpUp (const Vector &normal); bool cantMoveForward (const Vector &normal, TraceResult *tr); bool canStrafeLeft (TraceResult *tr); bool canStrafeRight (TraceResult *tr); bool isBlockedLeft (void); bool isBlockedRight (void); bool checkWallOnLeft (void); bool checkWallOnRight (void); bool updateNavigation (void); bool isEnemyThreat (void); bool isWeaponRestricted (int weaponIndex); bool isWeaponRestrictedAMX (int weaponIndex); bool isInViewCone (const Vector &origin); bool checkBodyParts (edict_t *target, Vector *origin, uint8 *bodyPart); bool seesEnemy (edict_t *player, bool ignoreFOV = false); bool doPlayerAvoidance (const Vector &normal); bool hasActiveGoal (void); bool advanceMovement (void); bool isBombDefusing (const Vector &bombOrigin); bool isOccupiedPoint (int index); bool seesItem (const Vector &dest, const char *itemName); bool lastEnemyShootable (void); bool isShootableBreakable (edict_t *ent); bool rateGroundWeapon (edict_t *ent); bool reactOnEnemy (void); bool getNextBestPoint (void); bool hasAnyWeapons (void); bool isDeadlyMove (const Vector &to); bool isOutOfBombTimer (void); bool isWeaponBadAtDistance (int weaponIndex, float distance); bool needToPauseFiring (float distance); bool lookupEnemies (void); bool isEnemyHidden (edict_t *enemy); bool isFriendInLineOfFire (float distance); bool isGroupOfEnemies (const Vector &location, int numEnemies = 1, float radius = 256.0f); bool isPenetrableObstacle (const Vector &dest); bool isPenetrableObstacle2 (const Vector &dest); bool isEnemyBehindShield (edict_t *enemy); bool checkChatKeywords (String &reply); bool isReplyingToChat (void); void instantChatter (int type); void runAI (void); void runMovement (void); void checkSpawnConditions (void); void buyStuff (void); void changePitch (float speed); void changeYaw (float speed); void checkMsgQueue (void); void checkRadioQueue (void); void checkReload (void); void avoidGrenades (void); void checkGrenadesThrow (void); void checkBurstMode (float distance); void checkSilencer (void); void updateAimDir (void); void updateLookAngles (void); void updateBodyAngles (void); void updateLookAnglesNewbie (const Vector &direction, float delta); void setIdealReactionTimers (bool actual = false); void updateHearing (void); void postprocessGoals (const IntArray &goals, int *result); void processPickups (void); void checkTerrain (float movedDistance, const Vector &dirNormal); void checkDarkness (void); void checkParachute (void); void getCampDirection (Vector *dest); void collectGoalExperience (int damage); void collectDataExperience (edict_t *attacker, int damage); void searchShortestPath (int srcIndex, int destIndex); void searchPath (int srcIndex, int destIndex, SearchPathType pathType = SEARCH_PATH_FASTEST); void clearRoute (void); void sayDebug (const char *format, ...); void frame (void); void resetCollision (void); void ignoreCollision (void); void setConditions (void); void overrideConditions (void); void updateEmotions (void); void setStrafeSpeed (const Vector &moveDir, float strafeSpeed); void updateTeamJoin (void); void updateTeamCommands (void); void decideFollowUser (void); void attackMovement (void); void getValidPoint (void); void fireWeapons (void); void selectWeapons (float distance, int index, int id, int choosen); void focusEnemy (void); void selectBestWeapon (void); void selectSecondary (void); void selectWeaponByName (const char *name); void selectWeaponById (int num); void completeTask (void); void processTasks (void); void normal_ (void); void spraypaint_ (void); void huntEnemy_ (void); void seekCover_ (void); void attackEnemy_ (void); void pause_ (void); void blind_ (void); void camp_ (void); void hide_ (void); void moveToPos_ (void); void plantBomb_ (void); void bombDefuse_ (void); void followUser_ (void); void throwExplosive_ (void); void throwFlashbang_ (void); void throwSmoke_ (void); void doublejump_ (void); void escapeFromBomb_ (void); void pickupItem_ (void); void shootBreakable_ (void); edict_t *lookupButton (const char *targetName); edict_t *lookupBreakable (void); edict_t *correctGrenadeVelocity (const char *model); const Vector &getEnemyBodyOffset (void); Vector calcThrow (const Vector &start, const Vector &stop); Vector calcToss (const Vector &start, const Vector &stop); Vector isBombAudible (void); Vector getBodyOffsetError (float distance); uint8 computeMsec (void); private: bool isOnLadder (void) const { return pev->movetype == MOVETYPE_FLY; } bool isOnFloor (void) const { return (pev->flags & (FL_ONGROUND | FL_PARTIALGROUND)) != 0; } bool isInWater (void) const { return pev->waterlevel >= 2; } public: entvars_t *pev; int m_wantedTeam; // player team bot wants select int m_wantedClass; // player model bot wants to select int m_difficulty; // bots hard level int m_moneyAmount; // amount of money in bot's bank float m_spawnTime; // time this bot spawned float m_timeTeamOrder; // time of last radio command float m_slowFrameTimestamp; // time to per-second think float m_timeRepotingInDelay; // time to delay report-in float m_nextBuyTime; // next buy time float m_checkDarkTime; // check for darkness time float m_preventFlashing; // bot turned away from flashbang float m_flashLevel; // flashlight level float m_blindTime; // time when bot is blinded float m_blindMoveSpeed; // mad speeds when bot is blind float m_blindSidemoveSpeed; // mad side move speeds when bot is blind float m_fallDownTime; // time bot started to fall float m_duckForJump; // is bot needed to duck for double jump float m_baseAgressionLevel; // base aggression level (on initializing) float m_baseFearLevel; // base fear level (on initializing) float m_agressionLevel; // dynamic aggression level (in game) float m_fearLevel; // dynamic fear level (in game) float m_nextEmotionUpdate; // next time to sanitize emotions float m_thinkFps; // skip some frames in bot thinking float m_thinkInterval; // interval between frames float m_goalValue; // ranking value for this waypoint float m_viewDistance; // current view distance float m_maxViewDistance; // maximum view distance float m_retreatTime; // time to retreat? float m_enemyUpdateTime; // time to check for new enemies float m_enemyReachableTimer; // time to recheck if enemy reachable float m_enemyIgnoreTimer; // ignore enemy for some time float m_seeEnemyTime; // time bot sees enemy float m_enemySurpriseTime; // time of surprise float m_idealReactionTime; // time of base reaction float m_actualReactionTime; // time of current reaction time float m_timeNextTracking; // time waypoint index for tracking player is recalculated float m_firePause; // time to pause firing float m_shootTime; // time to shoot float m_timeLastFired; // time to last firing int m_numEnemiesLeft; // number of enemies alive left on map int m_numFriendsLeft; // number of friend alive left on map int m_retryJoin; // retry count for chosing team/class int m_startAction; // team/class selection state int m_voteKickIndex; // index of player to vote against int m_lastVoteKick; // last index int m_voteMap; // number of map to vote for int m_logotypeIndex; // index for logotype int m_buyState; // current count in buying int m_blindButton; // buttons bot press, when blind int m_radioOrder; // actual command int m_actMessageIndex; // current processed message int m_pushMessageIndex; // offset for next pushed message int m_prevGoalIndex; // holds destination goal waypoint int m_chosenGoalIndex; // used for experience, same as above int m_lastDamageType; // stores last damage int m_team; // bot team int m_currentWeapon; // one current weapon for each bot int m_ammoInClip[MAX_WEAPONS]; // ammo in clip for each weapons int m_ammo[MAX_AMMO_SLOTS]; // total ammo amounts bool m_isVIP; // bot is vip? bool m_notKilled; // has the player been killed or has he just respawned bool m_notStarted; // team/class not chosen yet bool m_ignoreBuyDelay; // when reaching buyzone in the middle of the round don't do pauses bool m_inBombZone; // bot in the bomb zone or not bool m_inBuyZone; // bot currently in buy zone bool m_inVIPZone; // bot in the vip satefy zone bool m_buyingFinished; // done with buying bool m_buyPending; // bot buy is pending bool m_hasDefuser; // does bot has defuser bool m_hasNVG; // does bot has nightvision goggles bool m_usesNVG; // does nightvision goggles turned on bool m_hasC4; // does bot has c4 bomb bool m_hasProgressBar; // has progress bar on a HUD bool m_jumpReady; // is double jump ready bool m_canChooseAimDirection; // can choose aiming direction bool m_isEnemyReachable; // direct line to enemy edict_t *m_doubleJumpEntity; // pointer to entity that request double jump edict_t *m_radioEntity; // pointer to entity issuing a radio command edict_t *m_enemy; // pointer to enemy entity edict_t *m_lastEnemy; // pointer to last enemy entity edict_t *m_lastVictim; // pointer to killed entity edict_t *m_trackingEdict; // pointer to last tracked player when camping/hiding Vector m_waypointOrigin; // origin of waypoint Vector m_destOrigin; // origin of move destination Vector m_position; // position to move to in move to position task Vector m_doubleJumpOrigin; // origin of double jump Vector m_lastEnemyOrigin; // vector to last enemy origin ChatCollection m_sayTextBuffer; // holds the index & the actual message of the last unprocessed text message of a player BurstMode m_weaponBurstMode; // bot using burst mode? (famas/glock18, but also silencer mode) Personality m_personality; // bots type Array m_tasks; public: Bot (edict_t *bot, int difficulty, int personality, int team, int member, const String &steamId); ~Bot (void); public: void slowFrame (void); // the main function that decides intervals of running bot ai void fastFrame (void); /// the things that can be executed while skipping frames void processBlind (int alpha); void processDamage (edict_t *inflictor, int damage, int armor, int bits); void showDebugOverlay (void); void newRound (void); void processBuyzoneEntering (int buyState); void pushMsgQueue (int message); void prepareChatMessage (const String &message); void checkForChat (void); void showChaterIcon (bool show); void clearSearchNodes (void); void processBreakables (edict_t *touch); void avoidIncomingPlayers (edict_t *touch); void startTask (TaskID id, float desire, int data, float time, bool resume); void clearTask (TaskID id); void filterTasks (void); void clearTasks (void); void dropWeaponForUser (edict_t *user, bool discardC4); void say (const char *text); void sayTeam (const char *text); void pushChatMessage (int type, bool isTeamSay = false); void pushRadioMessage (int message); void pushChatterMessage (int message); void processChatterMessage (const char *tempMessage); void tryHeadTowardRadioMessage (void); void kill (void); void kick (void); void resetDoubleJump (void); void startDoubleJump (edict_t *ent); bool hasHostage (void); bool usesRifle (void); bool usesPistol (void); bool usesSniper (void); bool usesSubmachine (void); bool usesZoomableRifle (void); bool usesBadWeapon (void); bool usesCampGun (void); bool hasPrimaryWeapon (void); bool hasSecondaryWeapon (void); bool hasShield (void); bool isShieldDrawn (void); bool searchOptimalPoint (void); bool seesEntity (const Vector &dest, bool fromBody = false); int index (void); int getAmmo (void); int getNearestToPlantedBomb (void); float getFrameInterval (void); Task *getTask (void); public: inline int getAmmoInClip (void) const { return m_ammoInClip[m_currentWeapon]; } inline Vector getCenter (void) const { return (pev->absmax + pev->absmin) * 0.5; }; inline Vector getEyesPos (void) const { return pev->origin + pev->view_ofs; }; inline TaskID taskId (void) { return getTask ()->id; } inline edict_t *ent (void) { return pev->pContainingEntity; }; }; // manager class class BotManager final : public Singleton { private: float m_timeRoundStart; float m_timeRoundEnd; float m_timeRoundMid; float m_maintainTime; // time to maintain bot creation float m_quotaMaintainTime; // time to maintain bot quota float m_grenadeUpdateTime; // time to update active grenades float m_entityUpdateTime; // time to update intresting entities float m_plantSearchUpdateTime; // time to update for searching planted bomb float m_lastChatTime; // global chat time timestamp float m_timeBombPlanted; // time the bomb were planted float m_lastRadioTime[MAX_TEAM_COUNT]; // global radio time int m_lastWinner; // the team who won previous round int m_lastDifficulty; // last bots difficulty int m_bombSayStatus; // some bot is issued whine about bomb int m_lastRadio[MAX_TEAM_COUNT]; bool m_leaderChoosen[MAX_TEAM_COUNT]; // is team leader choose theese round bool m_economicsGood[MAX_TEAM_COUNT]; // is team able to buy anything bool m_deathMsgSent; // for fake ping bool m_bombPlanted; bool m_botsCanPause; bool m_roundEnded; Array m_activeGrenades; // holds currently active grenades on the map Array m_intrestingEntities; // holds currently intresting entities on the map Array m_creationTab; // bot creation tab Array m_filters; Bot *m_bots[MAX_ENGINE_PLAYERS]; // all available bots edict_t *m_killerEntity; // killer entity for bots protected: BotCreationResult create (const String &name, int difficulty, int personality, int team, int member); public: BotManager (void); ~BotManager (void); public: Bot *getBot (int index); Bot *getBot (edict_t *ent); Bot *getAliveBot (void); Bot *getHighfragBot (int team); int index (edict_t *ent); int getHumansCount (bool ignoreSpectators = false); int getAliveHumansCount (void); int getBotCount (void); void setBombPlanted (bool isPlanted); void countTeamPlayers (int &ts, int &cts); void slowFrame (void); void frame (void); void createKillerEntity (void); void destroyKillerEntity (void); void touchKillerEntity (Bot *bot); void destroy (void); void destroy (int index); void addbot (const String &name, int difficulty, int personality, int team, int member, bool manual); void addbot (const String &name, const String &difficulty, const String &personality, const String &team, const String &member, bool manual); void serverFill (int selection, int personality = PERSONALITY_NORMAL, int difficulty = -1, int numToAdd = -1); void kickEveryone (bool instant = false, bool zeroQuota = true); bool kickRandom (bool decQuota = true, Team fromTeam = TEAM_UNASSIGNED); void kickBot (int index); void kickFromTeam (Team team, bool removeAll = false); void killAllBots (int team = -1); void maintainQuota (void); void initQuota (void); void initRound (void); void decrementQuota (int by = 1); void selectLeaders (int team, bool reset); void listBots (void); void setWeaponMode (int selection); void updateTeamEconomics (int team, bool setTrue = false); void updateBotDifficulties (void); void reset (void); void initFilters (void); void resetFilters (void); void updateActiveGrenade (void); void updateIntrestingEntities (void); void calculatePingOffsets (void); void sendPingOffsets (edict_t *to); void sendDeathMsgFix (void); void captureChatRadio (const char *cmd, const char *arg, edict_t *ent); void notifyBombDefuse (void); void execGameEntity (entvars_t *vars); bool isTeamStacked (int team); public: Array &searchActiveGrenades (void) { return m_activeGrenades; } Array &searchIntrestingEntities (void) { return m_intrestingEntities; } bool hasActiveGrenades (void) const { return !m_activeGrenades.empty (); } bool hasIntrestingEntities (void) const { return !m_intrestingEntities.empty (); } bool checkTeamEco (int team) const { return m_economicsGood[team]; } int getLastWinner (void) const { return m_lastWinner; } void setLastWinner (int winner) { m_lastWinner = winner; } // get the list of filters Array &getFilters (void) { return m_filters; } void createRandom (bool manual = false) { addbot ("", -1, -1, -1, -1, manual); } void updateDeathMsgState (bool sent) { m_deathMsgSent = sent; } bool isBombPlanted (void) const { return m_bombPlanted; } float getTimeBombPlanted (void) const { return m_timeBombPlanted; } float getRoundStartTime (void) const { return m_timeRoundStart; } float getRoundMidTime (void) const { return m_timeRoundMid; } float getRoundEndTime (void) const { return m_timeRoundEnd; } bool isRoundOver (void) const { return m_roundEnded; } void setRoundOver (const bool over) { m_roundEnded = over; } bool canPause (void) const { return m_botsCanPause; } void setCanPause (const bool pause) { m_botsCanPause = pause; } bool hasBombSay (int type) { return (m_bombSayStatus & type) == type; } void clearBombSay (int type) { m_bombSayStatus &= ~type; } void setPlantedBombSearchTimestamp (const float timestamp) { m_plantSearchUpdateTime = timestamp; } float getPlantedBombSearchTimestamp (void) const { return m_plantSearchUpdateTime; } void setLastRadioTimestamp (const int team, const float timestamp) { m_lastRadioTime[team] = timestamp; } float getLastRadioTimestamp (const int team) const { return m_lastRadioTime[team]; } void setLastRadio (const int team, const int radio) { m_lastRadio[team] = radio; } int getLastRadio (const int team) const { return m_lastRadio[team]; } void setLastChatTimestamp (const float timestamp) { m_lastChatTime = timestamp; } float getLastChatTimestamp (void) const { return m_lastChatTime; } // some bots are online ? bool hasBotsOnline (void) { return getBotCount () > 0; } }; // waypoint operation class class Waypoint final : public Singleton { public: friend class Bot; private: struct Bucket { int x, y, z; }; int m_editFlags; int m_numWaypoints; int m_loadTries; int m_cacheWaypointIndex; int m_lastJumpWaypoint; int m_visibilityIndex; int m_findWPIndex; int m_facingAtIndex; int m_highestDamage[MAX_TEAM_COUNT]; float m_timeJumpStarted; float m_autoPathDistance; float m_pathDisplayTime; float m_arrowDisplayTime; float m_waypointDisplayTime[MAX_WAYPOINTS]; float m_waypointLightLevel[MAX_WAYPOINTS]; bool m_waypointPaths; bool m_isOnLadder; bool m_endJumpPoint; bool m_learnJumpWaypoint; bool m_waypointsChanged; bool m_needsVisRebuild; Vector m_learnVelocity; Vector m_learnPosition; Vector m_bombPos; Vector m_lastWaypoint; IntArray m_terrorPoints; IntArray m_ctPoints; IntArray m_goalPoints; IntArray m_campPoints; IntArray m_sniperPoints; IntArray m_rescuePoints; IntArray m_visitedGoals; IntArray m_buckets[MAX_WAYPOINT_BUCKET_MAX][MAX_WAYPOINT_BUCKET_MAX][MAX_WAYPOINT_BUCKET_MAX]; String m_tempInfo; FloydMatrix *m_matrix; Experience *m_experience; edict_t *m_editor; Path *m_paths[MAX_WAYPOINTS]; uint8 m_visLUT[MAX_WAYPOINTS][MAX_WAYPOINTS / 4]; public: Waypoint (void); ~Waypoint (void); public: int getFacingIndex (void); int getFarest (const Vector &origin, float maxDistance = 32.0); int getNearest (const Vector &origin, float minDistance = 9999.0f, int flags = -1); int getNearestNoBuckets (const Vector &origin, float minDistance = 9999.0f, int flags = -1); int getEditorNeareset (void); int getDangerIndex (int team, int start, int goal); int getDangerValue (int team, int start, int goal); int getDangerDamage (int team, int start, int goal); int getPathDist (int srcIndex, int destIndex); int clearConnections (int index); float calculateTravelTime (float maxSpeed, const Vector &src, const Vector &origin); bool load (void); bool isVisible (int srcIndex, int destIndex); bool isStandVisible (int srcIndex, int destIndex); bool isDuckVisible (int srcIndex, int destIndex); bool isConnected (int pointA, int pointB); bool isConnected (int index); bool isReachable (Bot *bot, int index); bool isNodeReacheable (const Vector &src, const Vector &destination); bool checkNodes (void); bool loadPathMatrix (void); bool saveExtFile (const char *ext, const char *type, const char *magic, int version, uint8 *data, int32 size); bool loadExtFile (const char *ext, const char *type, const char *magic, int version, uint8 *data); bool isVisited (int index); void save (void); void init (void); void frame (void); void loadExperience (void); void loadVisibility (void); void initTypes (void); void initLightLevels (void); void addPath (int addIndex, int pathIndex, float distance); void push (int flags, const Vector &waypointOrigin = Vector::null ()); void erase (int target); void toggleFlags (int toggleFlag); void setRadius (int index, float radius); void rebuildVisibility (void); void pathCreate (char dir); void erasePath (void); void cachePoint (int index); void calculatePathRadius (int index); void cleanupPathMemory (void); void saveExperience (void); void saveVisibility (void); void addBasic (void); void eraseFromDisk (void); void initPathMatrix (void); void savePathMatrix (void); void setSearchIndex (int index); void startLearnJump (void); void setVisited (int index); void clearVisited (void); void initBuckets (void); void addToBucket (const Vector &pos, int index); void eraseFromBucket (const Vector &pos, int index); void setBombPos (bool reset = false, const Vector &pos = Vector::null ()); void closeSocket (int sock); void updateGlobalExperience (void); const char *getDataDirectory (bool isMemoryFile = false); const char *getWaypointFilename (bool isMemoryFile = false); WaypointDownloadError downloadWaypoint (void); Bucket locateBucket (const Vector &pos); IntArray searchRadius (float radius, const Vector &origin, int maxCount = -1); IntArray &getWaypointsInBucket (const Vector &pos); public: Experience *getRawExperience (void) { return m_experience; } int getHighestDamageForTeam (int team) const { return m_highestDamage[team]; } void setHighestDamageForTeam (int team, int value) { m_highestDamage[team] = value; } const char *getAuthor (void) const { return m_tempInfo.chars (); } bool hasChanged (void) const { return m_waypointsChanged; } bool hasEditFlag (int flag) const { return !!(m_editFlags & flag); } void setEditFlag (int flag) { m_editFlags |= flag; } void clearEditFlag (int flag) { m_editFlags &= ~flag; } void setAutoPathDistance (const float distance) { m_autoPathDistance = distance; } const Vector &getBombPos (void) const { return m_bombPos; } // access paths Path &operator [] (int index) { return *m_paths[index]; } // check waypoints range bool exists (int index) const { return index >= 0 && index < m_numWaypoints; } // get real waypoint num int length (void) const { return m_numWaypoints; } // get the light level of waypoint float getLightLevel (int id) const { return m_waypointLightLevel[id]; } // check if has editor bool hasEditor (void) const { return !!m_editor; } // set's the waypoint editor void setEditor (edict_t *ent) { m_editor = ent; } // get the current waypoint editor edict_t *getEditor (void) { return m_editor; } }; // mostly config stuff, and some stuff dealing with menus class Config final : public Singleton { private: Array m_chat; Array > m_chatter; Array m_botNames; Array m_replies; Array m_weapons; // weapon info gathered through engine messages WeaponProp m_weaponProps[MAX_WEAPONS + 1]; // default tables for personality weapon preferences, overridden by general.cfg int m_normalWeaponPrefs[NUM_WEAPONS] = { 0, 2, 1, 4, 5, 6, 3, 12, 10, 24, 25, 13, 11, 8, 7, 22, 23, 18, 21, 17, 19, 15, 17, 9, 14, 16 }; int m_rusherWeaponPrefs[NUM_WEAPONS] = { 0, 2, 1, 4, 5, 6, 3, 24, 19, 22, 23, 20, 21, 10, 12, 13, 7, 8, 11, 9, 18, 17, 19, 25, 15, 16 }; int m_carefulWeaponPrefs[NUM_WEAPONS] = { 0, 2, 1, 4, 25, 6, 3, 7, 8, 12, 10, 13, 11, 9, 24, 18, 14, 17, 16, 15, 19, 20, 21, 22, 23, 5 }; int m_grenadeBuyPrecent[NUM_WEAPONS - 23] = { 95, 85, 60 }; int m_botBuyEconomyTable[NUM_WEAPONS - 15] = { 1900, 2100, 2100, 4000, 6000, 7000, 16000, 1200, 800, 1000, 3000 }; int *m_weaponPrefs[3] = { m_normalWeaponPrefs, m_rusherWeaponPrefs, m_carefulWeaponPrefs }; public: Config (void) = default; ~Config (void) = default; public: // load the configuration files void load (bool onlyMain); // picks random bot name BotName *pickBotName (void); // remove bot name from used list void clearUsedName (Bot *bot); // initialize weapon info void initWeapons (void); // fix weapon prices (ie for elite) void adjustWeaponPrices (void); WeaponInfo &findWeaponById (int id); public: // get the chat array Array &getChat (void) { return m_chat; } // get's the chatter array Array > &getChatter (void) { return m_chatter; } // get's the replies array Array &getReplies (void) { return m_replies; } // get's the weapon info data Array &getWeapons (void) { return m_weapons; } // get's raw weapon info WeaponInfo *getRawWeapons (void) { return m_weapons.begin (); } // set's the weapon properties void setWeaponProp (const WeaponProp &prop) { m_weaponProps[prop.id] = prop; } // get's the weapons prop const WeaponProp &getWeaponProp (int id) const { return m_weaponProps[id]; } // get's weapon preferences for personality int *getWeaponPrefs (int personality) const { return m_weaponPrefs[personality]; } // get economics value int *getEconLimit (void) { return m_botBuyEconomyTable; } // get's grenade buy percents bool chanceToBuyGrenade (const int grenadeType) const { return RandomSequence::ref ().chance (m_grenadeBuyPrecent[grenadeType]); } }; class BotUtils final : public Singleton { private: bool m_needToSendWelcome; float m_welcomeReceiveTime; StringArray m_sentences; Array m_clients; Array > m_tags; public: BotUtils (void); ~BotUtils (void) = default; public: // need to send welcome message ? void checkWelcome (void); // gets the weapon alias as hlsting, maybe move to config... int getWeaponAlias (bool needString, const char *weaponAlias, int weaponIndex = -1); // gets the build number of bot int buildNumber (void); // gets the shooting cone deviation float getShootingCone (edict_t *ent, const Vector &position); // check if origin is visible from the entity side bool isVisible (const Vector &origin, edict_t *ent); // check if entity is alive bool isAlive (edict_t *ent); // check if origin is inside view cone of entity bool isInViewCone (const Vector &origin, edict_t *ent); // checks if entitiy is fakeclient bool isFakeClient (edict_t *ent); // check if entitiy is a player bool isPlayer (edict_t *ent); // check if entity is a vip bool isPlayerVIP (edict_t *ent); // opens config helper bool openConfig (const char *fileName, const char *errorIfNotExists, MemFile *outFile, bool languageDependant = false); // nearest player search helper bool findNearestPlayer (void **holder, edict_t *to, float searchDistance = 4096.0, bool sameTeam = false, bool needBot = false, bool needAlive = false, bool needDrawn = false, bool needBotWithC4 = false); // simple loggerfor bots void logEntry (bool outputToConsole, int logLevel, const char *format, ...); // tracing decals for bots spraying logos void traceDecals (entvars_t *pev, TraceResult *trace, int logotypeIndex); // attaches sound to client struct void attachSoundsToClients (edict_t *ent, const char *sample, float volume); // simulate sound for players void simulateSoundUpdates (int playerIndex); // simple format utility const char *format (const char *format, ...); // update stats on clients void updateClients (void); // chat helper to strip the clantags out of the string void stripTags (String &line); // chat helper to make player name more human-like void humanizePlayerName (String &playerName); // chat helper to add errors to the bot chat string void addChatErrors (String &line); // chat helper to find keywords for given string bool checkKeywords (const String &line, String &reply); public: // re-show welcome after changelevel ? void setNeedForWelcome (bool need) { m_needToSendWelcome = need; } // get array of clients Array &getClients (void) { return m_clients; } // get clients as const-reference const Array &getClients (void) const { return m_clients; } // get single client as ref Client &getClient (const int index) { return m_clients[index]; } // checks if string is not empty bool isEmptyStr (const char *input) const { if (input == nullptr) { return true; } return *input == '\0'; } }; // bot command manager class BotControl final : public Singleton { public: using Handler = int (BotControl::*) (void); using MenuHandler = int (BotControl::*) (int); public: // generic bot command struct BotCmd { String name, format, help; Handler handler; }; // single bot menu struct Menu { int ident, slots; String text; MenuHandler handler; }; private: StringArray m_args; Array m_cmds; Array m_menus; edict_t *m_ent; bool m_isFromConsole; bool m_isMenuFillCommand; int m_menuServerFillTeam; int m_interMenuData[4] = { 0, }; public: BotControl (void); ~BotControl (void) = default; private: int cmdAddBot (void); int cmdKickBot (void); int cmdKickBots (void); int cmdKillBots (void); int cmdFill (void); int cmdVote (void); int cmdWeaponMode (void); int cmdVersion (void); int cmdWaypointMenu (void); int cmdMenu (void); int cmdList (void); int cmdWaypoint (void); int cmdWaypointOn (void); int cmdWaypointOff (void); int cmdWaypointAdd (void); int cmdWaypointAddBasic (void); int cmdWaypointSave (void); int cmdWaypointLoad (void); int cmdWaypointErase (void); int cmdWaypointDelete (void); int cmdWaypointCheck (void); int cmdWaypointCache (void); int cmdWaypointClean (void); int cmdWaypointSetRadius (void); int cmdWaypointSetFlags (void); int cmdWaypointTeleport (void); int cmdWaypointPathCreate (void); int cmdWaypointPathDelete (void); int cmdWaypointPathSetAutoDistance (void); int cmdWaypointAcquireEditor (void); int cmdWaypointReleaseEditor (void); 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 menuWaypointPage1 (int item); int menuWaypointPage2 (int item); int menuWaypointRadius (int item); int menuWaypointType (int item); int menuWaypointFlag (int item); int menuWaypointPath (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 (void); public: bool executeCommands (void); bool executeMenus (void); void showMenu (int id); void kickBotByMenu (int page); void msg (const char *fmt, ...); void assignAdminRights (edict_t *ent, char *infobuffer); void maintainAdminRights (void); public: void setFromConsole (const bool console) { m_isFromConsole = console; } void setArgs (const StringArray &args) { m_args.assign (args); } void setIssuer (edict_t *ent) { m_ent = ent; } void fixMissingArgs (size_t num) { if (num < m_args.length ()) { return; } do { m_args.push (""); } while (num--); } int getInt (size_t arg) const { if (!hasArg (arg)) { return 0; } return m_args[arg].toInt32 (); } const String &getStr (size_t arg) { static String empty ("empty"); if (!hasArg (arg) || m_args[arg].empty ()) { return empty; } return m_args[arg]; } bool hasArg (size_t arg) const { return arg < m_args.length (); } StringArray collectArgs (void) { StringArray args; for (int i = 0; i < engfuncs.pfnCmd_Argc (); i++) { args.push (engfuncs.pfnCmd_Argv (i)); } return args; } public: // for the server commands static void handleEngineCommands (void); // for the client commands bool handleClientCommands (edict_t *ent); // for the client menu commands bool handleMenuCommands (edict_t *ent); }; #include // expose bot super-globals static auto &waypoints = Waypoint::ref (); static auto &bots = BotManager::ref (); static auto &rng = RandomSequence::ref (); static auto &conf = Config::ref (); static auto &util = BotUtils::ref (); static auto &ctrl = BotControl::ref (); static auto &game = Game::ref (); static auto &illum = LightMeasure::ref (); // very global convars extern ConVar yb_jasonmode; extern ConVar yb_communication_type; extern ConVar yb_ignore_enemies; extern ConVar yb_chat; extern ConVar yb_language; inline int Bot::index (void) { return game.indexOfEntity (ent ()); } inline int Game::getTeam (edict_t *ent) { if (game.isNullEntity (ent)) { return TEAM_UNASSIGNED; } return util.getClient (indexOfEntity (ent) - 1).team; }