From 6dfb09f110086bc2cbde81ebfec0b9bc81890ec8 Mon Sep 17 00:00:00 2001 From: jeefo Date: Wed, 7 May 2025 13:07:40 +0300 Subject: [PATCH] fix: logos config not initialized (resolves #691) bot: make sure rescue zone icon blinking to consider bot reached rescue zone when escorting hostages (ref #688) bot: remove hardcoded radio communication randoms, so they're now depends on bots personality refactor: some refactoring of code --- CMakeLists.txt | 16 ++++++++------ ext/crlib | 2 +- ext/linkage | 2 +- inc/analyze.h | 2 +- inc/engine.h | 8 +++---- inc/graph.h | 12 +++++------ inc/hooks.h | 27 ++++++++++++----------- inc/manager.h | 2 +- inc/planner.h | 2 +- inc/vision.h | 2 +- inc/vistable.h | 2 +- inc/yapb.h | 55 ++++++++++++++++++++++++----------------------- src/analyze.cpp | 2 +- src/botlib.cpp | 56 ++++++++++++++++++++++++++---------------------- src/combat.cpp | 34 ++++++++++++++--------------- src/config.cpp | 3 ++- src/control.cpp | 15 +++++++------ src/engine.cpp | 12 +++++------ src/graph.cpp | 14 ++++++------ src/hooks.cpp | 8 +++---- src/manager.cpp | 26 ++++++++++++++++++++-- src/navigate.cpp | 6 +++--- src/planner.cpp | 4 ++-- src/tasks.cpp | 3 ++- src/vision.cpp | 4 ++-- src/vistable.cpp | 2 +- 26 files changed, 180 insertions(+), 141 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7081e5..ae18fad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(YAPB_SRC "src/vistable.cpp" ) -add_library(${PROJECT_NAME} MODULE ${YAPB_SRC}) +add_library(${PROJECT_NAME} SHARED ${YAPB_SRC}) find_package(Git QUIET) if(GIT_FOUND) @@ -109,10 +109,14 @@ if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" if(WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") set_property(TARGET ${PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() - - if(CMAKE_SIZEOF_VOID_P EQUAL 8 OR CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" OR CMAKE_SYSTEM_PROCESSOR MATCHES "^ppc") - target_compile_options(${PROJECT_NAME} PRIVATE -fPIC) - target_link_options(${PROJECT_NAME} PRIVATE -fPIC) + + if(VITA) + target_compile_options(${PROJECT_NAME} PRIVATE -fno-use-cxa-atexit) + else() + if(CMAKE_SIZEOF_VOID_P EQUAL 8 OR CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" OR CMAKE_SYSTEM_PROCESSOR MATCHES "^ppc") + target_compile_options(${PROJECT_NAME} PRIVATE -fPIC) + target_link_options(${PROJECT_NAME} PRIVATE -fPIC) + endif() endif() elseif(WIN32 AND MSVC) set_property(TARGET ${PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") @@ -132,7 +136,7 @@ if(WIN32 OR MINGW) target_sources(${PROJECT_NAME} PRIVATE "vc/yapb.rc") elseif(ANDROID) target_link_libraries(${PROJECT_NAME} PRIVATE m dl log) -else() +elseif(NOT VITA) target_link_libraries(${PROJECT_NAME} PRIVATE m dl pthread) endif() diff --git a/ext/crlib b/ext/crlib index 01a2628..43f0acc 160000 --- a/ext/crlib +++ b/ext/crlib @@ -1 +1 @@ -Subproject commit 01a2628642b5d28c42d115bbe99167756376839c +Subproject commit 43f0acc90e9042efb8e9f7287bfa6935a0f4bc90 diff --git a/ext/linkage b/ext/linkage index bd5617f..a21540a 160000 --- a/ext/linkage +++ b/ext/linkage @@ -1 +1 @@ -Subproject commit bd5617f41c84fa1f4e5800c75ea286f4d3cba62e +Subproject commit a21540a52d7559333ad9d8326411daf78af62891 diff --git a/inc/analyze.h b/inc/analyze.h index 575c090..e1cd7fd 100644 --- a/inc/analyze.h +++ b/inc/analyze.h @@ -53,7 +53,7 @@ private: void cleanup (); // show overlay message about analyzing - void displayOverlayMessage (); + void displayOverlayMessage () const; public: diff --git a/inc/engine.h b/inc/engine.h index 582954b..665aebe 100644 --- a/inc/engine.h +++ b/inc/engine.h @@ -194,7 +194,7 @@ public: void levelShutdown (); // display world line - void drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, const Color &color, int brightness, int speed, int life, DrawLine type = DrawLine::Simple); + void drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, const Color &color, int brightness, int speed, int life, DrawLine type = DrawLine::Simple) const; // test line void testLine (const Vector &start, const Vector &end, int ignoreFlags, edict_t *ignoreEntity, TraceResult *ptr); @@ -260,13 +260,13 @@ public: void searchEntities (StringRef field, StringRef value, EntitySearch functor); // search entities in sphere - void searchEntities (const Vector &position, float radius, EntitySearch functor); + void searchEntities (const Vector &position, float radius, EntitySearch functor) const; // check if map has entity bool hasEntityInGame (StringRef classname); // print the version to server console on startup - void printBotVersion (); + void printBotVersion () const; // ensure prosperous gaming environment as per: https://github.com/yapb/yapb/issues/575 void ensureHealthyGameEnvironment (); @@ -388,7 +388,7 @@ public: bool checkVisibility (edict_t *ent, uint8_t *set); // get pvs/pas visibility set - uint8_t *getVisibilitySet (Bot *bot, bool pvs); + uint8_t *getVisibilitySet (Bot *bot, bool pvs) const; // what kind of game engine / game dll / mod / tool we're running ? bool is (const int type) const { diff --git a/inc/graph.h b/inc/graph.h index 1978a89..d5ff895 100644 --- a/inc/graph.h +++ b/inc/graph.h @@ -218,9 +218,9 @@ public: bool convertOldFormat (); bool isConnected (int a, int b); bool isConnected (int index); - bool isNodeReacheableEx (const Vector &src, const Vector &destination, const float maxHeight); - bool isNodeReacheable (const Vector &src, const Vector &destination); - bool isNodeReacheableWithJump (const Vector &src, const Vector &destination); + bool isNodeReacheableEx (const Vector &src, const Vector &destination, const float maxHeight) const; + bool isNodeReacheable (const Vector &src, const Vector &destination) const; + bool isNodeReacheableWithJump (const Vector &src, const Vector &destination) const; bool checkNodes (bool teleportPlayer, bool onlyPaths = false); bool isVisited (int index); @@ -255,13 +255,13 @@ public: void eraseFromBucket (const Vector &pos, int index); void setBombOrigin (bool reset = false, const Vector &pos = nullptr); void unassignPath (int from, int to); - void convertFromPOD (Path &path, const PODPath &pod); + void convertFromPOD (Path &path, const PODPath &pod) const; void convertToPOD (const Path &path, PODPath &pod); - void convertCampDirection (Path &path); + void convertCampDirection (Path &path) const; void setAutoPathDistance (const float distance); void showStats (); void showFileInfo (); - void emitNotify (int32_t sound); + void emitNotify (int32_t sound) const; void syncCollectOnline (); void collectOnline (); diff --git a/inc/hooks.h b/inc/hooks.h index a65396c..29522a6 100644 --- a/inc/hooks.h +++ b/inc/hooks.h @@ -109,19 +109,22 @@ public: }; // used for transit calls between game dll and engine without all needed functions on bot side -class DynamicLinkerHook : public Singleton { +class EntityLinkHook : public Singleton { private: #if defined(CR_WINDOWS) # define DLSYM_FUNCTION GetProcAddress # define DLCLOSE_FUNCTION FreeLibrary +#elif defined(CR_PSVITA) // just a shim +# define DLSYM_FUNCTION vrtld_dlsym +# define DLCLOSE_FUNCTION vrtld_dlclose #else # define DLSYM_FUNCTION dlsym # define DLCLOSE_FUNCTION dlclose #endif private: - using DlsymProto = SharedLibrary::Func CR_STDCALL (SharedLibrary::Handle, const char *); - using DlcloseProto = int CR_STDCALL (SharedLibrary::Handle); + using DlsymProto = decltype (DLSYM_FUNCTION); + using DlcloseProto = decltype (DLCLOSE_FUNCTION); private: bool m_paused { false }; @@ -133,16 +136,16 @@ private: SharedLibrary m_self {}; public: - DynamicLinkerHook () = default; - ~DynamicLinkerHook () = default; + EntityLinkHook () = default; + ~EntityLinkHook () = default; public: void initialize (); bool needsBypass () const; - SharedLibrary::Func lookup (SharedLibrary::Handle module, const char *function); + SharedLibrary::Func lookupSymbol (SharedLibrary::Handle module, const char *function); - decltype (auto) close (SharedLibrary::Handle module) { + decltype (auto) freeLibrary (SharedLibrary::Handle module) { if (m_self.handle () == module) { disable (); return m_dlclose (module); @@ -177,15 +180,15 @@ public: } public: - CR_FORCE_STACK_ALIGN static SharedLibrary::Func CR_STDCALL lookupHandler (SharedLibrary::Handle module, const char *function) { - return instance ().lookup (module, function); + CR_FORCE_STACK_ALIGN static SharedLibrary::Func CR_STDCALL lookupHandler (SharedLibrary::Handle handle, const char *function) { + return instance ().lookupSymbol (handle, function); } - CR_FORCE_STACK_ALIGN static int CR_STDCALL closeHandler (SharedLibrary::Handle module) { - return instance ().close (module); + CR_FORCE_STACK_ALIGN static int CR_STDCALL closeHandler (SharedLibrary::Handle handle) { + return instance ().freeLibrary (handle); } }; // expose global -CR_EXPOSE_GLOBAL_SINGLETON (DynamicLinkerHook, entlink); +CR_EXPOSE_GLOBAL_SINGLETON (EntityLinkHook, entlink); CR_EXPOSE_GLOBAL_SINGLETON (ServerQueryHook, fakequeries); diff --git a/inc/manager.h b/inc/manager.h index 437ec74..5fa6f43 100644 --- a/inc/manager.h +++ b/inc/manager.h @@ -95,7 +95,7 @@ public: void kickEveryone (bool instant = false, bool zeroQuota = true); void kickBot (int index); void kickFromTeam (Team team, bool removeAll = false); - void killAllBots (int team = -1, bool silent = false); + void killAllBots (int team = Team::Invalid, bool silent = false); void maintainQuota (); void maintainAutoKill (); void maintainLeaders (); diff --git a/inc/planner.h b/inc/planner.h index 1150b2d..a2b6184 100644 --- a/inc/planner.h +++ b/inc/planner.h @@ -198,7 +198,7 @@ public: bool load (); // flush matrices to disk, so we will not rebuild them on load same map - void save (); + void save () const; // do the pathfinding bool find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance = nullptr); diff --git a/inc/vision.h b/inc/vision.h index 166aeec..64376b5 100644 --- a/inc/vision.h +++ b/inc/vision.h @@ -52,7 +52,7 @@ public: public: // updates bot view frustum - void calculate (Planes &planes, const Vector &viewAngle, const Vector &viewOffset); + void calculate (Planes &planes, const Vector &viewAngle, const Vector &viewOffset) const; // check if object inside frustum plane bool isObjectInsidePlane (const Plane &plane, const Vector ¢er, float height, float radius) const; diff --git a/inc/vistable.h b/inc/vistable.h index 975748f..bcc3a84 100644 --- a/inc/vistable.h +++ b/inc/vistable.h @@ -42,7 +42,7 @@ public: bool visible (int srcIndex, int destIndex, VisIndex vis = VisIndex::Any); void load (); - void save (); + void save () const; void rebuild (); public: diff --git a/inc/yapb.h b/inc/yapb.h index 2235a2c..408d963 100644 --- a/inc/yapb.h +++ b/inc/yapb.h @@ -225,6 +225,7 @@ private: int m_tryOpenDoor {}; // attempt's to open the door int m_liftState {}; // state of lift handling int m_radioSelect {}; // radio entry + int m_radioPercent {}; // radio usage percent (in response) int m_killsCount {}; // the kills count of a bot int m_lastPredictIndex {}; // last predicted path index @@ -370,7 +371,7 @@ private: CountdownTimer m_repathTimer {}; // bots is going to repath his route private: - int pickBestWeapon (Array &vec, int moneySave); + int pickBestWeapon (Array &vec, int moneySave) const; int getRandomCampDir (); int findAimingNode (const Vector &to, int &pathLength); int findNearestNode (); @@ -382,18 +383,18 @@ private: int findGoalPost (int tactic, IntArray *defensive, IntArray *offensive); int bestPrimaryCarried (); int bestSecondaryCarried (); - int bestGrenadeCarried (); - int getBestOwnedWeapon (); - int getBestOwnedPistol (); + int bestGrenadeCarried () const; + int getBestOwnedWeapon () const; + int getBestOwnedPistol () const; int changeNodeIndex (int index); - int numEnemiesNear (const Vector &origin, const float radius); - int numFriendsNear (const Vector &origin, const float radius); + int numEnemiesNear (const Vector &origin, const float radius) const; + int numFriendsNear (const Vector &origin, const float radius) const; float getBombTimeleft () const; float getEstimatedNodeReachTime (); - float isInFOV (const Vector &dest); + float isInFOV (const Vector &dest) const; float getShiftSpeed (); - float calculateScaleFactor (edict_t *ent); + float calculateScaleFactor (edict_t *ent) const; bool canReplaceWeapon (); bool canDuckUnder (const Vector &normal); @@ -418,14 +419,14 @@ private: bool seesEnemy (edict_t *player); bool hasActiveGoal (); bool advanceMovement (); - bool isBombDefusing (const Vector &bombOrigin); + bool isBombDefusing (const Vector &bombOrigin) const; bool isOccupiedNode (int index, bool needZeroVelocity = false); bool seesItem (const Vector &dest, StringRef classname); bool lastEnemyShootable (); bool rateGroundWeapon (edict_t *ent); bool reactOnEnemy (); bool selectBestNextNode (); - bool hasAnyWeapons (); + bool hasAnyWeapons () const; bool hasAnyAmmoInClip (); bool isKnifeMode (); bool isGrenadeWar (); @@ -439,13 +440,13 @@ private: bool isEnemyHidden (edict_t *enemy); bool isEnemyInvincible (edict_t *enemy); bool isEnemyNoTarget (edict_t *enemy); - bool isEnemyInDarkArea (edict_t *enemy); - bool isFriendInLineOfFire (float distance); + bool isEnemyInDarkArea (edict_t *enemy) const; + bool isFriendInLineOfFire (float distance) const; bool isGroupOfEnemies (const Vector &location); bool isPenetrableObstacle (const Vector &dest); - bool isPenetrableObstacle1 (const Vector &dest, int penetratePower); - bool isPenetrableObstacle2 (const Vector &dest, int penetratePower); - bool isPenetrableObstacle3 (const Vector &dest, int penetratePower); + bool isPenetrableObstacle1 (const Vector &dest, int penetratePower) const; + bool isPenetrableObstacle2 (const Vector &dest, int penetratePower) const; + bool isPenetrableObstacle3 (const Vector &dest, int penetratePower) const; bool isEnemyBehindShield (edict_t *enemy); bool checkChatKeywords (String &reply); bool isReplyingToChat (); @@ -455,13 +456,13 @@ private: bool canRunHeavyWeight (); bool isEnemyInSight (Vector &endPos); bool isEnemyNoticeable (float range); - bool isCreature (); - bool isPreviousLadder (); + bool isCreature () const; + bool isPreviousLadder () const; bool isIgnoredItem (edict_t *ent); void doPlayerAvoidance (const Vector &normal); void selectCampButtons (int index); - void instantChatter (int type); + void instantChatter (int type) const; void update (); void runMovement (); void checkSpawnConditions (); @@ -488,7 +489,7 @@ private: void checkFall (); void checkDarkness (); void checkParachute (); - void updatePracticeValue (int damage); + void updatePracticeValue (int damage) const; void updatePracticeDamage (edict_t *attacker, int damage); void findShortestPath (int srcIndex, int destIndex); void findPath (int srcIndex, int destIndex, FindPath pathType = FindPath::Fast); @@ -563,9 +564,9 @@ private: Vector isBombAudible (); Vector getBodyOffsetError (float distance); Vector getCampDirection (const Vector &dest); - Vector getCustomHeight (float distance); + Vector getCustomHeight (float distance) const; - uint8_t computeMsec (); + uint8_t computeMsec () const; private: bool isOnLadder () const { @@ -735,7 +736,7 @@ public: void pushMsgQueue (int message); void prepareChatMessage (StringRef message); void checkForChat (); - void showChatterIcon (bool show, bool disconnect = false); + void showChatterIcon (bool show, bool disconnect = false) const; void clearSearchNodes (); void checkBreakable (edict_t *touch); void checkBreakablesAround (); @@ -757,16 +758,16 @@ public: void sendBotToOrigin (const Vector &origin); void markStale (); bool hasHostage (); - bool hasPrimaryWeapon (); - bool hasSecondaryWeapon (); + bool hasPrimaryWeapon () const; + bool hasSecondaryWeapon () const; bool hasShield (); bool isShieldDrawn (); bool findNextBestNode (); bool findNextBestNodeEx (const IntArray &data, bool handleFails); bool seesEntity (const Vector &dest, bool fromBody = false); - int getAmmo (); - int getAmmo (int id); + int getAmmo () const; + int getAmmo (int id) const; int getNearestToPlantedBomb (); float getConnectionTime (); @@ -793,7 +794,7 @@ public: return getTask ()->id; } - edict_t *ent () { + edict_t *ent () const { return pev->pContainingEntity; }; diff --git a/src/analyze.cpp b/src/analyze.cpp index 7131c2f..4be92e7 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -269,7 +269,7 @@ void GraphAnalyze::cleanup () { } } -void GraphAnalyze::displayOverlayMessage () { +void GraphAnalyze::displayOverlayMessage () const { auto listenserverEdict = game.getLocalEntity (); if (game.isNullEntity (listenserverEdict) || !m_isAnalyzing) { diff --git a/src/botlib.cpp b/src/botlib.cpp index 0de00df..0dbfd70 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -856,7 +856,7 @@ Vector Bot::getCampDirection (const Vector &dest) { return nullptr; } -void Bot::showChatterIcon (bool show, bool disconnect) { +void Bot::showChatterIcon (bool show, bool disconnect) const { // this function depending on show boolean, shows/remove chatter, icon, on the head of bot. if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.as () != 2) { @@ -894,7 +894,7 @@ void Bot::showChatterIcon (bool show, bool disconnect) { } } -void Bot::instantChatter (int type) { +void Bot::instantChatter (int type) const { // this function sends instant chatter messages. if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.as () != 2 @@ -1222,7 +1222,7 @@ bool Bot::canReplaceWeapon () { return isWeaponRestricted (m_currentWeapon); } -int Bot::pickBestWeapon (Array &vec, int moneySave) { +int Bot::pickBestWeapon (Array &vec, int moneySave) const { // this function picks best available weapon from random choice with money save if (vec.length () < 2) { @@ -1890,6 +1890,7 @@ void Bot::setConditions () { if (m_agressionLevel > 1.0f) { m_agressionLevel = 1.0f; } + m_radioPercent = cr::min (m_radioPercent - rg (1, 5), 15); if (rg.chance (10)) { pushChatMessage (Chat::Kill); @@ -2450,7 +2451,7 @@ void Bot::checkRadioQueue () { if (seesEntity (m_radioEntity->v.origin) || m_radioOrder == Radio::StickTogetherTeam) { if (game.isNullEntity (m_targetEntity) && game.isNullEntity (m_enemy) - && rg.chance (m_personality == Personality::Careful ? 80 : 20)) { + && rg.chance (m_radioPercent)) { int numFollowers = 0; @@ -2494,11 +2495,11 @@ void Bot::checkRadioQueue () { } } } - else if (m_radioOrder != Chatter::GoingToPlantBomb && rg.chance (25)) { + else if (m_radioOrder != Chatter::GoingToPlantBomb && rg.chance (m_radioPercent)) { pushRadioMessage (Radio::Negative); } } - else if (m_radioOrder != Chatter::GoingToPlantBomb && rg.chance (35)) { + else if (m_radioOrder != Chatter::GoingToPlantBomb && rg.chance (m_radioPercent)) { pushRadioMessage (Radio::Negative); } } @@ -2530,7 +2531,7 @@ void Bot::checkRadioQueue () { m_fearLevel = 0.0f; } - if (rg.chance (45) && cv_radio_mode.as () == 2) { + if (rg.chance (m_radioPercent) && cv_radio_mode.as () == 2) { pushChatterMessage (Chatter::OnMyWay); } else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as () != 2) { @@ -2538,7 +2539,7 @@ void Bot::checkRadioQueue () { } tryHeadTowardRadioMessage (); } - else if (rg.chance (25)) { + else if (rg.chance (m_radioPercent)) { pushRadioMessage (Radio::Negative); } } @@ -2559,7 +2560,7 @@ void Bot::checkRadioQueue () { case Chatter::ScaredEmotion: case Chatter::PinnedDown: if (((game.isNullEntity (m_enemy) && seesEntity (m_radioEntity->v.origin)) || distanceSq < cr::sqrf (2048.0f) || !m_moveToC4) - && rg.chance (50) + && rg.chance (m_radioPercent) && m_seeEnemyTime + 4.0f < game.time ()) { m_fearLevel -= 0.1f; @@ -2568,22 +2569,22 @@ void Bot::checkRadioQueue () { m_fearLevel = 0.0f; } - if (rg.chance (45) && cv_radio_mode.as () == 2) { + if (rg.chance (m_radioPercent) && cv_radio_mode.as () == 2) { pushChatterMessage (Chatter::OnMyWay); } - else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as () != 2 && rg.chance (50)) { + else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as () != 2 && rg.chance (m_radioPercent)) { pushRadioMessage (Radio::RogerThat); } tryHeadTowardRadioMessage (); } - else if (rg.chance (30) && m_radioOrder == Radio::NeedBackup) { + else if (rg.chance (m_radioPercent) && m_radioOrder == Radio::NeedBackup) { pushRadioMessage (Radio::Negative); } break; case Radio::GoGoGo: if (m_radioEntity == m_targetEntity) { - if (rg.chance (45) && cv_radio_mode.as () == 2) { + if (rg.chance (m_radioPercent) && cv_radio_mode.as () == 2) { pushRadioMessage (Radio::RogerThat); } else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as () != 2) { @@ -2622,7 +2623,7 @@ void Bot::checkRadioQueue () { pushRadioMessage (Radio::RogerThat); resetDoubleJump (); } - else if (rg.chance (35)) { + else if (rg.chance (m_radioPercent)) { pushRadioMessage (Radio::Negative); } break; @@ -2637,7 +2638,7 @@ void Bot::checkRadioQueue () { m_targetEntity = nullptr; startTask (Task::EscapeFromBomb, TaskPri::EscapeFromBomb, kInvalidNodeIndex, 0.0f, true); } - else if (rg.chance (35)) { + else if (rg.chance (m_radioPercent)) { pushRadioMessage (Radio::Negative); } break; @@ -2656,7 +2657,7 @@ void Bot::checkRadioQueue () { break; case Radio::StormTheFront: - if (((game.isNullEntity (m_enemy) && seesEntity (m_radioEntity->v.origin)) || distanceSq < cr::sqrf (1024.0f)) && rg.chance (50)) { + if (((game.isNullEntity (m_enemy) && seesEntity (m_radioEntity->v.origin)) || distanceSq < cr::sqrf (1024.0f)) && rg.chance (m_radioPercent)) { pushRadioMessage (Radio::RogerThat); // don't pause/camp anymore @@ -2738,7 +2739,7 @@ void Bot::checkRadioQueue () { case Radio::ReportInTeam: switch (getCurrentTaskId ()) { case Task::Normal: - if (getTask ()->data != kInvalidNodeIndex && rg.chance (70)) { + if (getTask ()->data != kInvalidNodeIndex && rg.chance (m_radioPercent)) { const auto &path = graph[getTask ()->data]; if (path.flags & NodeFlag::Goal) { @@ -2752,14 +2753,14 @@ void Bot::checkRadioQueue () { else if (m_hasHostage) { pushChatterMessage (Chatter::RescuingHostages); } - else if ((path.flags & NodeFlag::Camp) && rg.chance (75)) { + else if ((path.flags & NodeFlag::Camp) && rg.chance (m_radioPercent)) { pushChatterMessage (Chatter::GoingToCamp); } else if (m_states & Sense::HearingEnemy) { pushChatterMessage (Chatter::HeardTheEnemy); } } - else if (rg.chance (30)) { + else if (rg.chance (m_radioPercent)) { pushChatterMessage (Chatter::ReportingIn); } break; @@ -2771,7 +2772,7 @@ void Bot::checkRadioQueue () { break; case Task::Camp: - if (rg.chance (40)) { + if (rg.chance (m_radioPercent)) { if (bots.isBombPlanted () && m_team == Team::Terrorist) { pushChatterMessage (Chatter::GuardingPlantedC4); } @@ -2828,7 +2829,7 @@ void Bot::checkRadioQueue () { break; default: - if (rg.chance (50)) { + if (rg.chance (m_radioPercent)) { pushChatterMessage (Chatter::Nothing); } break; @@ -2942,7 +2943,7 @@ void Bot::tryHeadTowardRadioMessage () { } if ((util.isFakeClient (m_radioEntity) - && rg.chance (25) + && rg.chance (m_radioPercent) && m_personality == Personality::Normal) || !(m_radioEntity->v.flags & FL_FAKECLIENT)) { if (tid == Task::Pause || tid == Task::Camp) { @@ -3657,6 +3658,9 @@ void Bot::takeDamage (edict_t *inflictor, int damage, int armor, int bits) { pushChatterMessage (Chatter::FriendlyFire); } else { + // increase radio percent + m_radioPercent = cr::max (m_radioPercent + 1, 90); + // attacked by an enemy if (m_healthValue > 60.0f) { m_agressionLevel += 0.1f; @@ -3744,7 +3748,7 @@ void Bot::takeBlind (int alpha) { } } -void Bot::updatePracticeValue (int damage) { +void Bot::updatePracticeValue (int damage) const { // gets called each time a bot gets damaged by some enemy. tries to achieve a statistic about most/less dangerous // nodes for a destination goal used for pathfinding @@ -3960,7 +3964,7 @@ bool Bot::canRunHeavyWeight () { return false; } -uint8_t Bot::computeMsec () { +uint8_t Bot::computeMsec () const { // estimate msec to use for this command based on time passed from the previous command return static_cast (cr::min (static_cast (cr::roundf ((game.time () - m_previousThinkTime) * 1000.0f)), 255)); @@ -4248,7 +4252,7 @@ void Bot::selectCampButtons (int index) { } } -bool Bot::isBombDefusing (const Vector &bombOrigin) { +bool Bot::isBombDefusing (const Vector &bombOrigin) const { // this function finds if somebody currently defusing the bomb. if (!bots.isBombPlanted ()) { @@ -4354,7 +4358,7 @@ void Bot::refreshCreatureStatus (char *infobuffer) { m_modelMask = modelTest.mask; } -bool Bot::isCreature () { +bool Bot::isCreature () const { // current creature models are: zombie, chicken constexpr auto kModelMaskZombie = (('o' << 8) + 'z'); constexpr auto kModelMaskChicken = (('h' << 8) + 'c'); diff --git a/src/combat.cpp b/src/combat.cpp index 8f5b8e3..7e39530 100644 --- a/src/combat.cpp +++ b/src/combat.cpp @@ -19,7 +19,7 @@ ConVar cv_aim_trace_consider_glass ("aim_trace_consider_glass", "0", "Bots will ConVar mp_friendlyfire ("mp_friendlyfire", nullptr, Var::GameRef); ConVar sv_gravity ("sv_gravity", nullptr, Var::GameRef); -int Bot::numFriendsNear (const Vector &origin, const float radius) { +int Bot::numFriendsNear (const Vector &origin, const float radius) const { if (game.is (GameFlags::FreeForAll)) { return 0; // no friends on free for all mode } @@ -39,7 +39,7 @@ int Bot::numFriendsNear (const Vector &origin, const float radius) { return count; } -int Bot::numEnemiesNear (const Vector &origin, const float radius) { +int Bot::numEnemiesNear (const Vector &origin, const float radius) const { if (game.is (GameFlags::FreeForAll)) { return 0; // no enemies on free for all mode } @@ -129,7 +129,7 @@ bool Bot::isEnemyNoTarget (edict_t *enemy) { return !!(enemy->v.flags & FL_NOTARGET); } -bool Bot::isEnemyInDarkArea (edict_t *enemy) { +bool Bot::isEnemyInDarkArea (edict_t *enemy) const { if (!cv_check_darkness && game.isNullEntity (enemy)) { return false; } @@ -773,7 +773,7 @@ Vector Bot::getEnemyBodyOffset () { return spot; } -Vector Bot::getCustomHeight (float distance) { +Vector Bot::getCustomHeight (float distance) const { enum DistanceIndex { Long, Middle, Short }; @@ -808,7 +808,7 @@ Vector Bot::getCustomHeight (float distance) { return { 0.0f, 0.0f, kOffsetRanges[m_weaponType][distanceIndex] }; } -bool Bot::isFriendInLineOfFire (float distance) { +bool Bot::isFriendInLineOfFire (float distance) const { // bot can't hurt teammates, if friendly fire is not enabled... if (!mp_friendlyfire || game.is (GameFlags::CSDM)) { return false; @@ -868,7 +868,7 @@ bool Bot::isPenetrableObstacle (const Vector &dest) { return isPenetrableObstacle2 (dest, penetratePower); } -bool Bot::isPenetrableObstacle1 (const Vector &dest, int penetratePower) { +bool Bot::isPenetrableObstacle1 (const Vector &dest, int penetratePower) const { TraceResult tr {}; float obstacleDistanceSq = 0.0f; @@ -906,7 +906,7 @@ bool Bot::isPenetrableObstacle1 (const Vector &dest, int penetratePower) { return false; } -bool Bot::isPenetrableObstacle2 (const Vector &dest, int) { +bool Bot::isPenetrableObstacle2 (const Vector &dest, int) const { // this function returns if enemy can be shoot through some obstacle const Vector &source = getEyesPos (); @@ -941,7 +941,7 @@ bool Bot::isPenetrableObstacle2 (const Vector &dest, int) { return false; } -bool Bot::isPenetrableObstacle3 (const Vector &dest, int penetratePower) { +bool Bot::isPenetrableObstacle3 (const Vector &dest, int penetratePower) const { // this function returns if enemy can be shoot through some obstacle TraceResult tr {}; @@ -1659,13 +1659,13 @@ void Bot::attackMovement () { ignoreCollision (); } -bool Bot::hasPrimaryWeapon () { +bool Bot::hasPrimaryWeapon () const { // this function returns returns true, if bot has a primary weapon return (pev->weapons & kPrimaryWeaponMask) != 0; } -bool Bot::hasSecondaryWeapon () { +bool Bot::hasSecondaryWeapon () const { // this function returns returns true, if bot has a secondary weapon return (pev->weapons & kSecondaryWeaponMask) != 0; @@ -1752,7 +1752,7 @@ int Bot::bestSecondaryCarried () { return weaponIndex; } -int Bot::bestGrenadeCarried () { +int Bot::bestGrenadeCarried () const { if (pev->weapons & cr::bit (Weapon::Explosive)) { return Weapon::Explosive; } @@ -1792,7 +1792,7 @@ bool Bot::rateGroundWeapon (edict_t *ent) { return groundIndex > hasWeapon; } -bool Bot::hasAnyWeapons () { +bool Bot::hasAnyWeapons () const { return !!(pev->weapons & (kPrimaryWeaponMask | kSecondaryWeaponMask)); } @@ -1902,7 +1902,7 @@ void Bot::selectSecondary () { pev->weapons = oldWeapons; } -int Bot::getBestOwnedWeapon () { +int Bot::getBestOwnedWeapon () const { auto tab = conf.getRawWeapons (); int weapons = pev->weapons; @@ -1921,7 +1921,7 @@ int Bot::getBestOwnedWeapon () { return num; } -int Bot::getBestOwnedPistol () { +int Bot::getBestOwnedPistol () const { auto tab = conf.getRawWeapons (); int weapons = pev->weapons; @@ -2111,7 +2111,7 @@ void Bot::checkReload () { } } -float Bot::calculateScaleFactor (edict_t *ent) { +float Bot::calculateScaleFactor (edict_t *ent) const { Vector entSize = ent->v.maxs - ent->v.mins; const float entArea = 2.0f * (entSize.x * entSize.y + entSize.y * entSize.z + entSize.x * entSize.z); @@ -2571,11 +2571,11 @@ bool Bot::isEnemyNoticeable (float range) { return rg (0.0f, 100.0f) < noticeChance; } -int Bot::getAmmo () { +int Bot::getAmmo () const { return getAmmo (m_currentWeapon); } -int Bot::getAmmo (int id) { +int Bot::getAmmo (int id) const { const auto &prop = conf.getWeaponProp (id); if (prop.ammo1 == -1 || prop.ammo1 > kMaxWeapons - 1) { diff --git a/src/config.cpp b/src/config.cpp index a4f3da9..30cf4a4 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -761,12 +761,13 @@ void BotConfig::loadLogosConfig () { if (isCommentLine (line)) { continue; } - addLogoIndex (line); + addLogoIndex (line.trim ()); } } // use defaults if (m_logosIndices.empty ()) { + game.print ("EMPTY!!!!!"); auto defaults = String { "{biohaz;{graf003;{graf004;{graf005;{lambda06;{target;{hand1;{spit2;{bloodhand6;{foot_l;{foot_r" }.split (";"); for (const auto &logo : defaults) { diff --git a/src/control.cpp b/src/control.cpp index 51163b8..5190f9a 100644 --- a/src/control.cpp +++ b/src/control.cpp @@ -17,7 +17,7 @@ int BotControl::cmdAddBot () { // this is duplicate error as in main bot creation code, but not to be silent if (!graph.length () || graph.hasChanged ()) { - ctrl.msg ("There is no graph found or graph is changed. Cannot create bot."); + msg ("There is no graph found or graph is changed. Cannot create bot."); return BotCommandResult::Handled; } @@ -91,7 +91,7 @@ int BotControl::cmdKillBots () { bots.killAllBots (Team::Terrorist, silentKill); } else { - bots.killAllBots (-1, silentKill); + bots.killAllBots (Team::Invalid, silentKill); } return BotCommandResult::Handled; } @@ -204,6 +204,9 @@ int BotControl::cmdCvars () { auto match = arg (pattern); + // stop printing if executed once more + flushPrintQueue (); + // revert all the cvars to their default values if (match == "defaults") { msg ("Bots cvars has been reverted to their default values."); @@ -244,7 +247,7 @@ int BotControl::cmdCvars () { cfg.puts ("// Configuration file for %s\n\n", product.name); } else { - ctrl.setRapidOutput (true); + setRapidOutput (true); } for (const auto &cvar : game.getCvars ()) { @@ -303,7 +306,7 @@ int BotControl::cmdCvars () { msg (" "); } } - ctrl.setRapidOutput (false); + setRapidOutput (false); if (isSave) { if (!cfg) { @@ -2172,13 +2175,13 @@ void BotControl::maintainAdminRights () { } 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); + 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); + msg ("Player %s had gained full remote access to %s.", ent->v.netname.chars (), product.name); } } } diff --git a/src/engine.cpp b/src/engine.cpp index 2bb1f28..248f989 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -224,7 +224,7 @@ void Game::levelShutdown () { } -void Game::drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, const Color &color, int brightness, int speed, int life, DrawLine type) { +void Game::drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, const Color &color, int brightness, int speed, int life, DrawLine type) const { // this function draws a arrow visible from the client side of the player whose player entity // is pointed to by ent, from the vector location start to the vector location end, // which is supposed to last life tenths seconds, and having the color defined by RGB. @@ -410,7 +410,7 @@ bool Game::checkVisibility (edict_t *ent, uint8_t *set) { return engfuncs.pfnCheckVisibility (ent, set) > 0; } -uint8_t *Game::getVisibilitySet (Bot *bot, bool pvs) { +uint8_t *Game::getVisibilitySet (Bot *bot, bool pvs) const { if (is (GameFlags::Xash3DLegacy)) { return nullptr; } @@ -545,7 +545,7 @@ void Game::prepareBotArgs (edict_t *ent, String str) { m_botArgs.emplace (args.substr (quote, args.length () - 1).trim ("\"")); // add string with trimmed quotes } else { - for (auto arg : args.split (" ")) { + for (auto &&arg : args.split (" ")) { m_botArgs.emplace (arg); } } @@ -560,7 +560,7 @@ void Game::prepareBotArgs (edict_t *ent, String str) { }; if (str.find (';', 0) != String::InvalidIndex) { - for (auto part : str.split (";")) { + for (auto &&part : str.split (";")) { parsePartArgs (part.trim ()); } } @@ -1126,7 +1126,7 @@ void Game::searchEntities (StringRef field, StringRef value, EntitySearch functo } } -void Game::searchEntities (const Vector &position, float radius, EntitySearch functor) { +void Game::searchEntities (const Vector &position, float radius, EntitySearch functor) const { edict_t *ent = nullptr; const Vector &pos = position.empty () ? m_startEntity->v.origin : position; @@ -1145,7 +1145,7 @@ bool Game::hasEntityInGame (StringRef classname) { return !isNullEntity (engfuncs.pfnFindEntityByString (nullptr, "classname", classname.chars ())); } -void Game::printBotVersion () { +void Game::printBotVersion () const { String gameVersionStr {}; StringArray botRuntimeFlags {}; diff --git a/src/graph.cpp b/src/graph.cpp index d2aa97d..9b5aed2 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -1301,7 +1301,7 @@ void BotGraph::showFileInfo () { msg (" bsp_size: %d", exten.mapSize); } -void BotGraph::emitNotify (int32_t sound) { +void BotGraph::emitNotify (int32_t sound) const { static HashMap notifySounds = { { NotifySound::Added, "weapons/xbow_hit1.wav" }, { NotifySound::Change, "weapons/mine_activate.wav" }, @@ -1559,7 +1559,7 @@ void BotGraph::initLightLevels () { if (m_paths.empty () || m_lightChecked) { return; } - auto players = bots.countTeamPlayers (); + const auto &players = bots.countTeamPlayers (); // do calculation if some-one is already playing on the server if (!players.first && !players.second) { @@ -1953,7 +1953,7 @@ float BotGraph::calculateTravelTime (float maxSpeed, const Vector &src, const Ve return origin.distance2d (src) / maxSpeed; } -bool BotGraph::isNodeReacheableEx (const Vector &src, const Vector &destination, const float maxHeight) { +bool BotGraph::isNodeReacheableEx (const Vector &src, const Vector &destination, const float maxHeight) const { TraceResult tr {}; float distanceSq = destination.distanceSq (src); @@ -2044,11 +2044,11 @@ bool BotGraph::isNodeReacheableEx (const Vector &src, const Vector &destination, } -bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) { +bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) const { return isNodeReacheableEx (src, destination, 45.0f); } -bool BotGraph::isNodeReacheableWithJump (const Vector &src, const Vector &destination) { +bool BotGraph::isNodeReacheableWithJump (const Vector &src, const Vector &destination) const { return isNodeReacheableEx (src, destination, cv_graph_analyze_max_jump_height.as ()); } @@ -2872,7 +2872,7 @@ void BotGraph::unassignPath (int from, int to) { m_hasChanged = true; } -void BotGraph::convertFromPOD (Path &path, const PODPath &pod) { +void BotGraph::convertFromPOD (Path &path, const PODPath &pod) const { path.number = pod.number; path.flags = pod.flags; path.origin = pod.origin; @@ -2916,7 +2916,7 @@ void BotGraph::convertToPOD (const Path &path, PODPath &pod) { pod.vis.crouch = path.vis.crouch; } -void BotGraph::convertCampDirection (Path &path) { +void BotGraph::convertCampDirection (Path &path) const { // this function converts old vector based camp directions to angles, note that podbotmm graph // are already saved with angles, and converting this stuff may result strange look directions. diff --git a/src/hooks.cpp b/src/hooks.cpp index 2059595..71e9283 100644 --- a/src/hooks.cpp +++ b/src/hooks.cpp @@ -102,7 +102,7 @@ void ServerQueryHook::init () { } } -SharedLibrary::Func DynamicLinkerHook::lookup (SharedLibrary::Handle module, const char *function) { +SharedLibrary::Func EntityLinkHook::lookupSymbol (SharedLibrary::Handle module, const char *function) { static const auto &gamedll = game.lib ().handle (); static const auto &self = m_self.handle (); @@ -148,7 +148,7 @@ SharedLibrary::Func DynamicLinkerHook::lookup (SharedLibrary::Handle module, con return nullptr; } -bool DynamicLinkerHook::callPlayerFunction (edict_t *ent) { +bool EntityLinkHook::callPlayerFunction (edict_t *ent) { auto callPlayer = [&] () { reinterpret_cast (reinterpret_cast (m_exports["player"])) (&ent->v); }; @@ -169,11 +169,11 @@ bool DynamicLinkerHook::callPlayerFunction (edict_t *ent) { return true; } -bool DynamicLinkerHook::needsBypass () const { +bool EntityLinkHook::needsBypass () const { return !plat.win && !game.isDedicated (); } -void DynamicLinkerHook::initialize () { +void EntityLinkHook::initialize () { #if defined(LINKENT_STATIC) return; #endif diff --git a/src/manager.cpp b/src/manager.cpp index a49828f..fd027e0 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -669,7 +669,7 @@ void BotManager::killAllBots (int team, bool silent) { // this function kills all bots on server (only this dll controlled bots) for (const auto &bot : m_bots) { - if (team != -1 && game.getRealTeam (bot->ent ()) != team) { + if (team != Team::Invalid && game.getRealTeam (bot->ent ()) != team) { continue; } bot->kill (); @@ -922,11 +922,14 @@ void BotManager::listBots () { bot->index (), bot->pev->netname.chars (), bot->m_personality == Personality::Rusher ? "rusher" : bot->m_personality == Personality::Normal ? "normal" : "careful", + botTeam (bot->ent ()), bot->m_difficulty, static_cast (bot->pev->frags), + bot->m_deathCount, bot->m_isAlive ? "yes" : "no", + timelimitStr); } ctrl.msg ("%d bots", m_bots.length ()); @@ -1123,7 +1126,7 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) { } } - char reject[StringBuffer::StaticBufferSize] = { 0, }; + char reject[128] = { 0, }; MDLL_ClientConnect (bot, bot->v.netname.chars (), strings.format ("127.0.0.%d", clientIndex + 100), reject); if (!strings.isEmpty (reject)) { @@ -1569,6 +1572,7 @@ void Bot::newRound () { m_hitboxEnumerator = cr::makeUnique (); } } + showChatterIcon (false); m_approachingLadderTimer.invalidate (); m_forgetLastVictimTimer.invalidate (); @@ -1609,6 +1613,24 @@ void Bot::newRound () { m_buyState = BuyState::PrimaryWeapon; m_lastEquipTime = 0.0f; + // setup radio percent each round + const auto badMorale = m_fearLevel > m_agressionLevel ? rg.chance (75) : rg.chance (35); + + switch (m_personality) { + case Personality::Normal: + default: + m_radioPercent = badMorale ? rg (50, 75) : rg (25, 50); + break; + + case Personality::Rusher: + m_radioPercent = badMorale ? rg (35, 50) : rg (15, 35); + break; + + case Personality::Careful: + m_radioPercent = badMorale ? rg (70, 90) : rg (50, 70); + break; + } + // if bot died, clear all weapon stuff and force buying again if (!m_isAlive) { clearAmmoInfo (); diff --git a/src/navigate.cpp b/src/navigate.cpp index d633d22..0d780d3 100644 --- a/src/navigate.cpp +++ b/src/navigate.cpp @@ -282,8 +282,8 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offensive) { else if (tactic == GoalTactic::Offensive && !(*offensive).empty ()) { // offensive goal postProcessGoals (*offensive, goalChoices); } - else if (tactic == GoalTactic::Goal && !graph.m_goalPoints.empty ()) // map goal node - { + else if (tactic == GoalTactic::Goal && !graph.m_goalPoints.empty ()) { // map goal node + // force bomber to select closest goal, if round-start goal was reset by something if (m_hasC4 && bots.getRoundStartTime () + 20.0f < game.time ()) { float nearestDistanceSq = kInfiniteDistance; @@ -3421,7 +3421,7 @@ bool Bot::isReachableNode (int index) { return tr.flFraction >= 1.0f; } -bool Bot::isPreviousLadder () { +bool Bot::isPreviousLadder () const { const auto prevNodeIndex = m_previousNodes[0]; // bot entered ladder path diff --git a/src/planner.cpp b/src/planner.cpp index 6be3b43..44901fd 100644 --- a/src/planner.cpp +++ b/src/planner.cpp @@ -395,7 +395,7 @@ bool FloydWarshallAlgo::load () { return true; } -void FloydWarshallAlgo::save () { +void FloydWarshallAlgo::save () const { if (!m_length) { return; } @@ -448,7 +448,7 @@ bool DijkstraAlgo::find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, i m_distance[srcIndex] = 0; while (!m_queue.empty ()) { - auto route = m_queue.pop (); + const auto &route = m_queue.pop (); auto current = route.second; // finished search diff --git a/src/tasks.cpp b/src/tasks.cpp index d2454d7..81e6f74 100644 --- a/src/tasks.cpp +++ b/src/tasks.cpp @@ -192,8 +192,9 @@ void Bot::normal_ () { if (game.mapIs (MapFlags::HostageRescue)) { // CT Bot has some hostages following? if (m_team == Team::CT && m_hasHostage) { + // and reached a rescue point? - if (m_pathFlags & NodeFlag::Rescue) { + if (m_inRescueZone && (m_pathFlags & NodeFlag::Rescue)) { m_hostages.clear (); } } diff --git a/src/vision.cpp b/src/vision.cpp index a6b5b69..252d89e 100644 --- a/src/vision.cpp +++ b/src/vision.cpp @@ -13,7 +13,7 @@ ConVar cv_whose_your_daddy ("whose_your_daddy", "0", "Enables or disables extra // game console variables ConVar mp_flashlight ("mp_flashlight", nullptr, Var::GameRef); -float Bot::isInFOV (const Vector &destination) { +float Bot::isInFOV (const Vector &destination) const { const float entityAngle = cr::wrapAngle360 (destination.yaw ()); // find yaw angle from source to destination... const float viewAngle = cr::wrapAngle360 (pev->v_angle.y); // get bot's current view angle... @@ -368,7 +368,7 @@ bool Frustum::isObjectInsidePlane (const Plane &plane, const Vector ¢er, flo return isPointInsidePlane (top) || isPointInsidePlane (bottom); } -void Frustum::calculate (Planes &planes, const Vector &viewAngle, const Vector &viewOffset) { +void Frustum::calculate (Planes &planes, const Vector &viewAngle, const Vector &viewOffset) const { Vector forward {}, right {}, up {}; viewAngle.angleVectors (&forward, &right, &up); diff --git a/src/vistable.cpp b/src/vistable.cpp index 40230ca..c4e815a 100644 --- a/src/vistable.cpp +++ b/src/vistable.cpp @@ -179,7 +179,7 @@ void GraphVistable::load () { } } -void GraphVistable::save () { +void GraphVistable::save () const { if (!graph.length () || graph.hasChanged () || m_rebuild) { return; }