diff --git a/ext/crlib b/ext/crlib index 72b32ac..2265a4c 160000 --- a/ext/crlib +++ b/ext/crlib @@ -1 +1 @@ -Subproject commit 72b32ac851400c6abb2332299d42f62b871620dd +Subproject commit 2265a4cc6b4b7da30a86b068382c0754399870d9 diff --git a/inc/constant.h b/inc/constant.h index 79dfd60..3d89399 100644 --- a/inc/constant.h +++ b/inc/constant.h @@ -449,6 +449,6 @@ constexpr auto kSecondaryWeaponMask = (cr::bit (Weapon::P228) | cr::bit (Weapon: constexpr auto kPrimaryWeaponMinIndex = 7; // grenade model names -static constexpr StringRef kExplosiveModelName = "hegrenade.mdl"; -static constexpr StringRef kFlashbangModelName = "flashbang.mdl"; -static constexpr StringRef kSmokeModelName = "smokegrenade.mdl"; +inline constexpr StringRef kExplosiveModelName = "hegrenade.mdl"; +inline constexpr StringRef kFlashbangModelName = "flashbang.mdl"; +inline constexpr StringRef kSmokeModelName = "smokegrenade.mdl"; diff --git a/inc/hooks.h b/inc/hooks.h index 3397326..88dd693 100644 --- a/inc/hooks.h +++ b/inc/hooks.h @@ -182,11 +182,6 @@ public: static int CR_STDCALL closeHandler (SharedLibrary::Handle module) { return instance ().close (module); } - -public: - void flush () { - m_exports.clear (); - } }; // expose global diff --git a/inc/product.h b/inc/product.h index a04c365..c633299 100644 --- a/inc/product.h +++ b/inc/product.h @@ -39,6 +39,7 @@ public: static constexpr StringRef email { "yapb@jeefo.net" }; static constexpr StringRef url { "https://yapb.jeefo.net/" }; static constexpr StringRef download { "yapb.jeefo.net" }; + static constexpr StringRef upload { "yapb.jeefo.net/upload" }; static constexpr StringRef logtag { "YB" }; static constexpr StringRef dtime { __DATE__ " " __TIME__ }; static constexpr StringRef date { __DATE__ }; @@ -53,6 +54,8 @@ public: ~Folders () = default; public: + static constexpr StringRef bot { "yapb" }; + static constexpr StringRef addons { "addons" }; static constexpr StringRef config { "conf" }; static constexpr StringRef data { "data" }; static constexpr StringRef lang { "lang" }; diff --git a/inc/storage.h b/inc/storage.h index 20e7af7..61237a5 100644 --- a/inc/storage.h +++ b/inc/storage.h @@ -79,10 +79,10 @@ public: String buildPath (int32_t type, bool isMemoryLoad = false); // get's relative path against bot library (bot library should reside in bin dir) - String getRunningPath (); + StringRef getRunningPath (); // same as above, but with valve-specific filesystem paths (loadfileforme) - String getRunningPathVFS (); + StringRef getRunningPathVFS (); // converts storage option to storage filename int32_t storageToBotFile (int32_t options); diff --git a/src/analyze.cpp b/src/analyze.cpp index 88b7a9d..959587c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -274,9 +274,9 @@ void GraphAnalyze::displayOverlayMessage () { return; } constexpr StringRef analyzeHudMesssage = - "+--------------------------------------------------------+\n" - " Map analysis for bots is in progress. Please Wait.. \n" - "+--------------------------------------------------------+\n"; + "+-----------------------------------------------------------------+\n" + " Map analysis for bots is in progress. Please Wait.. \n" + "+-----------------------------------------------------------------+\n"; static hudtextparms_t textParams {}; @@ -346,7 +346,7 @@ void GraphAnalyze::flood (const Vector &pos, const Vector &next, float range) { } void GraphAnalyze::setUpdateInterval () { - const auto frametime (globals->frametime); + const auto frametime = globals->frametime; if ((cv_graph_analyze_fps.float_ () + frametime) <= 1.0f / frametime) { m_updateInterval = game.time () + frametime * 0.06f; @@ -358,16 +358,16 @@ void GraphAnalyze::markGoals () { return; } - auto updateNodeFlags = [] (int type, const char *entity) { - game.searchEntities ("classname", entity, [&] (edict_t *ent) { + auto updateNodeFlags = [] (int type, StringRef classname) { + game.searchEntities ("classname", classname, [&] (edict_t *ent) { for (auto &path : graph) { - const auto &absOrigin = path.origin + Vector (1.0f, 1.0f, 1.0f); + const auto &bb = path.origin + Vector (1.0f, 1.0f, 1.0f); - if (ent->v.absmin.x > absOrigin.x || ent->v.absmin.y > absOrigin.y) { + if (ent->v.absmin.x > bb.x || ent->v.absmin.y > bb.y) { continue; } - if (ent->v.absmax.x < absOrigin.x || ent->v.absmax.y < absOrigin.y) { + if (ent->v.absmax.x < bb.x || ent->v.absmax.y < bb.y) { continue; } path.flags |= type; diff --git a/src/combat.cpp b/src/combat.cpp index 5cb1c04..57b99fd 100644 --- a/src/combat.cpp +++ b/src/combat.cpp @@ -188,7 +188,7 @@ bool Bot::checkBodyParts (edict_t *target) { return true; } - Vector dir = (target->v.origin - pev->origin).normalize2d (); + Vector dir = (target->v.origin - pev->origin).normalize2d_apx (); Vector perp (-dir.y, dir.x, 0.0f); spot = target->v.origin + Vector (perp.x * kEdgeOffset, perp.y * kEdgeOffset, 0); @@ -675,9 +675,10 @@ bool Bot::isPenetrableObstacle (const Vector &dest) { obstacleDistanceSq = tr.vecEndPos.distanceSq (source); } } - constexpr float kMaxDistanceSq = cr::sqrf (75.0f); if (obstacleDistanceSq > 0.0f) { + constexpr float kMaxDistanceSq = cr::sqrf (75.0f); + while (power > 0) { if (obstacleDistanceSq > kMaxDistanceSq) { obstacleDistanceSq -= kMaxDistanceSq; @@ -1214,6 +1215,9 @@ void Bot::attackMovement () { else if (usesKnife ()) { m_fightStyle = Fight::Strafe; } + else if (usesKnife () && isInViewCone (m_enemy->v.origin) && game.is (GameFlags::CSDM) && !isInNarrowPlace ()) { + m_fightStyle = Fight::Strafe; + } else { m_fightStyle = Fight::Stay; } diff --git a/src/config.cpp b/src/config.cpp index 2b2347d..d6b5156 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -576,12 +576,15 @@ void BotConfig::loadDifficultyConfig () { // currently, mindelay, maxdelay, headprob, seenthruprob, heardthruprob, recoil, aim_error {x,y,z} constexpr uint32_t kMaxDifficultyValues = 9; + // has errors ? + int errorCount = 0; + // helper for parsing each level auto parseLevel = [&] (int32_t level, StringRef data) { auto values = data.split (","); if (values.length () != kMaxDifficultyValues) { - logger.error ("Bad value for difficulty level #%d.", level); + ++errorCount; return; } auto diff = &m_difficulty[level]; @@ -629,6 +632,11 @@ void BotConfig::loadDifficultyConfig () { parseLevel (Difficulty::Expert, items[1]); } } + + // if some errors occurred, notify user + if (errorCount > 0) { + logger.error ("Config file: difficulty.%s has a bad syntax. Probably out of date.", kConfigExtension); + } } } @@ -656,6 +664,9 @@ void BotConfig::loadCustomConfig () { }; setDefaults (); + // has errors ? + int errorCount = 0; + // custom initialization if (openConfig ("custom", "Custom config file not found. Loading defaults.", &file)) { m_custom.clear (); @@ -672,8 +683,8 @@ void BotConfig::loadCustomConfig () { auto values = line.split ("="); if (values.length () != 2) { - logger.error ("Bad configuration for custom.%s", kConfigExtension); - return; + ++errorCount; + continue; } auto kv = Twin (values[0].trim (), values[1].trim ()); @@ -681,6 +692,11 @@ void BotConfig::loadCustomConfig () { m_custom[kv.first] = kv.second; } } + + // if some errors occurred, notify user + if (errorCount > 0) { + logger.error ("Config file: custom.%s has a bad syntax. Probably out of date.", kConfigExtension); + } } } diff --git a/src/control.cpp b/src/control.cpp index 4f6563d..49b831f 100644 --- a/src/control.cpp +++ b/src/control.cpp @@ -1460,10 +1460,10 @@ int BotControl::menuGraphRadius (int item) { closeMenu (); // reset menu display graph.setEditFlag (GraphEdit::On); // turn graph on in case - constexpr float radius[] = { 0.0f, 8.0f, 16.0f, 32.0f, 48.0f, 64.0f, 80.0f, 96.0f, 128.0f }; - if (item >= 1 && item <= 9) { - graph.setRadius (kInvalidNodeIndex, radius[item - 1]); + constexpr float kRadiusValues[] = { 0.0f, 8.0f, 16.0f, 32.0f, 48.0f, 64.0f, 80.0f, 96.0f, 128.0f }; + + graph.setRadius (kInvalidNodeIndex, kRadiusValues[item - 1]); showMenu (Menu::NodeRadius); } return BotCommandResult::Handled; @@ -1642,10 +1642,10 @@ int BotControl::menuCampDirections (int item) { int BotControl::menuAutoPathDistance (int item) { closeMenu (); // reset menu display - constexpr float distances[] = { 0.0f, 100.0f, 130.0f, 160.0f, 190.0f, 220.0f, 250.0f }; - if (item >= 1 && item <= 7) { - graph.setAutoPathDistance (distances[item - 1]); + constexpr float kDistanceValues[] = { 0.0f, 100.0f, 130.0f, 160.0f, 190.0f, 220.0f, 250.0f }; + + graph.setAutoPathDistance (kDistanceValues[item - 1]); } switch (item) { diff --git a/src/graph.cpp b/src/graph.cpp index e3a77ef..43ee410 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -9,7 +9,7 @@ ConVar cv_graph_fixcamp ("graph_fixcamp", "0", "Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format."); ConVar cv_graph_url ("graph_url", product.download.chars (), "Specifies the URL from which bots will be able to download graph in case of missing local one. Set to empty, if no downloads needed.", false, 0.0f, 0.0f); -ConVar cv_graph_url_upload ("graph_url_upload", "yapb.jeefo.net/upload", "Specifies the URL to which bots will try to upload the graph file to database.", false, 0.0f, 0.0f); +ConVar cv_graph_url_upload ("graph_url_upload", product.upload.chars (), "Specifies the URL to which bots will try to upload the graph file to database.", false, 0.0f, 0.0f); ConVar cv_graph_auto_save_count ("graph_auto_save_count", "15", "Every N graph nodes placed on map, the graph will be saved automatically (without checks).", true, 0.0f, kMaxNodes); ConVar cv_graph_draw_distance ("graph_draw_distance", "400", "Maximum distance to draw graph nodes from editor viewport.", true, 64.0f, 3072.0f); @@ -1848,7 +1848,7 @@ bool BotGraph::isNodeReacheableEx (const Vector &src, const Vector &destination, game.testLine (check, down, TraceIgnore::Monsters, m_editor, &tr); - float height = tr.flFraction * 1000.0f; // height from ground + const float height = tr.flFraction * 1000.0f; // height from ground // is the current height greater than the step height? if (height < lastHeight - maxHeight) { @@ -2515,8 +2515,8 @@ void BotGraph::addBasic () { return EntitySearchResult::Continue; }); - auto autoCreateForEntity = [] (int type, const char *entity) { - game.searchEntities ("classname", entity, [&] (edict_t *ent) { + auto autoCreateForEntity = [] (int type, StringRef classname) { + game.searchEntities ("classname", classname, [&] (edict_t *ent) { Vector pos = game.getEntityOrigin (ent); TraceResult tr; diff --git a/src/linkage.cpp b/src/linkage.cpp index 7fbbcd1..a674044 100644 --- a/src/linkage.cpp +++ b/src/linkage.cpp @@ -333,9 +333,6 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) { RETURN_META (MRES_IGNORED); } dllapi.pfnServerDeactivate (); - - // refill export table - entlink.flush (); }; table->pfnStartFrame = [] () { diff --git a/src/manager.cpp b/src/manager.cpp index bc014f1..91bc8df 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -373,6 +373,11 @@ void BotManager::maintainQuota () { return; } + if (analyzer.isAnalyzing ()) { + ctrl.msg ("Can't create bot during map analysis process."); + return; + } + // bot's creation update if (!m_addRequests.empty () && m_maintainTime < game.time ()) { const BotRequest &request = m_addRequests.popFront (); diff --git a/src/navigate.cpp b/src/navigate.cpp index 13a228d..2ff2e75 100644 --- a/src/navigate.cpp +++ b/src/navigate.cpp @@ -2820,7 +2820,7 @@ bool Bot::isBlockedRight () { bool Bot::checkWallOnLeft () { TraceResult tr {}; - game.testLine (pev->origin, pev->origin + -pev->angles.right () * 40.0f, TraceIgnore::Monsters, ent (), &tr); + game.testLine (pev->origin, pev->origin + -pev->angles.right () * 45.0f, TraceIgnore::Monsters, ent (), &tr); // check if the trace hit something... if (tr.flFraction < 1.0f) { @@ -2833,7 +2833,7 @@ bool Bot::checkWallOnRight () { TraceResult tr {}; // do a trace to the right... - game.testLine (pev->origin, pev->origin + pev->angles.right () * 40.0f, TraceIgnore::Monsters, ent (), &tr); + game.testLine (pev->origin, pev->origin + pev->angles.right () * 45.0f, TraceIgnore::Monsters, ent (), &tr); // check if the trace hit something... if (tr.flFraction < 1.0f) { @@ -3172,7 +3172,7 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) { srcIndex = changeNodeIndex (graph.getNearestNoBuckets (pev->origin, 256.0f)); if (!graph.exists (srcIndex)) { - printf ("%s source path index not valid (%d).", __func__, srcIndex); + printf ("%s source path index not valid (%d).\n", __func__, srcIndex); return; } } @@ -3183,7 +3183,7 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) { destIndex = graph.random (); if (!graph.exists (destIndex)) { - printf ("%s dest path index not valid (%d).", __func__, destIndex); + printf ("%s dest path index not valid (%d).\n", __func__, destIndex); return; } } @@ -3191,7 +3191,7 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) { // do not process if src points to dst if (srcIndex == destIndex) { - printf ("%s source path is same as dest (%d).", __func__, destIndex); + printf ("%s source path is same as dest (%d).\n", __func__, destIndex); return; } clearSearchNodes (); @@ -3246,7 +3246,7 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) { m_kickMeFromServer = true; // bot should be kicked within main thread, not here // bot should not roam when this occurs - printf ("A* Search for bot \"%s\" failed with internal pathfinder error. Seems to be graph is broken. Bot removed (re-added).", pev->netname.chars ()); + printf ("A* Search for bot \"%s\" failed with internal pathfinder error. Seems to be graph is broken. Bot removed (re-added).\n", pev->netname.chars ()); break; case AStarResult::Failed: @@ -3254,7 +3254,7 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) { findShortestPath (srcIndex, destIndex); // A* found no path, try floyd pathfinder instead if (cv_debug.bool_ ()) { - printf ("A* Search for bot \"%s\" has failed. Falling back to shortest-path algorithm. Seems to be graph is broken.", pev->netname.chars ()); + printf ("A* Search for bot \"%s\" has failed. Falling back to shortest-path algorithm. Seems to be graph is broken.\n", pev->netname.chars ()); } break; } diff --git a/src/storage.cpp b/src/storage.cpp index bd44c21..3b17d8a 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -393,11 +393,19 @@ void BotStorage::unlinkFromDisk () { graph.reset (); // re-initialize points } -String BotStorage::getRunningPath () { +StringRef BotStorage::getRunningPath () { // this function get's relative path against bot library (bot library should reside in bin dir) static String path; + // we're do not do relative (against bot's library) paths on android + if (plat.android) { + if (path.empty ()) { + path = strings.joinPath (game.getRunningModName (), folders.addons, folders.bot); + } + return path; + } + // compute the full path to the our folder if (path.empty ()) { path = SharedLibrary::path (&bstor); @@ -415,9 +423,17 @@ String BotStorage::getRunningPath () { return path; } -String BotStorage::getRunningPathVFS () { +StringRef BotStorage::getRunningPathVFS () { static String path; + // we're do not do relative (against bot's library) paths on android + if (plat.android) { + if (path.empty ()) { + path = strings.joinPath (folders.addons, folders.bot); + } + return path; + } + if (path.empty ()) { path = getRunningPath (); diff --git a/src/support.cpp b/src/support.cpp index a440d25..dad09d6 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -270,14 +270,6 @@ void BotSupport::checkWelcome () { m_welcomeReceiveTime = game.time () + 2.0f + mp_freezetime.float_ (); // receive welcome message in four seconds after game has commencing } - // legacy welcome message, to respect the original code - constexpr StringRef legacyWelcomeMessage = "Welcome to POD-Bot V2.5 by Count Floyd\n" - "Visit http://www.nuclearbox.com/podbot/ or\n" - " http://www.botepidemic.com/podbot for Updates\n"; - - // it's should be send in very rare cases - const bool sendLegacyWelcome = rg.chance (2); - if (m_welcomeReceiveTime > 0.0f && m_welcomeReceiveTime < game.time () && needToSendMsg) { if (!game.is (GameFlags::Mobility | GameFlags::Xash3D)) { game.serverCommand ("speak \"%s\"", m_sentences.random ()); @@ -287,6 +279,14 @@ void BotSupport::checkWelcome () { auto graphAuthor = graph.getAuthor (); auto graphModified = graph.getModifiedBy (); + // legacy welcome message, to respect the original code + constexpr StringRef legacyWelcomeMessage = "Welcome to POD-Bot V2.5 by Count Floyd\n" + "Visit http://www.nuclearbox.com/podbot/ or\n" + " http://www.botepidemic.com/podbot for Updates\n"; + + // it's should be send in very rare cases + const bool sendLegacyWelcome = rg.chance (2); + if (!graphAuthor.startsWith (product.name)) { authorStr.assignf ("Navigation Graph by: %s", graphAuthor);