Merge branch 'master' into chatter-fixes-and-improvements

This commit is contained in:
jeefo 2024-04-25 15:09:37 +03:00
commit d76e0e1ba2
No known key found for this signature in database
GPG key ID: 927BCA0779BEA8ED
27 changed files with 588 additions and 581 deletions

@ -1 +1 @@
Subproject commit 3596ac42ccc21d93d7fe2a937870d76e944f7f07 Subproject commit ea7a91bd042599132e60482f51087d9669dbe1c4

@ -1 +1 @@
Subproject commit b99f0bac831b823a1e5a57ef3bd7c7dcaf8dee22 Subproject commit 3e2bd997a6048a0c2d9318e65a63b30a35c67dfa

View file

@ -193,25 +193,25 @@ public:
m_printQueueFlushTimestamp = 0.0f; m_printQueueFlushTimestamp = 0.0f;
} }
int intValue (size_t arg) const { template <typename U> constexpr U arg (const size_t index) const {
if (!hasArg (arg)) { if constexpr (cr::is_same <U, float>::value) {
return 0; if (!hasArg (index)) {
}
return m_args[arg].int_ ();
}
float floatValue (size_t arg) const {
if (!hasArg (arg)) {
return 0.0f; return 0.0f;
} }
return m_args[arg].float_ (); return m_args[index].as <float> ();
} }
else if constexpr (cr::is_same <U, int>::value) {
StringRef strValue (size_t arg) { if (!hasArg (index)) {
if (!hasArg (arg)) { return 0;
}
return m_args[index].as <int> ();
}
else if constexpr (cr::is_same <U, StringRef>::value) {
if (!hasArg (index)) {
return ""; return "";
} }
return m_args[arg]; return m_args[index];
}
} }
bool hasArg (size_t arg) const { bool hasArg (size_t arg) const {

View file

@ -188,7 +188,7 @@ public:
void prepareBotArgs (edict_t *ent, String str); void prepareBotArgs (edict_t *ent, String str);
// adds cvar to registration stack // adds cvar to registration stack
void addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32_t varType, bool missingAction, const char *regval, class ConVar *self); void pushConVar (StringRef name, StringRef value, StringRef info, bool bounded, float min, float max, int32_t varType, bool missingAction, StringRef regval, class ConVar *self);
// check the cvar bounds // check the cvar bounds
void checkCvarsBounds (); void checkCvarsBounds ();
@ -470,18 +470,18 @@ public:
~ConVar () = default; ~ConVar () = default;
public: public:
ConVar (const char *name, const char *initval, int32_t type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) { ConVar (StringRef name, StringRef initval, int32_t type = Var::NoServer, bool regMissing = false, StringRef regVal = nullptr) : ptr (nullptr) {
setPrefix (name, type); setPrefix (name, type);
Game::instance ().addNewCvar (name_.chars (), initval, "", false, 0.0f, 0.0f, type, regMissing, regVal, this); Game::instance ().pushConVar (name_.chars (), initval, "", false, 0.0f, 0.0f, type, regMissing, regVal, this);
} }
ConVar (const char *name, const char *initval, const char *info, bool bounded = true, float min = 0.0f, float max = 1.0f, int32_t type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) { ConVar (StringRef name, StringRef initval, StringRef info, bool bounded = true, float min = 0.0f, float max = 1.0f, int32_t type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
setPrefix (name, type); setPrefix (name, type);
Game::instance ().addNewCvar (name_.chars (), initval, info, bounded, min, max, type, regMissing, regVal, this); Game::instance ().pushConVar (name_.chars (), initval, info, bounded, min, max, type, regMissing, regVal, this);
} }
public: public:
template <typename U> constexpr U get () const { template <typename U> constexpr U as () const {
if constexpr (cr::is_same <U, float>::value) { if constexpr (cr::is_same <U, float>::value) {
return ptr->value; return ptr->value;
} }
@ -498,34 +498,22 @@ public:
public: public:
operator bool () const { operator bool () const {
return bool_ (); return as <bool> ();
} }
operator float () const { operator float () const {
return float_ (); return as <float> ();
}
operator int () const {
return as <int> ();
} }
operator StringRef () { operator StringRef () {
return str (); return as <StringRef> ();
} }
public: public:
bool bool_ () const {
return get <bool> ();
}
int int_ () const {
return get <int> ();
}
float float_ () const {
return get <float> ();
}
StringRef str () const {
return get <StringRef> ();
}
StringRef name () const { StringRef name () const {
return ptr->name; return ptr->name;
} }
@ -546,7 +534,7 @@ public:
void revert (); void revert ();
// set the cvar prefix if needed // set the cvar prefix if needed
void setPrefix (const char *name, int32_t type); void setPrefix (StringRef name, int32_t type);
}; };
class MessageWriter final { class MessageWriter final {

View file

@ -317,7 +317,7 @@ public:
// get the random node on map // get the random node on map
int32_t random () const { int32_t random () const {
return rg.get (0, length () - 1); return rg (0, length () - 1);
} }
// check if has editor // check if has editor

View file

@ -309,7 +309,7 @@ private:
bool m_jumpSequence {}; // next path link will be jump link bool m_jumpSequence {}; // next path link will be jump link
PathWalk m_pathWalk {}; // pointer to current node from path PathWalk m_pathWalk {}; // pointer to current node from path
Dodge m_combatStrafeDir {}; // direction to strafe Dodge m_dodgeStrafeDir {}; // direction to strafe
Fight m_fightStyle {}; // combat style to use Fight m_fightStyle {}; // combat style to use
CollisionState m_collisionState {}; // collision State CollisionState m_collisionState {}; // collision State
FindPath m_pathType {}; // which pathfinder to use FindPath m_pathType {}; // which pathfinder to use
@ -354,6 +354,7 @@ private:
CountdownTimer m_forgetLastVictimTimer {}; // time to forget last victim position ? CountdownTimer m_forgetLastVictimTimer {}; // time to forget last victim position ?
CountdownTimer m_approachingLadderTimer {}; // bot is approaching ladder CountdownTimer m_approachingLadderTimer {}; // bot is approaching ladder
CountdownTimer m_lostReachableNodeTimer {}; // bot's issuing next node, probably he's lost
private: private:
int pickBestWeapon (Array <int> &vec, int moneySave); int pickBestWeapon (Array <int> &vec, int moneySave);

View file

@ -18,7 +18,7 @@ ConVar cv_graph_analyze_mark_goals_on_finish ("graph_analyze_mark_goals_on_finis
void GraphAnalyze::start () { void GraphAnalyze::start () {
// start analyzer in few seconds after level initialized // start analyzer in few seconds after level initialized
if (cv_graph_analyze_auto_start.bool_ ()) { if (cv_graph_analyze_auto_start) {
m_updateInterval = game.time () + 3.0f; m_updateInterval = game.time () + 3.0f;
m_basicsCreated = false; m_basicsCreated = false;
@ -79,7 +79,7 @@ void GraphAnalyze::update () {
setUpdateInterval (); setUpdateInterval ();
auto pos = graph[i].origin; auto pos = graph[i].origin;
const auto range = cv_graph_analyze_distance.float_ (); const auto range = cv_graph_analyze_distance.as <float> ();
for (int dir = 1; dir < kMaxNodeLinks; ++dir) { for (int dir = 1; dir < kMaxNodeLinks; ++dir) {
switch (dir) { switch (dir) {
@ -149,7 +149,7 @@ void GraphAnalyze::finish () {
ctrl.msg ("Completed map analysis."); ctrl.msg ("Completed map analysis.");
// auto save bots graph // auto save bots graph
if (cv_graph_analyze_auto_save.bool_ ()) { if (cv_graph_analyze_auto_save) {
if (!graph.saveGraphData ()) { if (!graph.saveGraphData ()) {
ctrl.msg ("Can't save analyzed graph. Internal error."); ctrl.msg ("Can't save analyzed graph. Internal error.");
return; return;
@ -171,7 +171,7 @@ void GraphAnalyze::optimize () {
return; return;
} }
if (!cv_graph_analyze_optimize_nodes_on_finish.bool_ ()) { if (!cv_graph_analyze_optimize_nodes_on_finish) {
return; return;
} }
cleanup (); cleanup ();
@ -220,7 +220,7 @@ void GraphAnalyze::optimize () {
} }
// clear the useless connections // clear the useless connections
if (cv_graph_analyze_clean_paths_on_finish.bool_ ()) { if (cv_graph_analyze_clean_paths_on_finish) {
for (auto i = 0; i < graph.length (); ++i) { for (auto i = 0; i < graph.length (); ++i) {
graph.clearConnections (i); graph.clearConnections (i);
} }
@ -352,13 +352,13 @@ void GraphAnalyze::flood (const Vector &pos, const Vector &next, float range) {
void GraphAnalyze::setUpdateInterval () { void GraphAnalyze::setUpdateInterval () {
const auto frametime = globals->frametime; const auto frametime = globals->frametime;
if ((cv_graph_analyze_fps.float_ () + frametime) <= 1.0f / frametime) { if ((cv_graph_analyze_fps.as <float> () + frametime) <= 1.0f / frametime) {
m_updateInterval = game.time () + frametime * 0.06f; m_updateInterval = game.time () + frametime * 0.06f;
} }
} }
void GraphAnalyze::markGoals () { void GraphAnalyze::markGoals () {
if (!cv_graph_analyze_mark_goals_on_finish.bool_ ()) { if (!cv_graph_analyze_mark_goals_on_finish) {
return; return;
} }

View file

@ -106,7 +106,7 @@ void Bot::avoidGrenades () {
m_lookAt.y = cr::wrapAngle ((game.getEntityOrigin (pent) - getEyesPos ()).angles ().y + 180.0f); m_lookAt.y = cr::wrapAngle ((game.getEntityOrigin (pent) - getEyesPos ()).angles ().y + 180.0f);
m_canChooseAimDirection = false; m_canChooseAimDirection = false;
m_preventFlashing = game.time () + rg.get (1.0f, 2.0f); m_preventFlashing = game.time () + rg (1.0f, 2.0f);
} }
} }
else if (game.isNullEntity (m_avoidGrenade) && model == kExplosiveModelName) { else if (game.isNullEntity (m_avoidGrenade) && model == kExplosiveModelName) {
@ -132,7 +132,7 @@ void Bot::avoidGrenades () {
} }
} }
} }
else if (cv_smoke_grenade_checks.int_ () == 1 && (pent->v.flags & FL_ONGROUND) && model == kSmokeModelName) { else if (cv_smoke_grenade_checks.as <int> () == 1 && (pent->v.flags & FL_ONGROUND) && model == kSmokeModelName) {
if (isInFOV (pent->v.origin - getEyesPos ()) < pev->fov / 3.0f) { if (isInFOV (pent->v.origin - getEyesPos ()) < pev->fov / 3.0f) {
const auto &entOrigin = game.getEntityOrigin (pent); const auto &entOrigin = game.getEntityOrigin (pent);
const auto &betweenUs = (entOrigin - pev->origin).normalize_apx (); const auto &betweenUs = (entOrigin - pev->origin).normalize_apx ();
@ -175,7 +175,7 @@ void Bot::checkBreakable (edict_t *touch) {
void Bot::checkBreakablesAround () { void Bot::checkBreakablesAround () {
if (!m_buyingFinished if (!m_buyingFinished
|| !cv_destroy_breakables_around.bool_ () || !cv_destroy_breakables_around
|| usesKnife () || usesKnife ()
|| rg.chance (25) || rg.chance (25)
|| !game.hasBreakables () || !game.hasBreakables ()
@ -185,7 +185,7 @@ void Bot::checkBreakablesAround () {
return; return;
} }
const auto radius = cv_object_destroy_radius.float_ (); const auto radius = cv_object_destroy_radius.as <float> ();
// check if we're have some breakables in 400 units range // check if we're have some breakables in 400 units range
for (const auto &breakable : game.getBreakables ()) { for (const auto &breakable : game.getBreakables ()) {
@ -280,7 +280,7 @@ edict_t *Bot::lookupBreakable () {
} }
void Bot::setIdealReactionTimers (bool actual) { void Bot::setIdealReactionTimers (bool actual) {
if (cv_whose_your_daddy.bool_ ()) { if (cv_whose_your_daddy) {
m_idealReactionTime = 0.05f; m_idealReactionTime = 0.05f;
m_actualReactionTime = 0.095f; m_actualReactionTime = 0.095f;
@ -294,7 +294,7 @@ void Bot::setIdealReactionTimers (bool actual) {
return; return;
} }
m_idealReactionTime = rg.get (tweak->reaction[0], tweak->reaction[1]); m_idealReactionTime = rg (tweak->reaction[0], tweak->reaction[1]);
} }
void Bot::updatePickups () { void Bot::updatePickups () {
@ -323,7 +323,7 @@ void Bot::updatePickups () {
} }
// knife mode is in progress ? // knife mode is in progress ?
else if (cv_jasonmode.bool_ ()) { else if (cv_jasonmode) {
return true; return true;
} }
@ -343,7 +343,7 @@ void Bot::updatePickups () {
} }
const auto &interesting = bots.getInterestingEntities (); const auto &interesting = bots.getInterestingEntities ();
const float radius = cr::sqrf (cv_object_pickup_radius.float_ ()); const float radius = cr::sqrf (cv_object_pickup_radius.as <float> ());
if (!game.isNullEntity (m_pickupItem)) { if (!game.isNullEntity (m_pickupItem)) {
bool itemExists = false; bool itemExists = false;
@ -426,7 +426,7 @@ void Bot::updatePickups () {
allowPickup = true; allowPickup = true;
pickupType = Pickup::Weapon; pickupType = Pickup::Weapon;
if (cv_pickup_ammo_and_kits.bool_ ()) { if (cv_pickup_ammo_and_kits) {
const int primaryWeaponCarried = bestPrimaryCarried (); const int primaryWeaponCarried = bestPrimaryCarried ();
const int secondaryWeaponCarried = bestSecondaryCarried (); const int secondaryWeaponCarried = bestSecondaryCarried ();
@ -494,7 +494,7 @@ void Bot::updatePickups () {
} }
// weapon replacement is not allowed // weapon replacement is not allowed
if (!cv_pickup_best.bool_ ()) { if (!cv_pickup_best) {
allowPickup = false; allowPickup = false;
pickupType = Pickup::None; pickupType = Pickup::None;
} }
@ -504,7 +504,7 @@ void Bot::updatePickups () {
pickupType = Pickup::Shield; pickupType = Pickup::Shield;
// weapon replacement is not allowed // weapon replacement is not allowed
if (!cv_pickup_best.bool_ ()) { if (!cv_pickup_best) {
allowPickup = false; allowPickup = false;
pickupType = Pickup::None; pickupType = Pickup::None;
} }
@ -517,7 +517,7 @@ void Bot::updatePickups () {
allowPickup = true; allowPickup = true;
pickupType = Pickup::PlantedC4; pickupType = Pickup::PlantedC4;
} }
else if (cv_pickup_custom_items.bool_ () && util.isItem (ent) && !classname.startsWith ("item_thighpack")) { else if (cv_pickup_custom_items && util.isItem (ent) && !classname.startsWith ("item_thighpack")) {
allowPickup = true; allowPickup = true;
pickupType = Pickup::Items; pickupType = Pickup::Items;
} }
@ -577,8 +577,8 @@ void Bot::updatePickups () {
const int index = findDefendNode (origin); const int index = findDefendNode (origin);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (cv_camping_time_min.float_ (), cv_camping_time_max.float_ ()), true); // push camp task on to stack startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (cv_camping_time_min.as <float> (), cv_camping_time_max.as <float> ()), true); // push camp task on to stack
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (3.0f, 6.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (3.0f, 6.0f), true); // push move command
// decide to duck or not to duck // decide to duck or not to duck
selectCampButtons (index); selectCampButtons (index);
@ -597,7 +597,7 @@ void Bot::updatePickups () {
const int index = findDefendNode (origin); const int index = findDefendNode (origin);
const Path &path = graph[index]; const Path &path = graph[index];
const float bombTimer = mp_c4timer.float_ (); const float bombTimer = mp_c4timer.as <float> ();
const float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin); const float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
if (timeMidBlowup > game.time ()) { if (timeMidBlowup > game.time ()) {
@ -672,7 +672,7 @@ void Bot::updatePickups () {
const int index = findDefendNode (origin); const int index = findDefendNode (origin);
const auto &path = graph[index]; const auto &path = graph[index];
const float timeToExplode = bots.getTimeBombPlanted () + mp_c4timer.float_ () - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin); const float timeToExplode = bots.getTimeBombPlanted () + mp_c4timer.as <float> () - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
clearTask (Task::MoveToPosition); // remove any move tasks clearTask (Task::MoveToPosition); // remove any move tasks
@ -700,8 +700,8 @@ void Bot::updatePickups () {
if (!m_defendedBomb && m_difficulty >= Difficulty::Normal && rg.chance (75) && m_healthValue < 60) { if (!m_defendedBomb && m_difficulty >= Difficulty::Normal && rg.chance (75) && m_healthValue < 60) {
const int index = findDefendNode (origin); const int index = findDefendNode (origin);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (cv_camping_time_min.float_ (), cv_camping_time_max.float_ ()), true); // push camp task on to stack startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (cv_camping_time_min.as <float> (), cv_camping_time_max.as <float> ()), true); // push camp task on to stack
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (10.0f, 30.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (10.0f, 30.0f), true); // push move command
// decide to duck or not to duck // decide to duck or not to duck
selectCampButtons (index); selectCampButtons (index);
@ -839,7 +839,7 @@ Vector Bot::getCampDirection (const Vector &dest) {
void Bot::showChatterIcon (bool show, bool disconnect) { void Bot::showChatterIcon (bool show, bool disconnect) {
// this function depending on show boolean, shows/remove chatter, icon, on the head of bot. // this function depending on show boolean, shows/remove chatter, icon, on the head of bot.
if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.int_ () != 2) { if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.as <int> () != 2) {
return; return;
} }
@ -877,7 +877,7 @@ void Bot::showChatterIcon (bool show, bool disconnect) {
void Bot::instantChatter (int type) { void Bot::instantChatter (int type) {
// this function sends instant chatter messages. // this function sends instant chatter messages.
if (!game.is (GameFlags::HasBotVoice) if (!game.is (GameFlags::HasBotVoice)
|| cv_radio_mode.int_ () != 2 || cv_radio_mode.as <int> () != 2
|| !conf.hasChatterBank (type) || !conf.hasChatterBank (type)
|| !conf.hasChatterBank (Chatter::DiePain)) { || !conf.hasChatterBank (Chatter::DiePain)) {
@ -894,7 +894,7 @@ void Bot::instantChatter (int type) {
const int ownIndex = index (); const int ownIndex = index ();
auto writeChatterSound = [&msg] (ChatterItem item) { auto writeChatterSound = [&msg] (ChatterItem item) {
msg.writeString (strings.format ("%s%s%s.wav", cv_chatter_path.str (), kPathSeparator, item.name)); msg.writeString (strings.format ("%s%s%s.wav", cv_chatter_path.as <StringRef> (), kPathSeparator, item.name));
}; };
for (auto &client : util.getClients ()) { for (auto &client : util.getClients ()) {
@ -920,12 +920,12 @@ void Bot::instantChatter (int type) {
void Bot::pushRadioMessage (int message) { void Bot::pushRadioMessage (int message) {
// this function inserts the radio message into the message queue // this function inserts the radio message into the message queue
if (cv_radio_mode.int_ () == 0 || m_numFriendsLeft == 0) { if (cv_radio_mode.as <int> () == 0 || m_numFriendsLeft == 0) {
return; return;
} }
m_forceRadio = !game.is (GameFlags::HasBotVoice) m_forceRadio = !game.is (GameFlags::HasBotVoice)
|| !conf.hasChatterBank (message) || !conf.hasChatterBank (message)
|| cv_radio_mode.int_ () != 2; // use radio instead voice || cv_radio_mode.as <int> () != 2; // use radio instead voice
m_radioSelect = message; m_radioSelect = message;
pushMsgQueue (BotMsg::Radio); pushMsgQueue (BotMsg::Radio);
@ -934,7 +934,7 @@ void Bot::pushRadioMessage (int message) {
void Bot::pushChatterMessage (int message) { void Bot::pushChatterMessage (int message) {
// this function inserts the voice message into the message queue (mostly same as above) // this function inserts the voice message into the message queue (mostly same as above)
if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.int_ () != 2 || !conf.hasChatterBank (message) || m_numFriendsLeft == 0) { if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.as <int> () != 2 || !conf.hasChatterBank (message) || m_numFriendsLeft == 0) {
return; return;
} }
bool sendMessage = false; bool sendMessage = false;
@ -991,21 +991,21 @@ void Bot::checkMsgQueue () {
} }
m_buyPending = false; m_buyPending = false;
m_nextBuyTime = game.time () + rg.get (0.5f, 1.3f); m_nextBuyTime = game.time () + rg (0.5f, 1.3f);
// if freezetime is very low do not delay the buy process // if freezetime is very low do not delay the buy process
if (mp_freezetime.float_ () <= 1.0f) { if (mp_freezetime.as <float> () <= 1.0f) {
m_nextBuyTime = game.time (); m_nextBuyTime = game.time ();
m_ignoreBuyDelay = true; m_ignoreBuyDelay = true;
} }
// if bot buying is off then no need to buy // if bot buying is off then no need to buy
if (!cv_botbuy.bool_ ()) { if (!cv_botbuy) {
m_buyState = BuyState::Done; m_buyState = BuyState::Done;
} }
// if fun-mode no need to buy // if fun-mode no need to buy
if (cv_jasonmode.bool_ ()) { if (cv_jasonmode) {
m_buyState = BuyState::Done; m_buyState = BuyState::Done;
selectWeaponById (Weapon::Knife); selectWeaponById (Weapon::Knife);
} }
@ -1067,7 +1067,7 @@ void Bot::checkMsgQueue () {
if (m_radioSelect != -1) { if (m_radioSelect != -1) {
if ((m_radioSelect != Radio::ReportingIn && m_forceRadio) if ((m_radioSelect != Radio::ReportingIn && m_forceRadio)
|| cv_radio_mode.int_ () != 2 || cv_radio_mode.as <int> () != 2
|| !conf.hasChatterBank (m_radioSelect) || !conf.hasChatterBank (m_radioSelect)
|| !game.is (GameFlags::HasBotVoice)) { || !game.is (GameFlags::HasBotVoice)) {
@ -1116,7 +1116,7 @@ void Bot::checkMsgQueue () {
bool Bot::isWeaponRestricted (int wid) { bool Bot::isWeaponRestricted (int wid) {
// this function checks for weapon restrictions. // this function checks for weapon restrictions.
auto val = cv_restricted_weapons.str (); auto val = cv_restricted_weapons.as <StringRef> ();
if (val.empty ()) { if (val.empty ()) {
return isWeaponRestrictedAMX (wid); // no banned weapons return isWeaponRestrictedAMX (wid); // no banned weapons
@ -1213,7 +1213,7 @@ int Bot::pickBestWeapon (Array <int> &vec, int moneySave) {
// swap array values // swap array values
vec.reverse (); vec.reverse ();
return vec[static_cast <int> (static_cast <float> (vec.length <int32_t> () - 1) * cr::log10 (rg.get (1.0f, cr::powf (10.0f, buyFactor))) / buyFactor + 0.5f)]; return vec[static_cast <int> (static_cast <float> (vec.length <int32_t> () - 1) * cr::log10 (rg (1.0f, cr::powf (10.0f, buyFactor))) / buyFactor + 0.5f)];
} }
int chance = 95; int chance = 95;
@ -1232,7 +1232,7 @@ int Bot::pickBestWeapon (Array <int> &vec, int moneySave) {
const auto &weapon = tab[w]; const auto &weapon = tab[w];
// if we have enough money for weapon, buy it // if we have enough money for weapon, buy it
if (weapon.price + moneySave < m_moneyAmount + rg.get (50, 200) && rg.chance (chance)) { if (weapon.price + moneySave < m_moneyAmount + rg (50, 200) && rg.chance (chance)) {
return w; return w;
} }
} }
@ -1246,7 +1246,7 @@ void Bot::buyStuff () {
m_nextBuyTime = game.time (); m_nextBuyTime = game.time ();
if (!m_ignoreBuyDelay) { if (!m_ignoreBuyDelay) {
m_nextBuyTime += rg.get (0.3f, 0.5f); m_nextBuyTime += rg (0.3f, 0.5f);
} }
int count = 0; int count = 0;
@ -1263,7 +1263,7 @@ void Bot::buyStuff () {
const bool isOldGame = game.is (GameFlags::Legacy); const bool isOldGame = game.is (GameFlags::Legacy);
const bool hasDefaultPistols = (pev->weapons & (cr::bit (Weapon::USP) | cr::bit (Weapon::Glock18))); const bool hasDefaultPistols = (pev->weapons & (cr::bit (Weapon::USP) | cr::bit (Weapon::Glock18)));
const bool isFirstRound = m_moneyAmount == mp_startmoney.int_ (); const bool isFirstRound = m_moneyAmount == mp_startmoney.as <int> ();
switch (m_buyState) { switch (m_buyState) {
case BuyState::PrimaryWeapon: // if no primary weapon and bot has some money, buy a primary weapon case BuyState::PrimaryWeapon: // if no primary weapon and bot has some money, buy a primary weapon
@ -1308,7 +1308,7 @@ void Bot::buyStuff () {
const int *limit = conf.getEconLimit (); const int *limit = conf.getEconLimit ();
int prostock = 0; int prostock = 0;
const int disrespectEconomicsPct = 100 - cv_economics_disrespect_percent.int_ (); const int disrespectEconomicsPct = 100 - cv_economics_disrespect_percent.as <int> ();
// filter out weapons with bot economics // filter out weapons with bot economics
switch (m_personality) { switch (m_personality) {
@ -1389,12 +1389,12 @@ void Bot::buyStuff () {
break; break;
} }
if (ignoreWeapon && tab[25].teamStandard == 1 && cv_economics_rounds.bool_ ()) { if (ignoreWeapon && tab[25].teamStandard == 1 && cv_economics_rounds) {
continue; continue;
} }
// save money for grenade for example? // save money for grenade for example?
moneySave = rg.get (500, 1000); moneySave = rg (500, 1000);
if (bots.getLastWinner () == m_team) { if (bots.getLastWinner () == m_team) {
moneySave = 0; moneySave = 0;
@ -1441,7 +1441,7 @@ void Bot::buyStuff () {
break; break;
case BuyState::ArmorVestHelm: // if armor is damaged and bot has some money, buy some armor case BuyState::ArmorVestHelm: // if armor is damaged and bot has some money, buy some armor
if (pev->armorvalue < rg.get (50.0f, 80.0f) if (pev->armorvalue < rg (50.0f, 80.0f)
&& teamHasGoodEconomics && teamHasGoodEconomics
&& (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) { && (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) {
@ -1458,8 +1458,8 @@ void Bot::buyStuff () {
case BuyState::SecondaryWeapon: // if bot has still some money, buy a better secondary weapon case BuyState::SecondaryWeapon: // if bot has still some money, buy a better secondary weapon
if (isPistolMode if (isPistolMode
|| (isFirstRound && hasDefaultPistols && rg.chance (60)) || (isFirstRound && hasDefaultPistols && rg.chance (60))
|| (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg.get (2000, 3000)) || (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg (2000, 3000))
|| (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg.get (7500, 9000))) { || (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg (7500, 9000))) {
do { do {
pref--; pref--;
@ -1492,7 +1492,7 @@ void Bot::buyStuff () {
continue; continue;
} }
if (selectedWeapon->price <= (m_moneyAmount - rg.get (100, 200))) { if (selectedWeapon->price <= (m_moneyAmount - rg (100, 200))) {
choices.emplace (*pref); choices.emplace (*pref);
} }
@ -1500,7 +1500,7 @@ void Bot::buyStuff () {
// found a desired weapon? // found a desired weapon?
if (!choices.empty ()) { if (!choices.empty ()) {
selectedWeapon = &tab[pickBestWeapon (choices, rg.get (100, 200))]; selectedWeapon = &tab[pickBestWeapon (choices, rg (100, 200))];
} }
else { else {
selectedWeapon = nullptr; selectedWeapon = nullptr;
@ -1527,7 +1527,7 @@ void Bot::buyStuff () {
case BuyState::Ammo: // buy enough primary & secondary ammo (do not check for money here) case BuyState::Ammo: // buy enough primary & secondary ammo (do not check for money here)
for (int i = 0; i < 7; ++i) { for (int i = 0; i < 7; ++i) {
issueCommand ("buyammo%d", rg.get (1, 2)); // simulate human issueCommand ("buyammo%d", rg (1, 2)); // simulate human
} }
// buy enough ammo // buy enough ammo
@ -1654,7 +1654,7 @@ void Bot::overrideConditions () {
} }
// special handling, if we have a knife in our hands // special handling, if we have a knife in our hands
if (isKnifeMode () && (util.isPlayer (m_enemy) || (cv_attack_monsters.bool_ () && util.isMonster (m_enemy)))) { if (isKnifeMode () && (util.isPlayer (m_enemy) || (cv_attack_monsters && util.isMonster (m_enemy)))) {
const float length = pev->origin.distance2d (m_enemy->v.origin); const float length = pev->origin.distance2d (m_enemy->v.origin);
// do nodes movement if enemy is not reachable with a knife // do nodes movement if enemy is not reachable with a knife
@ -1802,7 +1802,7 @@ void Bot::setLastVictim (edict_t *ent) {
m_lastVictim = ent; m_lastVictim = ent;
m_lastVictimOrigin = ent->v.origin; m_lastVictimOrigin = ent->v.origin;
m_forgetLastVictimTimer.start (rg.get (1.0f, 2.0f)); m_forgetLastVictimTimer.start (rg (1.0f, 2.0f));
} }
void Bot::setConditions () { void Bot::setConditions () {
@ -1897,7 +1897,7 @@ void Bot::setConditions () {
} }
// don't listen if seeing enemy, just checked for sounds or being blinded (because its inhuman) // don't listen if seeing enemy, just checked for sounds or being blinded (because its inhuman)
if (!cv_ignore_enemies.bool_ () if (!cv_ignore_enemies
&& m_soundUpdateTime < game.time () && m_soundUpdateTime < game.time ()
&& m_blindTime < game.time () && m_blindTime < game.time ()
&& m_seeEnemyTime + 1.0f < game.time ()) { && m_seeEnemyTime + 1.0f < game.time ()) {
@ -1991,12 +1991,12 @@ void Bot::filterTasks () {
if (util.isPlayer (m_lastEnemy) && !m_lastEnemyOrigin.empty () && !m_hasC4) { if (util.isPlayer (m_lastEnemy) && !m_lastEnemyOrigin.empty () && !m_hasC4) {
float retreatLevel = (100.0f - (m_healthValue > 70.0f ? 100.0f : m_healthValue)) * tempFear; // retreat level depends on bot health float retreatLevel = (100.0f - (m_healthValue > 70.0f ? 100.0f : m_healthValue)) * tempFear; // retreat level depends on bot health
if (m_numEnemiesLeft > m_numFriendsLeft / 2 && m_retreatTime < game.time () && m_seeEnemyTime - rg.get (2.0f, 4.0f) < game.time ()) { if (m_numEnemiesLeft > m_numFriendsLeft / 2 && m_retreatTime < game.time () && m_seeEnemyTime - rg (2.0f, 4.0f) < game.time ()) {
float timeSeen = m_seeEnemyTime - game.time (); float timeSeen = m_seeEnemyTime - game.time ();
float timeHeard = m_heardSoundTime - game.time (); float timeHeard = m_heardSoundTime - game.time ();
float ratio = 0.0f; float ratio = 0.0f;
m_retreatTime = game.time () + rg.get (1.0f, 4.0f); m_retreatTime = game.time () + rg (1.0f, 4.0f);
if (timeSeen > timeHeard) { if (timeSeen > timeHeard) {
timeSeen += 10.0f; timeSeen += 10.0f;
@ -2042,7 +2042,7 @@ void Bot::filterTasks () {
&& !m_isUsingGrenade && !m_isUsingGrenade
&& m_currentNodeIndex != graph.getNearest (m_lastEnemyOrigin) && m_currentNodeIndex != graph.getNearest (m_lastEnemyOrigin)
&& m_personality != Personality::Careful && m_personality != Personality::Careful
&& !cv_ignore_enemies.bool_ ()) { && !cv_ignore_enemies) {
float desireLevel = 4096.0f - ((1.0f - tempAgression) * m_lastEnemyOrigin.distance (pev->origin)); float desireLevel = 4096.0f - ((1.0f - tempAgression) * m_lastEnemyOrigin.distance (pev->origin));
@ -2166,7 +2166,7 @@ void Bot::startTask (Task id, float desire, int data, float time, bool resume) {
} }
// this is best place to handle some voice commands report team some info // this is best place to handle some voice commands report team some info
if (cv_radio_mode.int_ () > 1) { if (cv_radio_mode.as <int> () > 1) {
if (rg.chance (90)) { if (rg.chance (90)) {
if (tid == Task::Blind) { if (tid == Task::Blind) {
pushChatterMessage (Chatter::Blind); pushChatterMessage (Chatter::Blind);
@ -2198,8 +2198,8 @@ void Bot::startTask (Task id, float desire, int data, float time, bool resume) {
} }
} }
if (cv_debug_goal.int_ () != kInvalidNodeIndex) { if (cv_debug_goal.as <int> () != kInvalidNodeIndex) {
m_chosenGoalIndex = cv_debug_goal.int_ (); m_chosenGoalIndex = cv_debug_goal.as <int> ();
} }
else { else {
m_chosenGoalIndex = getTask ()->data; m_chosenGoalIndex = getTask ()->data;
@ -2354,7 +2354,7 @@ void Bot::checkRadioQueue () {
} }
} }
} }
int allowedFollowers = cv_user_max_followers.int_ (); int allowedFollowers = cv_user_max_followers.as <int> ();
if (m_radioEntity->v.weapons & cr::bit (Weapon::C4)) { if (m_radioEntity->v.weapons & cr::bit (Weapon::C4)) {
allowedFollowers = 1; allowedFollowers = 1;
@ -2403,7 +2403,7 @@ void Bot::checkRadioQueue () {
pushRadioMessage (Radio::RogerThat); pushRadioMessage (Radio::RogerThat);
m_campButtons = 0; m_campButtons = 0;
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), false); startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg (30.0f, 60.0f), false);
} }
} }
break; break;
@ -2422,10 +2422,10 @@ void Bot::checkRadioQueue () {
m_fearLevel = 0.0f; m_fearLevel = 0.0f;
} }
if (rg.chance (45) && cv_radio_mode.int_ () == 2) { if (rg.chance (45) && cv_radio_mode.as <int> () == 2) {
pushChatterMessage (Chatter::OnMyWay); pushChatterMessage (Chatter::OnMyWay);
} }
else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.int_ () != 2) { else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as <int> () != 2) {
pushRadioMessage (Radio::RogerThat); pushRadioMessage (Radio::RogerThat);
} }
tryHeadTowardRadioMessage (); tryHeadTowardRadioMessage ();
@ -2456,10 +2456,10 @@ void Bot::checkRadioQueue () {
m_fearLevel = 0.0f; m_fearLevel = 0.0f;
} }
if (rg.chance (45) && cv_radio_mode.int_ () == 2) { if (rg.chance (45) && cv_radio_mode.as <int> () == 2) {
pushChatterMessage (Chatter::OnMyWay); pushChatterMessage (Chatter::OnMyWay);
} }
else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.int_ () != 2 && rg.chance (50)) { else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as <int> () != 2 && rg.chance (50)) {
pushRadioMessage (Radio::RogerThat); pushRadioMessage (Radio::RogerThat);
} }
tryHeadTowardRadioMessage (); tryHeadTowardRadioMessage ();
@ -2471,10 +2471,10 @@ void Bot::checkRadioQueue () {
case Radio::GoGoGo: case Radio::GoGoGo:
if (m_radioEntity == m_targetEntity) { if (m_radioEntity == m_targetEntity) {
if (rg.chance (45) && cv_radio_mode.int_ () == 2) { if (rg.chance (45) && cv_radio_mode.as <int> () == 2) {
pushRadioMessage (Radio::RogerThat); pushRadioMessage (Radio::RogerThat);
} }
else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.int_ () != 2) { else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as <int> () != 2) {
pushRadioMessage (Radio::RogerThat); pushRadioMessage (Radio::RogerThat);
} }
@ -2500,7 +2500,7 @@ void Bot::checkRadioQueue () {
getTask ()->time = game.time (); getTask ()->time = game.time ();
m_targetEntity = nullptr; m_targetEntity = nullptr;
m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg.get (1024.0f, 2048.0f); m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg (1024.0f, 2048.0f);
clearSearchNodes (); clearSearchNodes ();
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true); startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true);
@ -2554,7 +2554,7 @@ void Bot::checkRadioQueue () {
getTask ()->time = game.time (); getTask ()->time = game.time ();
} }
m_targetEntity = nullptr; m_targetEntity = nullptr;
m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg.get (1024.0f, 2048.0f); m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg (1024.0f, 2048.0f);
clearSearchNodes (); clearSearchNodes ();
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true); startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true);
@ -2585,7 +2585,7 @@ void Bot::checkRadioQueue () {
m_agressionLevel = 0.0f; m_agressionLevel = 0.0f;
} }
if (getCurrentTaskId () == Task::Camp) { if (getCurrentTaskId () == Task::Camp) {
getTask ()->time += rg.get (10.0f, 15.0f); getTask ()->time += rg (10.0f, 15.0f);
} }
else { else {
// don't pause/camp anymore // don't pause/camp anymore
@ -2746,7 +2746,7 @@ void Bot::checkRadioQueue () {
pushRadioMessage (Radio::RogerThat); pushRadioMessage (Radio::RogerThat);
if (getCurrentTaskId () == Task::Camp) { if (getCurrentTaskId () == Task::Camp) {
getTask ()->time = game.time () + rg.get (30.0f, 60.0f); getTask ()->time = game.time () + rg (30.0f, 60.0f);
} }
else { else {
// don't pause anymore // don't pause anymore
@ -2785,10 +2785,10 @@ void Bot::checkRadioQueue () {
const int index = findDefendNode (m_radioEntity->v.origin); const int index = findDefendNode (m_radioEntity->v.origin);
// push camp task on to stack // push camp task on to stack
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (30.0f, 60.0f), true);
// push move command // push move command
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (30.0f, 60.0f), true); startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (30.0f, 60.0f), true);
// decide to duck or not to duck // decide to duck or not to duck
selectCampButtons (index); selectCampButtons (index);
@ -2885,7 +2885,7 @@ void Bot::frame () {
} }
// kick the bot if stay time is over, the quota maintain will add new bot for us later // kick the bot if stay time is over, the quota maintain will add new bot for us later
if (cv_rotate_bots.bool_ () && m_stayTime < game.time ()) { if (cv_rotate_bots && m_stayTime < game.time ()) {
m_kickedByRotation = true; // kicked by rotation, so not save bot name if save bot names is active m_kickedByRotation = true; // kicked by rotation, so not save bot name if save bot names is active
kick (); kick ();
@ -2905,7 +2905,7 @@ void Bot::update () {
if (m_team == Team::Terrorist && game.mapIs (MapFlags::Demolition)) { if (m_team == Team::Terrorist && game.mapIs (MapFlags::Demolition)) {
m_hasC4 = !!(pev->weapons & cr::bit (Weapon::C4)); m_hasC4 = !!(pev->weapons & cr::bit (Weapon::C4));
if (m_hasC4 && (cv_ignore_objectives.bool_ () || cv_jasonmode.bool_ ())) { if (m_hasC4 && (cv_ignore_objectives || cv_jasonmode)) {
m_hasC4 = false; m_hasC4 = false;
} }
} }
@ -2931,12 +2931,12 @@ void Bot::update () {
} }
else if (!m_isAlive) { else if (!m_isAlive) {
// we got a teamkiller? vote him away... // we got a teamkiller? vote him away...
if (m_voteKickIndex != m_lastVoteKick && cv_tkpunish.bool_ ()) { if (m_voteKickIndex != m_lastVoteKick && cv_tkpunish) {
issueCommand ("vote %d", m_voteKickIndex); issueCommand ("vote %d", m_voteKickIndex);
m_lastVoteKick = m_voteKickIndex; m_lastVoteKick = m_voteKickIndex;
// if bot tk punishment is enabled slay the tk // if bot tk punishment is enabled slay the tk
if (cv_tkpunish.int_ () != 2 || util.isFakeClient (game.entityOfIndex (m_voteKickIndex))) { if (cv_tkpunish.as <int> () != 2 || util.isFakeClient (game.entityOfIndex (m_voteKickIndex))) {
return; return;
} }
auto killer = game.entityOfIndex (m_lastVoteKick); auto killer = game.entityOfIndex (m_lastVoteKick);
@ -2953,7 +2953,7 @@ void Bot::update () {
} }
else if (m_buyingFinished else if (m_buyingFinished
&& !(pev->maxspeed < 10.0f && tid != Task::PlantBomb && tid != Task::DefuseBomb) && !(pev->maxspeed < 10.0f && tid != Task::PlantBomb && tid != Task::DefuseBomb)
&& !cv_freeze_bots.bool_ () && !cv_freeze_bots
&& !graph.hasChanged ()) { && !graph.hasChanged ()) {
botMovement = true; botMovement = true;
@ -2972,17 +2972,13 @@ void Bot::update () {
} }
void Bot::logicDuringFreezetime () { void Bot::logicDuringFreezetime () {
pev->button = 0;
if (m_changeViewTime > game.time ()) { if (m_changeViewTime > game.time ()) {
return; return;
} }
// simply skip randomly if (rg.chance (15) && m_jumpTime + rg (1.0f, 2.0f) < game.time ()) {
if (rg.chance (10)) {
return;
}
pev->button &= ~IN_DUCK;
if (rg.chance (15) && m_jumpTime + rg.get (1.0, 2.0f) < game.time ()) {
pev->button |= IN_JUMP; pev->button |= IN_JUMP;
m_jumpTime = game.time (); m_jumpTime = game.time ();
} }
@ -2990,7 +2986,7 @@ void Bot::logicDuringFreezetime () {
teammates.clear (); teammates.clear ();
for (const auto &bot : bots) { for (const auto &bot : bots) {
if (bot->m_isAlive && bot->m_team == m_team && seesEntity (bot->pev->origin) && bot.get () != this) { if (bot->m_isAlive && bot->m_team == m_team && bot.get () != this && seesEntity (bot->pev->origin)) {
teammates.push (bot.get ()); teammates.push (bot.get ());
} }
} }
@ -3008,7 +3004,7 @@ void Bot::logicDuringFreezetime () {
m_needToSendWelcomeChat = false; m_needToSendWelcomeChat = false;
} }
} }
m_changeViewTime = game.time () + rg.get (1.25f, 2.0f); m_changeViewTime = game.time () + rg (1.25f, 2.0f);
} }
void Bot::executeTasks () { void Bot::executeTasks () {
@ -3024,8 +3020,8 @@ void Bot::checkSpawnConditions () {
// this function is called instead of ai when buying finished, but freezetime is not yet left. // this function is called instead of ai when buying finished, but freezetime is not yet left.
// switch to knife if time to do this // switch to knife if time to do this
if (m_checkKnifeSwitch && m_buyingFinished && m_spawnTime + rg.get (5.0f, 7.5f) < game.time ()) { if (m_checkKnifeSwitch && m_buyingFinished && m_spawnTime + rg (5.0f, 7.5f) < game.time ()) {
if (rg.get (1, 100) < 2 && cv_spraypaints.bool_ ()) { if (rg (1, 100) < 2 && cv_spraypaints) {
startTask (Task::Spraypaint, TaskPri::Spraypaint, kInvalidNodeIndex, game.time () + 1.0f, false); startTask (Task::Spraypaint, TaskPri::Spraypaint, kInvalidNodeIndex, game.time () + 1.0f, false);
} }
@ -3043,13 +3039,13 @@ void Bot::checkSpawnConditions () {
} }
m_checkKnifeSwitch = false; m_checkKnifeSwitch = false;
if (rg.chance (cv_user_follow_percent.int_ ()) && game.isNullEntity (m_targetEntity) && !m_isLeader && !m_hasC4 && rg.chance (50)) { if (rg.chance (cv_user_follow_percent.as <int> ()) && game.isNullEntity (m_targetEntity) && !m_isLeader && !m_hasC4 && rg.chance (50)) {
decideFollowUser (); decideFollowUser ();
} }
} }
// check if we already switched weapon mode // check if we already switched weapon mode
if (m_checkWeaponSwitch && m_buyingFinished && m_spawnTime + rg.get (3.0f, 4.5f) < game.time ()) { if (m_checkWeaponSwitch && m_buyingFinished && m_spawnTime + rg (3.0f, 4.5f) < game.time ()) {
if (hasShield () && isShieldDrawn ()) { if (hasShield () && isShieldDrawn ()) {
pev->button |= IN_ATTACK2; pev->button |= IN_ATTACK2;
} }
@ -3129,7 +3125,7 @@ void Bot::logic () {
} }
// some stuff required by by chatter engine // some stuff required by by chatter engine
if (cv_radio_mode.int_ () == 2) { if (cv_radio_mode.as <int> () == 2) {
if ((m_states & Sense::SeeingEnemy) && !game.isNullEntity (m_enemy)) { if ((m_states & Sense::SeeingEnemy) && !game.isNullEntity (m_enemy)) {
int hasFriendNearby = numFriendsNear (pev->origin, 512.0f); int hasFriendNearby = numFriendsNear (pev->origin, 512.0f);
@ -3171,7 +3167,7 @@ void Bot::logic () {
m_wantsToFire = false; m_wantsToFire = false;
// avoid flyings grenades, if needed // avoid flyings grenades, if needed
if (cv_avoid_grenades.bool_ () && !m_isCreature) { if (cv_avoid_grenades && !m_isCreature) {
avoidGrenades (); avoidGrenades ();
} }
m_isUsingGrenade = false; m_isUsingGrenade = false;
@ -3219,7 +3215,7 @@ void Bot::logic () {
} }
// check the darkness // check the darkness
if (cv_check_darkness.bool_ ()) { if (cv_check_darkness) {
checkDarkness (); checkDarkness ();
} }
@ -3237,7 +3233,7 @@ void Bot::logic () {
checkParachute (); checkParachute ();
// display some debugging thingy to host entity // display some debugging thingy to host entity
if (cv_debug.int_ () >= 1) { if (cv_debug.as <int> () >= 1) {
showDebugOverlay (); showDebugOverlay ();
} }
@ -3266,7 +3262,7 @@ void Bot::showDebugOverlay () {
displayDebugOverlay = true; displayDebugOverlay = true;
} }
if (!displayDebugOverlay && cv_debug.int_ () >= 2) { if (!displayDebugOverlay && cv_debug.as <int> () >= 2) {
Bot *nearest = nullptr; Bot *nearest = nullptr;
if (util.findNearestPlayer (reinterpret_cast <void **> (&nearest), overlayEntity, 128.0f, false, true, true, true) && nearest == this) { if (util.findNearestPlayer (reinterpret_cast <void **> (&nearest), overlayEntity, 128.0f, false, true, true, true) && nearest == this) {
@ -3405,7 +3401,7 @@ void Bot::showDebugOverlay () {
} }
bool Bot::hasHostage () { bool Bot::hasHostage () {
if (cv_ignore_objectives.bool_ () || game.mapIs (MapFlags::Demolition)) { if (cv_ignore_objectives || game.mapIs (MapFlags::Demolition)) {
return false; return false;
} }
@ -3433,10 +3429,10 @@ void Bot::takeDamage (edict_t *inflictor, int damage, int armor, int bits) {
updatePracticeValue (damage); updatePracticeValue (damage);
} }
if (util.isPlayer (inflictor) || (cv_attack_monsters.bool_ () && util.isMonster (inflictor))) { if (util.isPlayer (inflictor) || (cv_attack_monsters && util.isMonster (inflictor))) {
const auto inflictorTeam = game.getTeam (inflictor); const auto inflictorTeam = game.getTeam (inflictor);
if (!util.isMonster (inflictor) && cv_tkpunish.bool_ () && inflictorTeam == m_team && !util.isFakeClient (inflictor)) { if (!util.isMonster (inflictor) && cv_tkpunish && inflictorTeam == m_team && !util.isFakeClient (inflictor)) {
// alright, die you team killer!!! // alright, die you team killer!!!
m_actualReactionTime = 0.0f; m_actualReactionTime = 0.0f;
m_seeEnemyTime = game.time (); m_seeEnemyTime = game.time ();
@ -3494,7 +3490,7 @@ void Bot::takeBlind (int alpha) {
// this function gets called by network message handler, when screenfade message get's send // this function gets called by network message handler, when screenfade message get's send
// it's used to make bot blind from the grenade. // it's used to make bot blind from the grenade.
m_viewDistance = rg.get (10.0f, 20.0f); m_viewDistance = rg (10.0f, 20.0f);
// do not take in effect some unique map effects on round start // do not take in effect some unique map effects on round start
if (bots.getRoundStartTime () + 5.0f < game.time ()) { if (bots.getRoundStartTime () + 5.0f < game.time ()) {
@ -3606,7 +3602,7 @@ void Bot::updatePracticeDamage (edict_t *attacker, int damage) {
} }
void Bot::pushChatMessage (int type, bool isTeamSay) { void Bot::pushChatMessage (int type, bool isTeamSay) {
if (!conf.hasChatBank (type) || !cv_chat.bool_ ()) { if (!conf.hasChatBank (type) || !cv_chat) {
return; return;
} }
@ -3679,7 +3675,7 @@ void Bot::debugMsgInternal (StringRef str) {
if (game.isDedicated ()) { if (game.isDedicated ()) {
return; return;
} }
const int level = cv_debug.int_ (); const int level = cv_debug.as <int> ();
if (level <= 2) { if (level <= 2) {
return; return;
@ -3718,7 +3714,7 @@ Vector Bot::isBombAudible () {
} }
const Vector &bombOrigin = graph.getBombOrigin (); const Vector &bombOrigin = graph.getBombOrigin ();
const float timeElapsed = ((game.time () - bots.getTimeBombPlanted ()) / mp_c4timer.float_ ()) * 100.0f; const float timeElapsed = ((game.time () - bots.getTimeBombPlanted ()) / mp_c4timer.as <float> ()) * 100.0f;
float desiredRadius = 768.0f; float desiredRadius = 768.0f;
// start the manual calculations // start the manual calculations
@ -3803,7 +3799,7 @@ float Bot::getBombTimeleft () const {
if (!bots.isBombPlanted ()) { if (!bots.isBombPlanted ()) {
return 0.0f; return 0.0f;
} }
return cr::max (bots.getTimeBombPlanted () + mp_c4timer.float_ () - game.time (), 0.0f); return cr::max (bots.getTimeBombPlanted () + mp_c4timer.as <float> () - game.time (), 0.0f);
} }
bool Bot::isOutOfBombTimer () { bool Bot::isOutOfBombTimer () {
@ -3915,8 +3911,8 @@ void Bot::updateHearing () {
auto error = kSprayDistance * cr::powf (nearestDistanceSq, 0.5f) / 2048.0f; auto error = kSprayDistance * cr::powf (nearestDistanceSq, 0.5f) / 2048.0f;
auto origin = hearedEnemy->v.origin; auto origin = hearedEnemy->v.origin;
origin.x = origin.x + rg.get (-error, error); origin.x = origin.x + rg (-error, error);
origin.y = origin.y + rg.get (-error, error); origin.y = origin.y + rg (-error, error);
return origin; return origin;
}; };
@ -3962,7 +3958,7 @@ void Bot::updateHearing () {
// check if heard enemy can be shoot through some obstacle // check if heard enemy can be shoot through some obstacle
else { else {
if (cv_shoots_thru_walls.bool_ () if (cv_shoots_thru_walls
&& m_lastEnemy == hearedEnemy && m_lastEnemy == hearedEnemy
&& rg.chance (conf.getDifficultyTweaks (m_difficulty)->hearThruPct) && rg.chance (conf.getDifficultyTweaks (m_difficulty)->hearThruPct)
&& m_seeEnemyTime + 3.0f > game.time () && m_seeEnemyTime + 3.0f > game.time ()
@ -3992,7 +3988,7 @@ void Bot::enteredBuyZone (int buyState) {
if (m_seeEnemyTime + 12.0f < game.time () if (m_seeEnemyTime + 12.0f < game.time ()
&& m_lastEquipTime + 15.0f < game.time () && m_lastEquipTime + 15.0f < game.time ()
&& m_inBuyZone && m_inBuyZone
&& (bots.getRoundStartTime () + rg.get (10.0f, 20.0f) + mp_buytime.float_ () < game.time ()) && (bots.getRoundStartTime () + rg (10.0f, 20.0f) + mp_buytime.as <float> () < game.time ())
&& !bots.isBombPlanted () && !bots.isBombPlanted ()
&& m_moneyAmount > econLimit[EcoLimit::PrimaryGreater]) { && m_moneyAmount > econLimit[EcoLimit::PrimaryGreater]) {
@ -4085,7 +4081,8 @@ float Bot::getShiftSpeed () {
|| isInWater () || isInWater ()
|| isKnifeMode () || isKnifeMode ()
|| m_isStuck || m_isStuck
|| m_numEnemiesLeft <= 0) { || m_numEnemiesLeft <= 0
|| !m_lostReachableNodeTimer.elapsed ()) {
return pev->maxspeed; return pev->maxspeed;
} }

View file

@ -55,14 +55,14 @@ void BotChatManager::humanizePlayerName (String &playerName) {
} }
// sometimes switch name to lower characters, only valid for the english languge // sometimes switch name to lower characters, only valid for the english languge
if (rg.chance (8) && cv_language.str () == "en") { if (rg.chance (8) && cv_language.as <StringRef> () == "en") {
playerName.lowercase (); playerName.lowercase ();
} }
} }
void BotChatManager::addChatErrors (String &line) { void BotChatManager::addChatErrors (String &line) {
// sometimes switch name to lower characters, only valid for the english languge // sometimes switch name to lower characters, only valid for the english languge
if (rg.chance (8) && cv_language.str () == "en") { if (rg.chance (8) && cv_language.as <StringRef> () == "en") {
line.lowercase (); line.lowercase ();
} }
const auto length = static_cast <int32_t> (line.length ()); const auto length = static_cast <int32_t> (line.length ());
@ -72,12 +72,13 @@ void BotChatManager::addChatErrors (String &line) {
// "length / 2" percent of time drop a character // "length / 2" percent of time drop a character
if (rg.chance (percentile)) { if (rg.chance (percentile)) {
line.erase (static_cast <size_t> (rg.get (length / 8, length - length / 8), 1)); auto pos = rg (length / 8, length - length / 8);
line.erase (static_cast <size_t> (pos));
} }
// "length" / 4 precent of time swap character // "length" / 4 precent of time swap character
if (rg.chance (percentile / 2)) { if (rg.chance (percentile / 2)) {
size_t pos = static_cast <size_t> (rg.get (length / 8, 3 * length / 8)); // choose random position in string auto pos = static_cast <size_t> (rg (length / 8, 3 * length / 8)); // choose random position in string
cr::swap (line[pos], line[pos + 1]); cr::swap (line[pos], line[pos + 1]);
} }
} }
@ -86,7 +87,7 @@ void BotChatManager::addChatErrors (String &line) {
bool BotChatManager::checkKeywords (StringRef line, String &reply) { bool BotChatManager::checkKeywords (StringRef line, String &reply) {
// this function checks is string contain keyword, and generates reply to it // this function checks is string contain keyword, and generates reply to it
if (!cv_chat.bool_ () || line.empty ()) { if (!cv_chat || line.empty ()) {
return false; return false;
} }
@ -135,7 +136,7 @@ bool BotChatManager::checkKeywords (StringRef line, String &reply) {
void Bot::prepareChatMessage (StringRef message) { void Bot::prepareChatMessage (StringRef message) {
// this function parses messages from the botchat, replaces keywords and converts names into a more human style // this function parses messages from the botchat, replaces keywords and converts names into a more human style
if (!cv_chat.bool_ () || message.empty ()) { if (!cv_chat || message.empty ()) {
return; return;
} }
m_chatBuffer = message; m_chatBuffer = message;
@ -306,10 +307,10 @@ bool Bot::isReplyingToChat () {
if (m_sayTextBuffer.entityIndex != -1 && !m_sayTextBuffer.sayText.empty ()) { if (m_sayTextBuffer.entityIndex != -1 && !m_sayTextBuffer.sayText.empty ()) {
// check is time to chat is good // check is time to chat is good
if (m_sayTextBuffer.timeNextChat < game.time () + rg.get (m_sayTextBuffer.chatDelay / 2, m_sayTextBuffer.chatDelay)) { if (m_sayTextBuffer.timeNextChat < game.time () + rg (m_sayTextBuffer.chatDelay / 2, m_sayTextBuffer.chatDelay)) {
String replyText; String replyText;
if (rg.chance (m_sayTextBuffer.chatProbability + rg.get (40, 70)) && checkChatKeywords (replyText)) { if (rg.chance (m_sayTextBuffer.chatProbability + rg (40, 70)) && checkChatKeywords (replyText)) {
prepareChatMessage (replyText); prepareChatMessage (replyText);
pushMsgQueue (BotMsg::Say); pushMsgQueue (BotMsg::Say);
@ -329,14 +330,14 @@ bool Bot::isReplyingToChat () {
void Bot::checkForChat () { void Bot::checkForChat () {
// say a text every now and then // say a text every now and then
if (m_isAlive || !cv_chat.bool_ () || game.is (GameFlags::CSDM)) { if (m_isAlive || !cv_chat || game.is (GameFlags::CSDM)) {
return; return;
} }
// bot chatting turned on? // bot chatting turned on?
if (rg.chance (cv_chat_percent.int_ ()) if (rg.chance (cv_chat_percent.as <int> ())
&& m_lastChatTime + rg.get (6.0f, 10.0f) < game.time () && m_lastChatTime + rg (6.0f, 10.0f) < game.time ()
&& bots.getLastChatTimestamp () + rg.get (2.5f, 5.0f) < game.time () && bots.getLastChatTimestamp () + rg (2.5f, 5.0f) < game.time ()
&& !isReplyingToChat ()) { && !isReplyingToChat ()) {
if (conf.hasChatBank (Chat::Dead)) { if (conf.hasChatBank (Chat::Dead)) {
@ -364,7 +365,7 @@ void Bot::checkForChat () {
} }
// clear the used line buffer every now and then // clear the used line buffer every now and then
if (static_cast <int> (m_sayTextBuffer.lastUsedSentences.length ()) > rg.get (4, 6)) { if (static_cast <int> (m_sayTextBuffer.lastUsedSentences.length ()) > rg (4, 6)) {
m_sayTextBuffer.lastUsedSentences.clear (); m_sayTextBuffer.lastUsedSentences.clear ();
} }
} }
@ -373,7 +374,7 @@ void Bot::checkForChat () {
void Bot::sendToChat (StringRef message, bool teamOnly) { void Bot::sendToChat (StringRef message, bool teamOnly) {
// this function prints saytext message to all players // this function prints saytext message to all players
if (message.empty () || !cv_chat.bool_ ()) { if (message.empty () || !cv_chat) {
return; return;
} }
issueCommand ("%s \"%s\"", teamOnly ? "say_team" : "say", message); issueCommand ("%s \"%s\"", teamOnly ? "say_team" : "say", message);

View file

@ -58,7 +58,7 @@ int Bot::numEnemiesNear (const Vector &origin, const float radius) {
} }
bool Bot::isEnemyHidden (edict_t *enemy) { bool Bot::isEnemyHidden (edict_t *enemy) {
if (!cv_check_enemy_rendering.bool_ () || game.isNullEntity (enemy)) { if (!cv_check_enemy_rendering || game.isNullEntity (enemy)) {
return false; return false;
} }
const auto &v = enemy->v; const auto &v = enemy->v;
@ -100,7 +100,7 @@ bool Bot::isEnemyHidden (edict_t *enemy) {
} }
bool Bot::isEnemyInvincible (edict_t *enemy) { bool Bot::isEnemyInvincible (edict_t *enemy) {
if (!cv_check_enemy_invincibility.bool_ () || game.isNullEntity (enemy)) { if (!cv_check_enemy_invincibility || game.isNullEntity (enemy)) {
return false; return false;
} }
const auto &v = enemy->v; const auto &v = enemy->v;
@ -217,7 +217,7 @@ bool Bot::checkBodyParts (edict_t *target) {
bool Bot::seesEnemy (edict_t *player) { bool Bot::seesEnemy (edict_t *player) {
auto isBehindSmokeClouds = [&] (const Vector &pos) { auto isBehindSmokeClouds = [&] (const Vector &pos) {
if (cv_smoke_grenade_checks.int_ () == 2) { if (cv_smoke_grenade_checks.as <int> () == 2) {
return bots.isLineBlockedBySmoke (getEyesPos (), pos); return bots.isLineBlockedBySmoke (getEyesPos (), pos);
} }
return false; return false;
@ -228,7 +228,7 @@ bool Bot::seesEnemy (edict_t *player) {
} }
bool ignoreFieldOfView = false; bool ignoreFieldOfView = false;
if (cv_whose_your_daddy.bool_ () && util.isPlayer (pev->dmg_inflictor) && game.getTeam (pev->dmg_inflictor) != m_team) { if (cv_whose_your_daddy && util.isPlayer (pev->dmg_inflictor) && game.getTeam (pev->dmg_inflictor) != m_team) {
ignoreFieldOfView = true; ignoreFieldOfView = true;
} }
@ -257,7 +257,7 @@ bool Bot::lookupEnemies () {
// this function tries to find the best suitable enemy for the bot // this function tries to find the best suitable enemy for the bot
// do not search for enemies while we're blinded, or shooting disabled by user // do not search for enemies while we're blinded, or shooting disabled by user
if (m_enemyIgnoreTimer > game.time () || m_blindTime > game.time () || cv_ignore_enemies.bool_ ()) { if (m_enemyIgnoreTimer > game.time () || m_blindTime > game.time () || cv_ignore_enemies) {
return false; return false;
} }
edict_t *player, *newEnemy = nullptr; edict_t *player, *newEnemy = nullptr;
@ -270,10 +270,12 @@ bool Bot::lookupEnemies () {
else if (game.isNullEntity (m_enemy) && m_seeEnemyTime + 4.0f > game.time () && util.isAlive (m_lastEnemy)) { else if (game.isNullEntity (m_enemy) && m_seeEnemyTime + 4.0f > game.time () && util.isAlive (m_lastEnemy)) {
m_states |= Sense::SuspectEnemy; m_states |= Sense::SuspectEnemy;
// check if last enemy can be penetrated const bool denyLastEnemy = pev->velocity.lengthSq2d () > 0.0f
const auto penetratePower = conf.findWeaponById (m_currentWeapon).penetratePower * 4; && pev->origin.distanceSq2d (m_lastEnemyOrigin) < cr::sqrf (256.0f)
&& m_shootTime + 1.5f > game.time ();
if (isPenetrableObstacle1 (m_lastEnemyOrigin, penetratePower)) { if (!(m_aimFlags & (AimFlags::Enemy | AimFlags::PredictPath | AimFlags::Danger))
&& !denyLastEnemy && seesEntity (m_lastEnemyOrigin, true)) {
m_aimFlags |= AimFlags::LastEnemy; m_aimFlags |= AimFlags::LastEnemy;
} }
} }
@ -298,14 +300,14 @@ bool Bot::lookupEnemies () {
auto set = nullptr; auto set = nullptr;
// setup potential visibility set from engine // setup potential visibility set from engine
if (cv_use_engine_pvs_check.bool_ ()) { if (cv_use_engine_pvs_check) {
game.getVisibilitySet (this, true); game.getVisibilitySet (this, true);
} }
// ignore shielded enemies, while we have real one // ignore shielded enemies, while we have real one
edict_t *shieldEnemy = nullptr; edict_t *shieldEnemy = nullptr;
if (cv_attack_monsters.bool_ ()) { if (cv_attack_monsters) {
// search the world for monsters... // search the world for monsters...
for (const auto &interesting : bots.getInterestingEntities ()) { for (const auto &interesting : bots.getInterestingEntities ()) {
if (!util.isMonster (interesting)) { if (!util.isMonster (interesting)) {
@ -313,7 +315,7 @@ bool Bot::lookupEnemies () {
} }
// check the engine PVS // check the engine PVS
if (cv_use_engine_pvs_check.bool_ () && !game.checkVisibility (interesting, set)) { if (cv_use_engine_pvs_check && !game.checkVisibility (interesting, set)) {
continue; continue;
} }
@ -343,12 +345,12 @@ bool Bot::lookupEnemies () {
player = client.ent; player = client.ent;
// check the engine PVS // check the engine PVS
if (cv_use_engine_pvs_check.bool_ () && !game.checkVisibility (player, set)) { if (cv_use_engine_pvs_check && !game.checkVisibility (player, set)) {
continue; continue;
} }
// extra skill player can see through smoke... if being attacked // extra skill player can see through smoke... if being attacked
if (cv_whose_your_daddy.bool_ () && (player->v.button & (IN_ATTACK | IN_ATTACK2)) && m_viewDistance < m_maxViewDistance) { if (cv_whose_your_daddy && (player->v.button & (IN_ATTACK | IN_ATTACK2)) && m_viewDistance < m_maxViewDistance) {
nearestDistanceSq = cr::sqrf (m_maxViewDistance); nearestDistanceSq = cr::sqrf (m_maxViewDistance);
} }
@ -378,7 +380,7 @@ bool Bot::lookupEnemies () {
} }
} }
if (newEnemy != nullptr && (util.isPlayer (newEnemy) || (cv_attack_monsters.bool_ () && util.isMonster (newEnemy)))) { if (newEnemy != nullptr && (util.isPlayer (newEnemy) || (cv_attack_monsters && util.isMonster (newEnemy)))) {
bots.setCanPause (true); bots.setCanPause (true);
m_aimFlags |= AimFlags::Enemy; m_aimFlags |= AimFlags::Enemy;
@ -401,7 +403,7 @@ bool Bot::lookupEnemies () {
} }
m_targetEntity = nullptr; // stop following when we see an enemy... m_targetEntity = nullptr; // stop following when we see an enemy...
if (cv_whose_your_daddy.bool_ ()) { if (cv_whose_your_daddy) {
m_enemySurpriseTime = m_actualReactionTime * 0.5f; m_enemySurpriseTime = m_actualReactionTime * 0.5f;
} }
else { else {
@ -475,7 +477,7 @@ bool Bot::lookupEnemies () {
} }
// if no enemy visible check if last one shoot able through wall // if no enemy visible check if last one shoot able through wall
if (cv_shoots_thru_walls.bool_ () if (cv_shoots_thru_walls
&& rg.chance (conf.getDifficultyTweaks (m_difficulty)->seenThruPct) && rg.chance (conf.getDifficultyTweaks (m_difficulty)->seenThruPct)
&& isPenetrableObstacle (newEnemy->v.origin)) { && isPenetrableObstacle (newEnemy->v.origin)) {
@ -528,12 +530,12 @@ Vector Bot::getBodyOffsetError (float distance) {
const float hitError = distance / (cr::clamp (static_cast <float> (m_difficulty), 1.0f, 4.0f) * 1280.0f); const float hitError = distance / (cr::clamp (static_cast <float> (m_difficulty), 1.0f, 4.0f) * 1280.0f);
const auto &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins; const auto &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins;
m_aimLastError = Vector (rg.get (mins.x * hitError, maxs.x * hitError), rg.get (mins.y * hitError, maxs.y * hitError), rg.get (mins.z * hitError * 0.5f, maxs.z * hitError * 0.5f)); m_aimLastError = Vector (rg (mins.x * hitError, maxs.x * hitError), rg (mins.y * hitError, maxs.y * hitError), rg (mins.z * hitError * 0.5f, maxs.z * hitError * 0.5f));
const auto &aimError = conf.getDifficultyTweaks (m_difficulty) ->aimError; const auto &aimError = conf.getDifficultyTweaks (m_difficulty) ->aimError;
m_aimLastError += Vector (rg.get (-aimError.x, aimError.x), rg.get (-aimError.y, aimError.y), rg.get (-aimError.z, aimError.z)); m_aimLastError += Vector (rg (-aimError.x, aimError.x), rg (-aimError.y, aimError.y), rg (-aimError.z, aimError.z));
m_aimErrorTime = game.time () + rg.get (0.4f, 0.8f); m_aimErrorTime = game.time () + rg (0.4f, 0.8f);
} }
return m_aimLastError; return m_aimLastError;
} }
@ -582,6 +584,9 @@ Vector Bot::getEnemyBodyOffset () {
if (distance > kSprayDistance && (isRecoilHigh () || usesShotgun ())) { if (distance > kSprayDistance && (isRecoilHigh () || usesShotgun ())) {
headshotPct = 0; headshotPct = 0;
} }
else if (distance <= kSprayDistance && isRecoilHigh ()) {
headshotPct = 0;
}
// now check is our skill match to aim at head, else aim at enemy body // now check is our skill match to aim at head, else aim at enemy body
if (m_enemyBodyPartSet == m_enemy || rg.chance (headshotPct)) { if (m_enemyBodyPartSet == m_enemy || rg.chance (headshotPct)) {
@ -665,7 +670,7 @@ Vector Bot::getCustomHeight (float distance) {
bool Bot::isFriendInLineOfFire (float distance) { bool Bot::isFriendInLineOfFire (float distance) {
// bot can't hurt teammates, if friendly fire is not enabled... // bot can't hurt teammates, if friendly fire is not enabled...
if (!mp_friendlyfire.bool_ () || game.is (GameFlags::CSDM)) { if (!mp_friendlyfire || game.is (GameFlags::CSDM)) {
return false; return false;
} }
@ -710,7 +715,7 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
if (penetratePower == 0) { if (penetratePower == 0) {
return false; return false;
} }
const auto method = cv_shoots_thru_walls.int_ (); const auto method = cv_shoots_thru_walls.as <int> ();
// switch methods // switch methods
switch (method) { switch (method) {
@ -858,13 +863,13 @@ bool Bot::needToPauseFiring (float distance) {
const float yPunch = cr::sqrf (cr::deg2rad (pev->punchangle.y)); const float yPunch = cr::sqrf (cr::deg2rad (pev->punchangle.y));
const float tolerance = (100.0f - static_cast <float> (m_difficulty) * 25.0f) / 99.0f; const float tolerance = (100.0f - static_cast <float> (m_difficulty) * 25.0f) / 99.0f;
const float baseTime = distance > kSprayDistance ? 0.65f : 0.48f; const float baseTime = distance > kSprayDistance ? 0.55f : 0.38f;
const float maxRecoil = static_cast <float> (conf.getDifficultyTweaks (m_difficulty)->maxRecoil); const float maxRecoil = static_cast <float> (conf.getDifficultyTweaks (m_difficulty)->maxRecoil);
// check if we need to compensate recoil // check if we need to compensate recoil
if (cr::tanf (cr::sqrtf (cr::abs (xPunch) + cr::abs (yPunch))) * distance > offset + maxRecoil + tolerance) { if (cr::tanf (cr::sqrtf (cr::abs (xPunch) + cr::abs (yPunch))) * distance > offset + maxRecoil + tolerance) {
if (m_firePause < game.time ()) { if (m_firePause < game.time ()) {
m_firePause = game.time () + rg.get (baseTime, baseTime + maxRecoil * 0.01f * tolerance) - m_frameInterval; m_firePause = game.time () + rg (baseTime, baseTime + maxRecoil * 0.01f * tolerance) - m_frameInterval;
} }
return true; return true;
} }
@ -1024,7 +1029,7 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
const int offset = cr::abs <int> (m_difficulty * 25 / 20 - 5); const int offset = cr::abs <int> (m_difficulty * 25 / 20 - 5);
m_shootTime = game.time () + 0.1f + rg.get (kMinFireDelay[offset], kMaxFireDelay[offset]); m_shootTime = game.time () + 0.1f + rg (kMinFireDelay[offset], kMaxFireDelay[offset]);
m_zoomCheckTime = game.time (); m_zoomCheckTime = game.time ();
} }
} }
@ -1059,7 +1064,7 @@ void Bot::fireWeapons () {
} }
// use knife if near and good difficulty (l33t dude!) // use knife if near and good difficulty (l33t dude!)
if (cv_stab_close_enemies.bool_ () && m_difficulty >= Difficulty::Normal if (cv_stab_close_enemies && m_difficulty >= Difficulty::Normal
&& m_healthValue > 80.0f && m_healthValue > 80.0f
&& !game.isNullEntity (m_enemy) && !game.isNullEntity (m_enemy)
&& m_healthValue >= m_enemy->v.health && m_healthValue >= m_enemy->v.health
@ -1255,13 +1260,14 @@ void Bot::attackMovement () {
m_moveSpeed = pev->maxspeed; m_moveSpeed = pev->maxspeed;
} }
} }
const bool isFullView = !!(m_enemyParts & (Visibility::Head | Visibility::Body));
if (m_lastFightStyleCheck + 3.0f < game.time ()) { if (m_lastFightStyleCheck + 3.0f < game.time ()) {
if (usesSniper ()) { if (usesSniper ()) {
m_fightStyle = Fight::Stay; m_fightStyle = Fight::Stay;
} }
else if (usesRifle () || usesSubmachine () || usesHeavy ()) { else if (usesRifle () || usesSubmachine () || usesHeavy ()) {
const int rand = rg.get (1, 100); const int rand = rg (1, 100);
if (distance < 768.0f) { if (distance < 768.0f) {
m_fightStyle = Fight::Strafe; m_fightStyle = Fight::Strafe;
@ -1297,7 +1303,7 @@ void Bot::attackMovement () {
} }
// do not try to strafe while ducking // do not try to strafe while ducking
if (isDucking () || isInNarrowPlace ()) { if (isDucking () || isInNarrowPlace () || !isFullView) {
m_fightStyle = Fight::Stay; m_fightStyle = Fight::Stay;
} }
const auto pistolStrafeDistance = game.is (GameFlags::CSDM) ? kSprayDistanceX2 * 3.0f : kSprayDistanceX2; const auto pistolStrafeDistance = game.is (GameFlags::CSDM) ? kSprayDistanceX2 * 3.0f : kSprayDistanceX2;
@ -1320,12 +1326,12 @@ void Bot::attackMovement () {
} }
if (m_fightStyle == Fight::Strafe) { if (m_fightStyle == Fight::Strafe) {
auto swapStrafeCombatDir = [&] () { auto swapDodgeDirection = [&] () {
m_combatStrafeDir = (m_combatStrafeDir == Dodge::Left ? Dodge::Right : Dodge::Left); m_dodgeStrafeDir = (m_dodgeStrafeDir == Dodge::Left ? Dodge::Right : Dodge::Left);
}; };
auto strafeUpdateTime = [] () { auto strafeUpdateTime = [] () {
return game.time () + rg.get (0.3f, 1.0f); return game.time () + rg (0.3f, 1.0f);
}; };
// to start strafing, we have to first figure out if the target is on the left side or right side // to start strafing, we have to first figure out if the target is on the left side or right side
@ -1334,14 +1340,14 @@ void Bot::attackMovement () {
const auto &rightSide = m_enemy->v.v_angle.right ().normalize2d_apx (); const auto &rightSide = m_enemy->v.v_angle.right ().normalize2d_apx ();
if ((dirToPoint | rightSide) < 0.0f) { if ((dirToPoint | rightSide) < 0.0f) {
m_combatStrafeDir = Dodge::Right; m_dodgeStrafeDir = Dodge::Right;
} }
else { else {
m_combatStrafeDir = Dodge::Left; m_dodgeStrafeDir = Dodge::Left;
} }
if (rg.chance (30)) { if (rg.chance (30)) {
swapStrafeCombatDir (); swapDodgeDirection ();
} }
m_strafeSetTime = strafeUpdateTime (); m_strafeSetTime = strafeUpdateTime ();
} }
@ -1349,12 +1355,12 @@ void Bot::attackMovement () {
const bool wallOnRight = checkWallOnRight (); const bool wallOnRight = checkWallOnRight ();
const bool wallOnLeft = checkWallOnLeft (); const bool wallOnLeft = checkWallOnLeft ();
if (m_combatStrafeDir == Dodge::Left) { if (m_dodgeStrafeDir == Dodge::Left) {
if (!wallOnLeft) { if (!wallOnLeft) {
m_strafeSpeed = -pev->maxspeed; m_strafeSpeed = -pev->maxspeed;
} }
else if (!wallOnRight) { else if (!wallOnRight) {
swapStrafeCombatDir (); swapDodgeDirection ();
m_strafeSetTime = strafeUpdateTime (); m_strafeSetTime = strafeUpdateTime ();
m_strafeSpeed = pev->maxspeed; m_strafeSpeed = pev->maxspeed;
@ -1369,7 +1375,7 @@ void Bot::attackMovement () {
m_strafeSpeed = pev->maxspeed; m_strafeSpeed = pev->maxspeed;
} }
else if (!wallOnLeft) { else if (!wallOnLeft) {
swapStrafeCombatDir (); swapDodgeDirection ();
m_strafeSetTime = strafeUpdateTime (); m_strafeSetTime = strafeUpdateTime ();
m_strafeSpeed = -pev->maxspeed; m_strafeSpeed = -pev->maxspeed;
@ -1388,7 +1394,7 @@ void Bot::attackMovement () {
if (m_difficulty >= Difficulty::Normal if (m_difficulty >= Difficulty::Normal
&& (m_jumpTime + 5.0f < game.time () && (m_jumpTime + 5.0f < game.time ()
&& isOnFloor () && isOnFloor ()
&& rg.get (0, 1000) < (m_isReloading ? 8 : 2) && rg (0, 1000) < (m_isReloading ? 8 : 2)
&& pev->velocity.length2d () > 150.0f) && !usesSniper ()) { && pev->velocity.length2d () > 150.0f) && !usesSniper ()) {
pev->button |= IN_JUMP; pev->button |= IN_JUMP;
@ -1401,7 +1407,7 @@ void Bot::attackMovement () {
m_duckTime = game.time () + m_frameInterval * 3.0f; m_duckTime = game.time () + m_frameInterval * 3.0f;
} }
else if ((distance > kSprayDistanceX2 && hasPrimaryWeapon ()) else if ((distance > kSprayDistanceX2 && hasPrimaryWeapon ())
&& (m_enemyParts & (Visibility::Head | Visibility::Body)) && isFullView
&& getCurrentTaskId () != Task::SeekCover && getCurrentTaskId () != Task::SeekCover
&& getCurrentTaskId () != Task::Hunt) { && getCurrentTaskId () != Task::Hunt) {
@ -1418,7 +1424,7 @@ void Bot::attackMovement () {
if (m_difficulty >= Difficulty::Normal && isOnFloor () && m_duckTime < game.time ()) { if (m_difficulty >= Difficulty::Normal && isOnFloor () && m_duckTime < game.time ()) {
if (distance < kSprayDistanceX2) { if (distance < kSprayDistanceX2) {
if (rg.get (0, 1000) < rg.get (5, 10) && pev->velocity.length2d () > 150.0f && isInViewCone (m_enemy->v.origin)) { if (rg (0, 1000) < rg (5, 10) && pev->velocity.length2d () > 150.0f && isInViewCone (m_enemy->v.origin)) {
pev->button |= IN_JUMP; pev->button |= IN_JUMP;
} }
} }
@ -1585,7 +1591,7 @@ bool Bot::hasAnyWeapons () {
} }
bool Bot::isKnifeMode () { bool Bot::isKnifeMode () {
return cv_jasonmode.bool_ () || (usesKnife () && !hasAnyWeapons ()) || m_isCreature; return cv_jasonmode || (usesKnife () && !hasAnyWeapons ()) || m_isCreature;
} }
bool Bot::isGrenadeWar () { bool Bot::isGrenadeWar () {
@ -1597,7 +1603,7 @@ bool Bot::isGrenadeWar () {
} }
// if we're forced to via cvar // if we're forced to via cvar
if (cv_grenadier_mode.bool_ ()) { if (cv_grenadier_mode) {
return true; return true;
} }
return game.mapIs (MapFlags::GrenadeWar); // in case map was flagged return game.mapIs (MapFlags::GrenadeWar); // in case map was flagged
@ -1717,7 +1723,7 @@ void Bot::decideFollowUser () {
void Bot::updateTeamCommands () { void Bot::updateTeamCommands () {
// prevent spamming // prevent spamming
if (m_timeTeamOrder > game.time () + 2.0f || game.is (GameFlags::FreeForAll) || !cv_radio_mode.int_ ()) { if (m_timeTeamOrder > game.time () + 2.0f || game.is (GameFlags::FreeForAll) || !cv_radio_mode.as <int> ()) {
return; return;
} }
@ -1739,20 +1745,20 @@ void Bot::updateTeamCommands () {
// has teammates? // has teammates?
if (memberNear) { if (memberNear) {
if (m_personality == Personality::Rusher && cv_radio_mode.int_ () == 2) { if (m_personality == Personality::Rusher && cv_radio_mode.as <int> () == 2) {
pushRadioMessage (Radio::StormTheFront); pushRadioMessage (Radio::StormTheFront);
} }
else if (m_personality != Personality::Rusher && cv_radio_mode.int_ () == 2) { else if (m_personality != Personality::Rusher && cv_radio_mode.as <int> () == 2) {
pushRadioMessage (Radio::TeamFallback); pushRadioMessage (Radio::TeamFallback);
} }
} }
else if (memberExists && cv_radio_mode.int_ () == 1) { else if (memberExists && cv_radio_mode.as <int> () == 1) {
pushRadioMessage (Radio::TakingFireNeedAssistance); pushRadioMessage (Radio::TakingFireNeedAssistance);
} }
else if (memberExists && cv_radio_mode.int_ () == 2) { else if (memberExists && cv_radio_mode.as <int> () == 2) {
pushChatterMessage (Chatter::ScaredEmotion); pushChatterMessage (Chatter::ScaredEmotion);
} }
m_timeTeamOrder = game.time () + rg.get (15.0f, 30.0f); m_timeTeamOrder = game.time () + rg (15.0f, 30.0f);
} }
bool Bot::isGroupOfEnemies (const Vector &location, int numEnemies, float radius) { bool Bot::isGroupOfEnemies (const Vector &location, int numEnemies, float radius) {
@ -1871,7 +1877,7 @@ Vector Bot::calcToss (const Vector &start, const Vector &stop) {
// returns null vector if toss is not feasible. // returns null vector if toss is not feasible.
TraceResult tr {}; TraceResult tr {};
const float gravity = sv_gravity.float_ () * 0.55f; const float gravity = sv_gravity.as <float> () * 0.55f;
// prevent div by zero in some strange situations // prevent div by zero in some strange situations
if (cr::fzero (gravity)) { if (cr::fzero (gravity)) {
@ -1931,7 +1937,7 @@ Vector Bot::calcThrow (const Vector &start, const Vector &stop) {
Vector velocity = stop - start; Vector velocity = stop - start;
TraceResult tr {}; TraceResult tr {};
const float gravity = sv_gravity.float_ () * 0.55f; const float gravity = sv_gravity.as <float> () * 0.55f;
// prevent div by zero in some strange situations // prevent div by zero in some strange situations
if (cr::fzero (gravity)) { if (cr::fzero (gravity)) {
@ -2010,7 +2016,7 @@ void Bot::checkGrenadesThrow () {
? m_lastEnemyOrigin.empty () ? m_lastEnemyOrigin.empty ()
: (preventibleTasks : (preventibleTasks
|| isInNarrowPlace () || isInNarrowPlace ()
|| cv_ignore_enemies.bool_ () || cv_ignore_enemies
|| m_isUsingGrenade || m_isUsingGrenade
|| m_isReloading || m_isReloading
|| (isKnifeMode () && !bots.isBombPlanted ()) || (isKnifeMode () && !bots.isBombPlanted ())
@ -2094,7 +2100,7 @@ void Bot::checkGrenadesThrow () {
// care about different grenades // care about different grenades
switch (grenadeToThrow) { switch (grenadeToThrow) {
case Weapon::Explosive: case Weapon::Explosive:
if (mp_friendlyfire.bool_ () && numFriendsNear (m_lastEnemy->v.origin, 256.0f) > 0) { if (mp_friendlyfire && numFriendsNear (m_lastEnemy->v.origin, 256.0f) > 0) {
allowThrowing = false; allowThrowing = false;
} }
else { else {
@ -2245,7 +2251,7 @@ bool Bot::isEnemyNoticeable (float range) {
} }
if (m_enemyParts & Visibility::Other) { if (m_enemyParts & Visibility::Other) {
coverRatio += rg.get (10.0f, 25.0f); coverRatio += rg (10.0f, 25.0f);
} }
constexpr float kCloseRange = 300.0f; constexpr float kCloseRange = 300.0f;
constexpr float kFarRange = 1000.0f; constexpr float kFarRange = 1000.0f;
@ -2311,7 +2317,7 @@ bool Bot::isEnemyNoticeable (float range) {
} }
noticeChance = cr::max (0.1f, noticeChance * cr::abs (m_agressionLevel - m_fearLevel)); noticeChance = cr::max (0.1f, noticeChance * cr::abs (m_agressionLevel - m_fearLevel));
return rg.get (0.0f, 100.0f) < noticeChance; return rg (0.0f, 100.0f) < noticeChance;
} }
int Bot::getAmmo () { int Bot::getAmmo () {

View file

@ -65,7 +65,7 @@ void BotConfig::loadMainConfig (bool isFirstLoad) {
auto keyval = line.split (" "); auto keyval = line.split (" ");
if (keyval.length () > 1) { if (keyval.length () > 1) {
auto ignore = String (cv_ignore_cvars_on_changelevel.str ()).split (","); auto ignore = String (cv_ignore_cvars_on_changelevel.as <StringRef> ()).split (",");
auto key = keyval[0].trim ().chars (); auto key = keyval[0].trim ().chars ();
auto cvar = engfuncs.pfnCVarGetPointer (key); auto cvar = engfuncs.pfnCVarGetPointer (key);
@ -76,7 +76,7 @@ void BotConfig::loadMainConfig (bool isFirstLoad) {
if (needsToIgnoreVar (ignore, key) && !strings.matches (value, cvar->string)) { if (needsToIgnoreVar (ignore, key) && !strings.matches (value, cvar->string)) {
// preserve quota number if it's zero // preserve quota number if it's zero
if (cv_quota.name () == cvar->name && cv_quota.int_ () <= 0) { if (cv_quota.name () == cvar->name && cv_quota.as <int> () <= 0) {
engfuncs.pfnCvar_DirectSet (cvar, value); engfuncs.pfnCvar_DirectSet (cvar, value);
continue; continue;
} }
@ -101,13 +101,13 @@ void BotConfig::loadMainConfig (bool isFirstLoad) {
} }
// android is a bit hard to play, lower the difficulty by default // android is a bit hard to play, lower the difficulty by default
if (plat.android && cv_difficulty.int_ () > 3) { if (plat.android && cv_difficulty.as <int> () > 3) {
cv_difficulty.set (3); cv_difficulty.set (3);
} }
// bind the correct menu key for bot menu... // bind the correct menu key for bot menu...
if (!game.isDedicated ()) { if (!game.isDedicated ()) {
auto val = cv_bind_menu_key.str (); auto val = cv_bind_menu_key.as <StringRef> ();
if (!val.empty ()) { if (!val.empty ()) {
game.serverCommand ("bind \"%s\" \"yb menu\"", val); game.serverCommand ("bind \"%s\" \"yb menu\"", val);
@ -115,7 +115,7 @@ void BotConfig::loadMainConfig (bool isFirstLoad) {
} }
// disable logger if requested // disable logger if requested
logger.disableLogWrite (cv_logger_disable_logfile.bool_ ()); logger.disableLogWrite (cv_logger_disable_logfile);
} }
void BotConfig::loadNamesConfig () { void BotConfig::loadNamesConfig () {
@ -161,10 +161,10 @@ void BotConfig::loadWeaponsConfig () {
for (size_t i = 0; i < data.length (); ++i) { for (size_t i = 0; i < data.length (); ++i) {
if (as) { if (as) {
weapons[i].teamAS = data[i].int_ (); weapons[i].teamAS = data[i].as <int> ();
} }
else { else {
weapons[i].teamStandard = data[i].int_ (); weapons[i].teamStandard = data[i].as <int> ();
} }
} }
}; };
@ -176,7 +176,7 @@ void BotConfig::loadWeaponsConfig () {
} }
for (size_t i = 0; i < to.length (); ++i) { for (size_t i = 0; i < to.length (); ++i) {
to[i] = data[i].int_ (); to[i] = data[i].as <int> ();
} }
}; };
String line; String line;
@ -235,7 +235,7 @@ void BotConfig::loadChatterConfig () {
MemFile file; MemFile file;
// chatter initialization // chatter initialization
if (game.is (GameFlags::HasBotVoice) && cv_radio_mode.int_ () == 2 && openConfig ("chatter", "Couldn't open chatter system configuration", &file)) { if (game.is (GameFlags::HasBotVoice) && cv_radio_mode.as <int> () == 2 && openConfig ("chatter", "Couldn't open chatter system configuration", &file)) {
m_chatter.clear (); m_chatter.clear ();
struct EventMap { struct EventMap {
@ -521,7 +521,7 @@ void BotConfig::loadLanguageConfig () {
} }
file.close (); file.close ();
} }
else if (cv_language.str () != "en") { else if (cv_language.as <StringRef> () != "en") {
logger.error ("Couldn't load language configuration"); logger.error ("Couldn't load language configuration");
} }
} }
@ -592,15 +592,15 @@ void BotConfig::loadDifficultyConfig () {
} }
auto diff = &m_difficulty[level]; auto diff = &m_difficulty[level];
diff->reaction[0] = values[0].float_ (); diff->reaction[0] = values[0].as <float> ();
diff->reaction[1] = values[1].float_ (); diff->reaction[1] = values[1].as <float> ();
diff->headshotPct = values[2].int_ (); diff->headshotPct = values[2].as <int> ();
diff->seenThruPct = values[3].int_ (); diff->seenThruPct = values[3].as <int> ();
diff->hearThruPct = values[4].int_ (); diff->hearThruPct = values[4].as <int> ();
diff->maxRecoil = values[5].int_ (); diff->maxRecoil = values[5].as <int> ();
diff->aimError.x = values[6].float_ (); diff->aimError.x = values[6].as <float> ();
diff->aimError.y = values[7].float_ (); diff->aimError.y = values[7].as <float> ();
diff->aimError.z = values[8].float_ (); diff->aimError.z = values[8].as <float> ();
}; };
// difficulty initialization // difficulty initialization
@ -882,10 +882,10 @@ bool BotConfig::openConfig (StringRef fileName, StringRef errorIfNotExists, MemF
auto configDir = strings.joinPath (bstor.getRunningPathVFS (), folders.config); auto configDir = strings.joinPath (bstor.getRunningPathVFS (), folders.config);
if (languageDependant) { if (languageDependant) {
if (fileName.startsWith ("lang") && cv_language.str () == "en") { if (fileName.startsWith ("lang") && cv_language.as <StringRef> () == "en") {
return false; return false;
} }
auto langConfig = strings.joinPath (configDir, folders.lang, strings.format ("%s_%s.%s", cv_language.str (), fileName, kConfigExtension)); auto langConfig = strings.joinPath (configDir, folders.lang, strings.format ("%s_%s.%s", cv_language.as <StringRef> (), fileName, kConfigExtension));
// check is file is exists for this language // check is file is exists for this language
if (!outFile->open (langConfig)) { if (!outFile->open (langConfig)) {

View file

@ -25,19 +25,19 @@ int BotControl::cmdAddBot () {
m_args.resize (max); m_args.resize (max);
// if team is specified, modify args to set team // if team is specified, modify args to set team
if (strValue (alias).endsWith ("_ct")) { if (arg <StringRef> (alias).endsWith ("_ct")) {
m_args.set (team, "2"); m_args.set (team, "2");
} }
else if (strValue (alias).endsWith ("_t")) { else if (arg <StringRef> (alias).endsWith ("_t")) {
m_args.set (team, "1"); m_args.set (team, "1");
} }
// if high-skilled bot is requested set personality to rusher and max-out difficulty // if high-skilled bot is requested set personality to rusher and max-out difficulty
if (strValue (alias).contains ("addhs")) { if (arg <StringRef> (alias).contains ("addhs")) {
m_args.set (difficulty, "4"); m_args.set (difficulty, "4");
m_args.set (personality, "1"); m_args.set (personality, "1");
} }
bots.addbot (strValue (name), strValue (difficulty), strValue (personality), strValue (team), strValue (model), true); bots.addbot (arg <StringRef> (name), arg <StringRef> (difficulty), arg <StringRef> (personality), arg <StringRef> (team), arg <StringRef> (model), true);
return BotCommandResult::Handled; return BotCommandResult::Handled;
} }
@ -46,10 +46,10 @@ int BotControl::cmdKickBot () {
enum args { alias = 1, team }; enum args { alias = 1, team };
// if team is specified, kick from specified tram // if team is specified, kick from specified tram
if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") { if (arg <StringRef> (alias).endsWith ("_ct") || arg <int> (team) == 2 || arg <StringRef> (team) == "ct") {
bots.kickFromTeam (Team::CT); bots.kickFromTeam (Team::CT);
} }
else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") { else if (arg <StringRef> (alias).endsWith ("_t") || arg <int> (team) == 1 || arg <StringRef> (team) == "t") {
bots.kickFromTeam (Team::Terrorist); bots.kickFromTeam (Team::Terrorist);
} }
else { else {
@ -62,13 +62,13 @@ int BotControl::cmdKickBots () {
enum args { alias = 1, instant, team }; enum args { alias = 1, instant, team };
// check if we're need to remove bots instantly // check if we're need to remove bots instantly
const auto kickInstant = strValue (instant) == "instant"; const auto kickInstant = arg <StringRef> (instant) == "instant";
// if team is specified, kick from specified tram // if team is specified, kick from specified tram
if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") { if (arg <StringRef> (alias).endsWith ("_ct") || arg <int> (team) == 2 || arg <StringRef> (team) == "ct") {
bots.kickFromTeam (Team::CT, true); bots.kickFromTeam (Team::CT, true);
} }
else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") { else if (arg <StringRef> (alias).endsWith ("_t") || arg <int> (team) == 1 || arg <StringRef> (team) == "t") {
bots.kickFromTeam (Team::Terrorist, true); bots.kickFromTeam (Team::Terrorist, true);
} }
else { else {
@ -81,13 +81,13 @@ int BotControl::cmdKillBots () {
enum args { alias = 1, team, silent, max }; enum args { alias = 1, team, silent, max };
// do not issue any messages // do not issue any messages
bool silentKill = hasArg (silent) && strValue (silent).startsWith ("si"); bool silentKill = hasArg (silent) && arg <StringRef> (silent).startsWith ("si");
// if team is specified, kick from specified tram // if team is specified, kick from specified tram
if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") { if (arg <StringRef> (alias).endsWith ("_ct") || arg <int> (team) == 2 || arg <StringRef> (team) == "ct") {
bots.killAllBots (Team::CT, silentKill); bots.killAllBots (Team::CT, silentKill);
} }
else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") { else if (arg <StringRef> (alias).endsWith ("_t") || arg <int> (team) == 1 || arg <StringRef> (team) == "t") {
bots.killAllBots (Team::Terrorist, silentKill); bots.killAllBots (Team::Terrorist, silentKill);
} }
else { else {
@ -102,7 +102,10 @@ int BotControl::cmdFill () {
if (!hasArg (team)) { if (!hasArg (team)) {
return BotCommandResult::BadFormat; return BotCommandResult::BadFormat;
} }
bots.serverFill (intValue (team), hasArg (personality) ? intValue (personality) : -1, hasArg (difficulty) ? intValue (difficulty) : -1, hasArg (count) ? intValue (count) - 1 : -1); bots.serverFill (arg <int> (team),
hasArg (personality) ? arg <int> (personality) : -1,
hasArg (difficulty) ? arg <int> (difficulty) : -1,
hasArg (count) ? arg <int> (count) - 1 : -1);
return BotCommandResult::Handled; return BotCommandResult::Handled;
} }
@ -113,7 +116,7 @@ int BotControl::cmdVote () {
if (!hasArg (mapid)) { if (!hasArg (mapid)) {
return BotCommandResult::BadFormat; return BotCommandResult::BadFormat;
} }
const int mapID = intValue (mapid); const int mapID = arg <int> (mapid);
// loop through all players // loop through all players
for (const auto &bot : bots) { for (const auto &bot : bots) {
@ -139,7 +142,7 @@ int BotControl::cmdWeaponMode () {
{ "sniper", 6 }, { "sniper", 6 },
{ "standard", 7 } { "standard", 7 }
}; };
auto mode = strValue (type); auto mode = arg <StringRef> (type);
// check if selected mode exists // check if selected mode exists
if (!modes.exists (mode)) { if (!modes.exists (mode)) {
@ -180,7 +183,7 @@ int BotControl::cmdMenu () {
// reset the current menu // reset the current menu
closeMenu (); closeMenu ();
if (strValue (cmd) == "cmd" && util.isAlive (m_ent)) { if (arg <StringRef> (cmd) == "cmd" && util.isAlive (m_ent)) {
showMenu (Menu::Commands); showMenu (Menu::Commands);
} }
else { else {
@ -199,7 +202,7 @@ int BotControl::cmdList () {
int BotControl::cmdCvars () { int BotControl::cmdCvars () {
enum args { alias = 1, pattern }; enum args { alias = 1, pattern };
auto match = strValue (pattern); auto match = arg <StringRef> (pattern);
// revert all the cvars to their default values // revert all the cvars to their default values
if (match == "defaults") { if (match == "defaults") {
@ -257,7 +260,7 @@ int BotControl::cmdCvars () {
if (isSave && !cfg) { if (isSave && !cfg) {
continue; continue;
} }
auto val = cvar.self->str (); auto val = cvar.self->as <StringRef> ();
// float value ? // float value ?
bool isFloat = !val.empty () && val.find (".") != StringRef::InvalidIndex; bool isFloat = !val.empty () && val.find (".") != StringRef::InvalidIndex;
@ -276,20 +279,20 @@ int BotControl::cmdCvars () {
} }
} }
else { else {
cfg.puts ("// Default: \"%s\"\n", cvar.self->str ()); cfg.puts ("// Default: \"%s\"\n", cvar.self->as <StringRef> ());
} }
cfg.puts ("// \n"); cfg.puts ("// \n");
if (cvar.bounded) { if (cvar.bounded) {
if (isFloat) { if (isFloat) {
cfg.puts ("%s \"%.1f\"\n", cvar.reg.name, cvar.self->float_ ()); cfg.puts ("%s \"%.1f\"\n", cvar.reg.name, cvar.self->as <float> ());
} }
else { else {
cfg.puts ("%s \"%i\"\n", cvar.reg.name, cvar.self->int_ ()); cfg.puts ("%s \"%i\"\n", cvar.reg.name, cvar.self->as <int> ());
} }
} }
else { else {
cfg.puts ("%s \"%s\"\n", cvar.reg.name, cvar.self->str ()); cfg.puts ("%s \"%s\"\n", cvar.reg.name, cvar.self->as <StringRef> ());
} }
cfg.puts ("\n"); cfg.puts ("\n");
} }
@ -327,7 +330,7 @@ int BotControl::cmdExec () {
if (!hasArg (target) || !hasArg (command)) { if (!hasArg (target) || !hasArg (command)) {
return BotCommandResult::BadFormat; return BotCommandResult::BadFormat;
} }
const auto userId = intValue (target); const auto userId = arg <int> (target);
// find our little target // find our little target
auto bot = bots.findBotByIndex (userId); auto bot = bots.findBotByIndex (userId);
@ -337,7 +340,7 @@ int BotControl::cmdExec () {
msg ("Bot with #%d not found or not a bot.", userId); msg ("Bot with #%d not found or not a bot.", userId);
return BotCommandResult::Handled; return BotCommandResult::Handled;
} }
bot->issueCommand (strValue (command).chars ()); bot->issueCommand (arg <StringRef> (command).chars ());
return BotCommandResult::Handled; return BotCommandResult::Handled;
} }
@ -366,7 +369,7 @@ int BotControl::cmdNode () {
}; };
// graph editor supported only with editor // graph editor supported only with editor
if (game.isDedicated () && !graph.hasEditor () && !isAllowedOnDedicatedServer (strValue (cmd))) { if (game.isDedicated () && !graph.hasEditor () && !isAllowedOnDedicatedServer (arg <StringRef> (cmd))) {
msg ("Unable to use graph edit commands without setting graph editor player. Please use \"graph acquire_editor\" to acquire rights for graph editing."); msg ("Unable to use graph edit commands without setting graph editor player. Please use \"graph acquire_editor\" to acquire rights for graph editing.");
return BotCommandResult::Handled; return BotCommandResult::Handled;
} }
@ -426,8 +429,8 @@ int BotControl::cmdNode () {
addGraphCmd ("release_editor", "release_editor [noarguments]", "Releases graph editing rights.", &BotControl::cmdNodeReleaseEditor); addGraphCmd ("release_editor", "release_editor [noarguments]", "Releases graph editing rights.", &BotControl::cmdNodeReleaseEditor);
} }
} }
if (commands.exists (strValue (cmd))) { if (commands.exists (arg <StringRef> (cmd))) {
const auto &item = commands[strValue (cmd)]; const auto &item = commands[arg <StringRef> (cmd)];
// graph have only bad format return status // graph have only bad format return status
int status = (this->*item.handler) (); int status = (this->*item.handler) ();
@ -439,8 +442,8 @@ int BotControl::cmdNode () {
} }
} }
else { else {
if (strValue (cmd) == "help" && hasArg (cmd2) && commands.exists (strValue (cmd2))) { if (arg <StringRef> (cmd) == "help" && hasArg (cmd2) && commands.exists (arg <StringRef> (cmd2))) {
auto &item = commands[strValue (cmd2)]; auto &item = commands[arg <StringRef> (cmd2)];
msg ("Command: \"%s %s %s\"", m_args[root], m_args[alias], item.name); msg ("Command: \"%s %s %s\"", m_args[root], m_args[alias], item.name);
msg ("Format: %s", item.format); msg ("Format: %s", item.format);
@ -461,13 +464,13 @@ int BotControl::cmdNodeOn () {
enum args { alias = 1, cmd, option }; enum args { alias = 1, cmd, option };
// enable various features of editor // enable various features of editor
if (strValue (option).empty () || strValue (option) == "display" || strValue (option) == "models") { if (arg <StringRef> (option).empty () || arg <StringRef> (option) == "display" || arg <StringRef> (option) == "models") {
graph.setEditFlag (GraphEdit::On); graph.setEditFlag (GraphEdit::On);
enableDrawModels (true); enableDrawModels (true);
msg ("Graph editor has been enabled."); msg ("Graph editor has been enabled.");
} }
else if (strValue (option) == "noclip") { else if (arg <StringRef> (option) == "noclip") {
m_ent->v.movetype = MOVETYPE_NOCLIP; m_ent->v.movetype = MOVETYPE_NOCLIP;
if (graph.hasEditFlag (GraphEdit::On)) { if (graph.hasEditFlag (GraphEdit::On)) {
@ -482,7 +485,7 @@ int BotControl::cmdNodeOn () {
msg ("Graph editor has been enabled with noclip mode."); msg ("Graph editor has been enabled with noclip mode.");
} }
} }
else if (strValue (option) == "auto") { else if (arg <StringRef> (option) == "auto") {
if (graph.hasEditFlag (GraphEdit::On)) { if (graph.hasEditFlag (GraphEdit::On)) {
graph.setEditFlag (GraphEdit::Auto); graph.setEditFlag (GraphEdit::Auto);
@ -497,9 +500,9 @@ int BotControl::cmdNodeOn () {
} }
if (graph.hasEditFlag (GraphEdit::On)) { if (graph.hasEditFlag (GraphEdit::On)) {
m_graphSaveVarValues.roundtime = mp_roundtime.float_ (); m_graphSaveVarValues.roundtime = mp_roundtime.as <float> ();
m_graphSaveVarValues.freezetime = mp_freezetime.float_ (); m_graphSaveVarValues.freezetime = mp_freezetime.as <float> ();
m_graphSaveVarValues.timelimit = mp_timelimit.float_ (); m_graphSaveVarValues.timelimit = mp_timelimit.as <float> ();
mp_roundtime.set (9); mp_roundtime.set (9);
mp_freezetime.set (0); mp_freezetime.set (0);
@ -512,7 +515,7 @@ int BotControl::cmdNodeOff () {
enum args { graph_cmd = 1, cmd, option }; enum args { graph_cmd = 1, cmd, option };
// enable various features of editor // enable various features of editor
if (strValue (option).empty () || strValue (option) == "display") { if (arg <StringRef> (option).empty () || arg <StringRef> (option) == "display") {
graph.clearEditFlag (GraphEdit::On | GraphEdit::Auto | GraphEdit::Noclip); graph.clearEditFlag (GraphEdit::On | GraphEdit::Auto | GraphEdit::Noclip);
enableDrawModels (false); enableDrawModels (false);
@ -523,18 +526,18 @@ int BotControl::cmdNodeOff () {
msg ("Graph editor has been disabled."); msg ("Graph editor has been disabled.");
} }
else if (strValue (option) == "models") { else if (arg <StringRef> (option) == "models") {
enableDrawModels (false); enableDrawModels (false);
msg ("Graph editor has disabled spawn points highlighting."); msg ("Graph editor has disabled spawn points highlighting.");
} }
else if (strValue (option) == "noclip") { else if (arg <StringRef> (option) == "noclip") {
m_ent->v.movetype = MOVETYPE_WALK; m_ent->v.movetype = MOVETYPE_WALK;
graph.clearEditFlag (GraphEdit::Noclip); graph.clearEditFlag (GraphEdit::Noclip);
msg ("Graph editor has disabled noclip mode."); msg ("Graph editor has disabled noclip mode.");
} }
else if (strValue (option) == "auto") { else if (arg <StringRef> (option) == "auto") {
graph.clearEditFlag (GraphEdit::Auto); graph.clearEditFlag (GraphEdit::Auto);
msg ("Graph editor has disabled auto add node mode."); msg ("Graph editor has disabled auto add node mode.");
} }
@ -567,12 +570,12 @@ int BotControl::cmdNodeSave () {
enum args { graph_cmd = 1, cmd, option }; enum args { graph_cmd = 1, cmd, option };
// if no check is set save anyway // if no check is set save anyway
if (strValue (option) == "nocheck") { if (arg <StringRef> (option) == "nocheck") {
graph.saveGraphData (); graph.saveGraphData ();
msg ("All nodes has been saved and written to disk (IGNORING QUALITY CONTROL)."); msg ("All nodes has been saved and written to disk (IGNORING QUALITY CONTROL).");
} }
else if (strValue (option) == "old" || strValue (option) == "oldformat") { else if (arg <StringRef> (option) == "old" || arg <StringRef> (option) == "oldformat") {
if (graph.length () >= 1024) { if (graph.length () >= 1024) {
msg ("Unable to save POD-Bot Format waypoint file. Number of nodes exceeds 1024."); msg ("Unable to save POD-Bot Format waypoint file. Number of nodes exceeds 1024.");
@ -611,7 +614,7 @@ int BotControl::cmdNodeErase () {
enum args { graph_cmd = 1, cmd, iamsure }; enum args { graph_cmd = 1, cmd, iamsure };
// prevent accidents when graph are deleted unintentionally // prevent accidents when graph are deleted unintentionally
if (strValue (iamsure) == "iamsure") { if (arg <StringRef> (iamsure) == "iamsure") {
bstor.unlinkFromDisk (); bstor.unlinkFromDisk ();
} }
else { else {
@ -627,11 +630,11 @@ int BotControl::cmdNodeDelete () {
graph.setEditFlag (GraphEdit::On); graph.setEditFlag (GraphEdit::On);
// if "nearest" or nothing passed delete nearest, else delete by index // if "nearest" or nothing passed delete nearest, else delete by index
if (strValue (nearest).empty () || strValue (nearest) == "nearest") { if (arg <StringRef> (nearest).empty () || arg <StringRef> (nearest) == "nearest") {
graph.erase (kInvalidNodeIndex); graph.erase (kInvalidNodeIndex);
} }
else { else {
int index = intValue (nearest); const auto index = arg <int> (nearest);
// check for existence // check for existence
if (graph.exists (index)) { if (graph.exists (index)) {
@ -662,11 +665,11 @@ int BotControl::cmdNodeCache () {
graph.setEditFlag (GraphEdit::On); graph.setEditFlag (GraphEdit::On);
// if "nearest" or nothing passed delete nearest, else delete by index // if "nearest" or nothing passed delete nearest, else delete by index
if (strValue (nearest).empty () || strValue (nearest) == "nearest") { if (arg <StringRef> (nearest).empty () || arg <StringRef> (nearest) == "nearest") {
graph.cachePoint (kInvalidNodeIndex); graph.cachePoint (kInvalidNodeIndex);
} }
else { else {
const int index = intValue (nearest); const int index = arg <int> (nearest);
// check for existence // check for existence
if (graph.exists (index)) { if (graph.exists (index)) {
@ -683,7 +686,7 @@ int BotControl::cmdNodeClean () {
graph.setEditFlag (GraphEdit::On); graph.setEditFlag (GraphEdit::On);
// if "all" passed clean up all the paths // if "all" passed clean up all the paths
if (strValue (option) == "all") { if (arg <StringRef> (option) == "all") {
int removed = 0; int removed = 0;
for (auto i = 0; i < graph.length (); ++i) { for (auto i = 0; i < graph.length (); ++i) {
@ -691,13 +694,13 @@ int BotControl::cmdNodeClean () {
} }
msg ("Done. Processed %d nodes. %d useless paths was cleared.", graph.length (), removed); msg ("Done. Processed %d nodes. %d useless paths was cleared.", graph.length (), removed);
} }
else if (strValue (option).empty () || strValue (option) == "nearest") { else if (arg <StringRef> (option).empty () || arg <StringRef> (option) == "nearest") {
int removed = graph.clearConnections (graph.getEditorNearest ()); int removed = graph.clearConnections (graph.getEditorNearest ());
msg ("Done. Processed node %d. %d useless paths was cleared.", graph.getEditorNearest (), removed); msg ("Done. Processed node %d. %d useless paths was cleared.", graph.getEditorNearest (), removed);
} }
else { else {
const int index = intValue (option); const int index = arg <int> (option);
// check for existence // check for existence
if (graph.exists (index)) { if (graph.exists (index)) {
@ -721,13 +724,13 @@ int BotControl::cmdNodeSetRadius () {
} }
int radiusIndex = kInvalidNodeIndex; int radiusIndex = kInvalidNodeIndex;
if (strValue (index).empty () || strValue (index) == "nearest") { if (arg <StringRef> (index).empty () || arg <StringRef> (index) == "nearest") {
radiusIndex = graph.getEditorNearest (); radiusIndex = graph.getEditorNearest ();
} }
else { else {
radiusIndex = intValue (index); radiusIndex = arg <int> (index);
} }
graph.setRadius (radiusIndex, strValue (radius).float_ ()); graph.setRadius (radiusIndex, arg <StringRef> (radius).as <float> ());
return BotCommandResult::Handled; return BotCommandResult::Handled;
} }
@ -749,7 +752,7 @@ int BotControl::cmdNodeTeleport () {
if (!hasArg (teleport_index)) { if (!hasArg (teleport_index)) {
return BotCommandResult::BadFormat; return BotCommandResult::BadFormat;
} }
int index = intValue (teleport_index); int index = arg <int> (teleport_index);
// check for existence // check for existence
if (graph.exists (index)) { if (graph.exists (index)) {
@ -773,16 +776,16 @@ int BotControl::cmdNodePathCreate () {
graph.setEditFlag (GraphEdit::On); graph.setEditFlag (GraphEdit::On);
// choose the direction for path creation // choose the direction for path creation
if (strValue (cmd).endsWith ("_jump")) { if (arg <StringRef> (cmd).endsWith ("_jump")) {
graph.pathCreate (PathConnection::Jumping); graph.pathCreate (PathConnection::Jumping);
} }
else if (strValue (cmd).endsWith ("_both")) { else if (arg <StringRef> (cmd).endsWith ("_both")) {
graph.pathCreate (PathConnection::Bidirectional); graph.pathCreate (PathConnection::Bidirectional);
} }
else if (strValue (cmd).endsWith ("_in")) { else if (arg <StringRef> (cmd).endsWith ("_in")) {
graph.pathCreate (PathConnection::Incoming); graph.pathCreate (PathConnection::Incoming);
} }
else if (strValue (cmd).endsWith ("_out")) { else if (arg <StringRef> (cmd).endsWith ("_out")) {
graph.pathCreate (PathConnection::Outgoing); graph.pathCreate (PathConnection::Outgoing);
} }
else { else {
@ -819,7 +822,7 @@ int BotControl::cmdNodePathCleanAll () {
auto requestedNode = kInvalidNodeIndex; auto requestedNode = kInvalidNodeIndex;
if (hasArg (index)) { if (hasArg (index)) {
requestedNode = intValue (index); requestedNode = arg <int> (index);
} }
graph.resetPath (requestedNode); graph.resetPath (requestedNode);
@ -871,7 +874,7 @@ int BotControl::cmdNodeUpload () {
msg ("Sorry, unable to upload graph file that contains errors. Please type \"graph check\" to verify graph consistency."); msg ("Sorry, unable to upload graph file that contains errors. Please type \"graph check\" to verify graph consistency.");
return BotCommandResult::Handled; return BotCommandResult::Handled;
} }
String uploadUrlAddress = cv_graph_url_upload.str (); String uploadUrlAddress = cv_graph_url_upload.as <StringRef> ();
// only allow to upload to non-https endpoint // only allow to upload to non-https endpoint
if (uploadUrlAddress.startsWith ("https")) { if (uploadUrlAddress.startsWith ("https")) {
@ -930,7 +933,7 @@ int BotControl::cmdNodeIterateCamp () {
graph.setEditFlag (GraphEdit::On); graph.setEditFlag (GraphEdit::On);
// get the option describing operation // get the option describing operation
auto op = strValue (option); auto op = arg <StringRef> (option);
if (op != "begin" && op != "end" && op != "next") { if (op != "begin" && op != "end" && op != "next") {
return BotCommandResult::BadFormat; return BotCommandResult::BadFormat;
@ -998,7 +1001,7 @@ int BotControl::cmdNodeAdjustHeight () {
if (!hasArg (offset)) { if (!hasArg (offset)) {
return BotCommandResult::BadFormat; return BotCommandResult::BadFormat;
} }
auto heightOffset = floatValue (offset); auto heightOffset = arg <float> (offset);
// adjust the height for all the nodes (negative values possible) // adjust the height for all the nodes (negative values possible)
for (auto &path : graph) { for (auto &path : graph) {
@ -1026,7 +1029,7 @@ int BotControl::menuMain (int item) {
break; break;
case 4: case 4:
if (game.is (GameFlags::ReGameDLL) && !cv_bots_kill_on_endround.bool_ ()) { if (game.is (GameFlags::ReGameDLL) && !cv_bots_kill_on_endround) {
game.serverCommand ("endround"); game.serverCommand ("endround");
} }
else { else {
@ -1069,7 +1072,7 @@ int BotControl::menuFeatures (int item) {
break; break;
case 4: case 4:
cv_debug.set (cv_debug.int_ () ^ 1); cv_debug.set (cv_debug.as <int> () ^ 1);
showMenu (Menu::Features); showMenu (Menu::Features);
break; break;
@ -1549,8 +1552,8 @@ int BotControl::menuGraphDebug (int item) {
switch (item) { switch (item) {
case 1: case 1:
cv_debug_goal.set (graph.getEditorNearest ()); cv_debug_goal.set (graph.getEditorNearest ());
if (cv_debug_goal.int_ () != kInvalidNodeIndex) { if (cv_debug_goal.as <int> () != kInvalidNodeIndex) {
msg ("Debug goal is set to node %d.", cv_debug_goal.int_ ()); msg ("Debug goal is set to node %d.", cv_debug_goal.as <int> ());
} }
else { else {
msg ("Cannot find the node. Debug goal is disabled."); msg ("Cannot find the node. Debug goal is disabled.");
@ -1560,8 +1563,8 @@ int BotControl::menuGraphDebug (int item) {
case 2: case 2:
cv_debug_goal.set (graph.getFacingIndex ()); cv_debug_goal.set (graph.getFacingIndex ());
if (cv_debug_goal.int_ () != kInvalidNodeIndex) { if (cv_debug_goal.as <int> () != kInvalidNodeIndex) {
msg ("Debug goal is set to node %d.", cv_debug_goal.int_ ()); msg ("Debug goal is set to node %d.", cv_debug_goal.as <int> ());
} }
else { else {
msg ("Cannot find the node. Debug goal is disabled."); msg ("Cannot find the node. Debug goal is disabled.");
@ -1871,7 +1874,7 @@ bool BotControl::executeCommands () {
String cmd; String cmd;
// give some help // give some help
if (hasArg (1) && strValue (1) == "help") { if (hasArg (1) && arg <StringRef> (1) == "help") {
const auto hasSecondArg = hasArg (2); const auto hasSecondArg = hasArg (2);
for (auto &item : m_cmds) { for (auto &item : m_cmds) {
@ -1879,7 +1882,7 @@ bool BotControl::executeCommands () {
cmd = item.name.split ("/").first (); cmd = item.name.split ("/").first ();
} }
if (!hasSecondArg || aliasMatch (item.name, strValue (2), cmd)) { if (!hasSecondArg || aliasMatch (item.name, arg <StringRef> (2), cmd)) {
msg ("Command: \"%s %s\"", prefix, cmd); msg ("Command: \"%s %s\"", prefix, cmd);
msg ("Format: %s", item.format); msg ("Format: %s", item.format);
msg ("Help: %s", conf.translate (item.help)); msg ("Help: %s", conf.translate (item.help));
@ -1903,7 +1906,7 @@ bool BotControl::executeCommands () {
return true; return true;
} }
else { else {
msg ("No help found for \"%s\"", strValue (2)); msg ("No help found for \"%s\"", arg <StringRef> (2));
} }
return true; return true;
} }
@ -1961,14 +1964,14 @@ bool BotControl::executeMenus () {
const auto &issuer = util.getClient (game.indexOfPlayer (m_ent)); const auto &issuer = util.getClient (game.indexOfPlayer (m_ent));
// check if it's menu select, and some key pressed // check if it's menu select, and some key pressed
if (strValue (0) != "menuselect" || strValue (1).empty () || issuer.menu == Menu::None) { if (arg <StringRef> (0) != "menuselect" || arg <StringRef> (1).empty () || issuer.menu == Menu::None) {
return false; return false;
} }
// let's get handle // let's get handle
for (auto &menu : m_menus) { for (auto &menu : m_menus) {
if (menu.ident == issuer.menu) { if (menu.ident == issuer.menu) {
return (this->*menu.handler) (strValue (1).int_ ()) == BotCommandResult::Handled; return (this->*menu.handler) (arg <StringRef> (1).as <int> ()) == BotCommandResult::Handled;
} }
} }
return false; return false;
@ -2013,7 +2016,7 @@ void BotControl::showMenu (int id) {
for (const auto &display : m_menus) { for (const auto &display : m_menus) {
if (display.ident == id) { if (display.ident == id) {
String text = (game.is (GameFlags::Xash3D | GameFlags::Mobility) && !cv_display_menu_text.bool_ ()) ? " " : display.text.chars (); String text = (game.is (GameFlags::Xash3D | GameFlags::Mobility) && !cv_display_menu_text) ? " " : display.text.chars ();
// split if needed // split if needed
if (text.length () > maxMenuSentLength) { if (text.length () > maxMenuSentLength) {
@ -2106,8 +2109,8 @@ void BotControl::assignAdminRights (edict_t *ent, char *infobuffer) {
if (!game.isDedicated () || util.isFakeClient (ent)) { if (!game.isDedicated () || util.isFakeClient (ent)) {
return; return;
} }
StringRef key = cv_password_key.str (); StringRef key = cv_password_key.as <StringRef> ();
StringRef password = cv_password.str (); StringRef password = cv_password.as <StringRef> ();
if (!key.empty () && !password.empty ()) { if (!key.empty () && !password.empty ()) {
auto &client = util.getClient (game.indexOfPlayer (ent)); auto &client = util.getClient (game.indexOfPlayer (ent));
@ -2126,8 +2129,8 @@ void BotControl::maintainAdminRights () {
return; return;
} }
StringRef key = cv_password_key.str (); StringRef key = cv_password_key.as <StringRef> ();
StringRef password = cv_password.str (); StringRef password = cv_password.as <StringRef> ();
for (auto &client : util.getClients ()) { for (auto &client : util.getClients ()) {
if (!(client.flags & ClientFlags::Used) || util.isFakeClient (client.ent)) { if (!(client.flags & ClientFlags::Used) || util.isFakeClient (client.ent)) {

View file

@ -11,7 +11,7 @@ ConVar cv_csdm_mode ("csdm_mode", "0", "Enables or disables CSDM / FFA mode for
ConVar cv_ignore_map_prefix_game_mode ("ignore_map_prefix_game_mode", "0", "If enabled, bots will not apply game modes based on map name prefix (fy_ and ka_ specifically)."); ConVar cv_ignore_map_prefix_game_mode ("ignore_map_prefix_game_mode", "0", "If enabled, bots will not apply game modes based on map name prefix (fy_ and ka_ specifically).");
ConVar cv_threadpool_workers ("threadpool_workers", "-1", "Maximum number of threads bot will run to process some tasks. -1 means half of CPU cores used.", true, -1.0f, static_cast <float> (plat.hardwareConcurrency ())); ConVar cv_threadpool_workers ("threadpool_workers", "-1", "Maximum number of threads bot will run to process some tasks. -1 means half of CPU cores used.", true, -1.0f, static_cast <float> (plat.hardwareConcurrency ()));
ConVar cv_grenadier_mode ("grenadier_mode", "0", "If enabled, bots will not apply throwing condition on grenades."); ConVar cv_grenadier_mode ("grenadier_mode", "0", "If enabled, bots will not apply throwing condition on grenades.");
ConVar cv_ignore_enemies_after_spawn_time ("ignore_enemies_after_spawn_time", "0", "Make bots ignore enemies for a specified here time in seconds on new round. Useful for Zombie Plague mods.", true, 0.0f, 540.0f); ConVar cv_ignore_enemies_after_spawn_time ("ignore_enemies_after_spawn_time", "0", "Make bots ignore enemies for a specified here time in seconds on new round. Useful for Zombie Plague mods.", false);
ConVar sv_skycolor_r ("sv_skycolor_r", nullptr, Var::GameRef); ConVar sv_skycolor_r ("sv_skycolor_r", nullptr, Var::GameRef);
ConVar sv_skycolor_g ("sv_skycolor_g", nullptr, Var::GameRef); ConVar sv_skycolor_g ("sv_skycolor_g", nullptr, Var::GameRef);
@ -55,7 +55,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
bots.destroy (); bots.destroy ();
// startup threaded worker // startup threaded worker
worker.startup (cv_threadpool_workers.int_ ()); worker.startup (cv_threadpool_workers.as <int> ());
m_spawnCount[Team::CT] = 0; m_spawnCount[Team::CT] = 0;
m_spawnCount[Team::Terrorist] = 0; m_spawnCount[Team::Terrorist] = 0;
@ -154,7 +154,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
} }
// next maps doesn't have map-specific entities, so determine it by name // next maps doesn't have map-specific entities, so determine it by name
if (!cv_ignore_map_prefix_game_mode.bool_ ()) { if (!cv_ignore_map_prefix_game_mode) {
StringRef prefix = getMapName (); StringRef prefix = getMapName ();
if (prefix.startsWith ("fy_")) { if (prefix.startsWith ("fy_")) {
@ -590,27 +590,27 @@ bool Game::is25thAnniversaryUpdate () {
return sv_use_steam_networking.exists (); return sv_use_steam_networking.exists ();
} }
void Game::addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32_t varType, bool missingAction, const char *regval, ConVar *self) { void Game::pushConVar (StringRef name, StringRef value, StringRef info, bool bounded, float min, float max, int32_t varType, bool missingAction, StringRef regval, ConVar *self) {
// this function adds globally defined variable to registration stack // this function adds globally defined variable to registration stack
ConVarReg reg {}; ConVarReg reg {};
reg.reg.name = const_cast <char *> (name); reg.reg.name = name.chars ();
reg.reg.string = const_cast <char *> (value); reg.reg.string = value.chars ();
reg.name = name; reg.name = name;
reg.missing = missingAction; reg.missing = missingAction;
reg.init = value; reg.init = value;
reg.info = info; reg.info = info;
reg.bounded = bounded; reg.bounded = bounded;
if (regval) { if (!regval.empty ()) {
reg.regval = regval; reg.regval = regval;
} }
if (bounded) { if (bounded) {
reg.min = min; reg.min = min;
reg.max = max; reg.max = max;
reg.initial = static_cast <float> (atof (value)); reg.initial = value.as <float> ();
} }
int eflags = FCVAR_EXTDLL; int eflags = FCVAR_EXTDLL;
@ -646,7 +646,7 @@ void ConVar::revert () {
} }
} }
void ConVar::setPrefix (const char *name, int32_t type) { void ConVar::setPrefix (StringRef name, int32_t type) {
if (type == Var::GameRef) { if (type == Var::GameRef) {
name_ = name; name_ = name;
return; return;
@ -662,7 +662,7 @@ void Game::checkCvarsBounds () {
// read only cvar is not changeable // read only cvar is not changeable
if (var.type == Var::ReadOnly && !var.init.empty ()) { if (var.type == Var::ReadOnly && !var.init.empty ()) {
if (var.init != var.self->str ()) { if (var.init != var.self->as <StringRef> ()) {
var.self->set (var.init.chars ()); var.self->set (var.init.chars ());
} }
continue; continue;
@ -671,8 +671,8 @@ void Game::checkCvarsBounds () {
if (!var.bounded || !var.self) { if (!var.bounded || !var.self) {
continue; continue;
} }
auto value = var.self->float_ (); auto value = var.self->as <float> ();
auto str = String (var.self->str ()); auto str = String (var.self->as <StringRef> ());
// check the bounds and set default if out of bounds // check the bounds and set default if out of bounds
if (value > var.max || value < var.min || (!str.empty () && isalpha (str[0]))) { if (value > var.max || value < var.min || (!str.empty () && isalpha (str[0]))) {
@ -685,7 +685,7 @@ void Game::checkCvarsBounds () {
// special case for xash3d, by default engine is not calling startframe if no players on server, but our quota management and bot adding // special case for xash3d, by default engine is not calling startframe if no players on server, but our quota management and bot adding
// mechanism assumes that starframe is called even if no players on server, so, set the xash3d's sv_forcesimulating cvar to 1 in case it's not // mechanism assumes that starframe is called even if no players on server, so, set the xash3d's sv_forcesimulating cvar to 1 in case it's not
if (is (GameFlags::Xash3D)) { if (is (GameFlags::Xash3DLegacy)) {
static ConVarRef sv_forcesimulating ("sv_forcesimulating"); static ConVarRef sv_forcesimulating ("sv_forcesimulating");
if (sv_forcesimulating.exists () && !cr::fequal (sv_forcesimulating.value (), 1.0f)) { if (sv_forcesimulating.exists () && !cr::fequal (sv_forcesimulating.value (), 1.0f)) {
@ -929,7 +929,7 @@ void Game::applyGameModes () {
} }
// handle cvar cases // handle cvar cases
switch (cv_csdm_mode.int_ ()) { switch (cv_csdm_mode.as <int> ()) {
default: default:
case 0: case 0:
break; break;
@ -1312,5 +1312,5 @@ float LightMeasure::getLightLevel (const Vector &point) {
} }
float LightMeasure::getSkyColor () { float LightMeasure::getSkyColor () {
return static_cast <float> (Color (sv_skycolor_r.int_ (), sv_skycolor_g.int_ (), sv_skycolor_b.int_ ()).avg ()); return static_cast <float> (Color (sv_skycolor_r.as <int> (), sv_skycolor_g.as <int> (), sv_skycolor_b.as <int> ()).avg ());
} }

View file

@ -729,7 +729,7 @@ void BotGraph::add (int type, const Vector &pos) {
} }
// autosave nodes here and there // autosave nodes here and there
if (!analyzer.isAnalyzing () && cv_graph_auto_save_count.bool_ () && ++m_autoSaveCount >= cv_graph_auto_save_count.int_ ()) { if (!analyzer.isAnalyzing () && cv_graph_auto_save_count && ++m_autoSaveCount >= cv_graph_auto_save_count.as <int> ()) {
if (saveGraphData ()) { if (saveGraphData ()) {
msg ("Nodes has been autosaved..."); msg ("Nodes has been autosaved...");
} }
@ -1324,7 +1324,7 @@ void BotGraph::syncCollectOnline () {
if (localGraphs.empty ()) { if (localGraphs.empty ()) {
return; return;
} }
String uploadUrlAddress = cv_graph_url_upload.str (); String uploadUrlAddress = cv_graph_url_upload.as <StringRef> ();
// only allow to upload to non-https endpoint // only allow to upload to non-https endpoint
if (uploadUrlAddress.startsWith ("https")) { if (uploadUrlAddress.startsWith ("https")) {
@ -1416,7 +1416,7 @@ void BotGraph::syncCollectOnline () {
} }
void BotGraph::collectOnline () { void BotGraph::collectOnline () {
if (m_isOnlineCollected || !cv_graph_auto_collect_db.bool_ ()) { if (m_isOnlineCollected || !cv_graph_auto_collect_db) {
return; return;
} }
@ -1818,7 +1818,7 @@ bool BotGraph::loadGraphData () {
} }
bool BotGraph::canDownload () { bool BotGraph::canDownload () {
return !cv_graph_url.str ().empty (); return !cv_graph_url.as <StringRef> ().empty ();
} }
bool BotGraph::saveGraphData () { bool BotGraph::saveGraphData () {
@ -2019,7 +2019,7 @@ bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) {
} }
bool BotGraph::isNodeReacheableWithJump (const Vector &src, const Vector &destination) { bool BotGraph::isNodeReacheableWithJump (const Vector &src, const Vector &destination) {
return isNodeReacheableEx (src, destination, cv_graph_analyze_max_jump_height.float_ ()); return isNodeReacheableEx (src, destination, cv_graph_analyze_max_jump_height.as <float> ());
} }
void BotGraph::frame () { void BotGraph::frame () {
@ -2092,7 +2092,7 @@ void BotGraph::frame () {
const float distanceSq = path.origin.distanceSq (m_editor->v.origin); const float distanceSq = path.origin.distanceSq (m_editor->v.origin);
// check if node is within a distance, and is visible // check if node is within a distance, and is visible
if (distanceSq < cr::sqrf (cv_graph_draw_distance.float_ ()) if (distanceSq < cr::sqrf (cv_graph_draw_distance.as <float> ())
&& ((util.isVisible (path.origin, m_editor) && ((util.isVisible (path.origin, m_editor)
&& util.isInViewCone (path.origin, m_editor)) || !util.isAlive (m_editor) || distanceSq < cr::sqrf (64.0f))) { && util.isInViewCone (path.origin, m_editor)) || !util.isAlive (m_editor) || distanceSq < cr::sqrf (64.0f))) {
@ -2844,7 +2844,7 @@ void BotGraph::convertFromPOD (Path &path, const PODPath &pod) {
path.start = Vector (pod.csx, pod.csy, 0.0f); path.start = Vector (pod.csx, pod.csy, 0.0f);
path.end = Vector (pod.cex, pod.cey, 0.0f); path.end = Vector (pod.cex, pod.cey, 0.0f);
if (cv_graph_fixcamp.bool_ ()) { if (cv_graph_fixcamp) {
convertCampDirection (path); convertCampDirection (path);
} }
path.radius = pod.radius; path.radius = pod.radius;

View file

@ -61,7 +61,7 @@ int32_t ServerQueryHook::sendTo (int socket, const void *message, size_t length,
void ServerQueryHook::init () { void ServerQueryHook::init () {
// if previously requested to disable? // if previously requested to disable?
if (!cv_enable_query_hook.bool_ ()) { if (!cv_enable_query_hook) {
if (m_sendToDetour.detoured ()) { if (m_sendToDetour.detoured ()) {
disable (); disable ();
} }

View file

@ -394,7 +394,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
auto ent = const_cast <edict_t *> (player); auto ent = const_cast <edict_t *> (player);
// if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false, and SV_EmitPings will not overwrite our results // if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false, and SV_EmitPings will not overwrite our results
if (cv_show_latency.int_ () == 2) { if (cv_show_latency.as <int> () == 2) {
if (!util.isFakeClient (ent) && (ent->v.oldbuttons | ent->v.button | cmd->buttons) & IN_SCORE) { if (!util.isFakeClient (ent) && (ent->v.oldbuttons | ent->v.button | cmd->buttons) & IN_SCORE) {
cmd->buttons &= ~IN_SCORE; cmd->buttons &= ~IN_SCORE;
util.emitPings (ent); util.emitPings (ent);
@ -863,10 +863,10 @@ CR_EXPORT int Meta_Query (char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_t
gpMetaUtilFuncs->pfnLogError (PLID, "%s: meta-interface version mismatch (metamod: %s, %s: %s)", Plugin_info.name, ifvers, Plugin_info.name, Plugin_info.ifvers); gpMetaUtilFuncs->pfnLogError (PLID, "%s: meta-interface version mismatch (metamod: %s, %s: %s)", Plugin_info.name, ifvers, Plugin_info.name, Plugin_info.ifvers);
const auto mmajor = mdll[0].int_ () ; const auto mmajor = mdll[0].as <int> ();
const auto mminor = mdll[1].int_ (); const auto mminor = mdll[1].as <int> ();
const auto pmajor = pdll[0].int_ (); const auto pmajor = pdll[0].as <int> ();
const auto pminor = pdll[1].int_ (); const auto pminor = pdll[1].as <int> ();
if (pmajor > mmajor || (pmajor == mmajor && pminor > mminor)) { if (pmajor > mmajor || (pmajor == mmajor && pminor > mminor)) {
gpMetaUtilFuncs->pfnLogError (PLID, "metamod version is too old for this plugin; update metamod"); gpMetaUtilFuncs->pfnLogError (PLID, "metamod version is too old for this plugin; update metamod");

View file

@ -192,10 +192,10 @@ BotCreateResult BotManager::create (StringRef name, int difficulty, int personal
return BotCreateResult::TeamStacked; return BotCreateResult::TeamStacked;
} }
if (difficulty < Difficulty::Noob || difficulty > Difficulty::Expert) { if (difficulty < Difficulty::Noob || difficulty > Difficulty::Expert) {
difficulty = cv_difficulty.int_ (); difficulty = cv_difficulty.as <int> ();
if (difficulty < Difficulty::Noob || difficulty > Difficulty::Expert) { if (difficulty < Difficulty::Noob || difficulty > Difficulty::Expert) {
difficulty = rg.get (3, 4); difficulty = rg (3, 4);
cv_difficulty.set (difficulty); cv_difficulty.set (difficulty);
} }
} }
@ -211,8 +211,8 @@ BotCreateResult BotManager::create (StringRef name, int difficulty, int personal
if (personality < Personality::Normal || personality > Personality::Careful) { if (personality < Personality::Normal || personality > Personality::Careful) {
// assign preferred if we're forced with cvar // assign preferred if we're forced with cvar
if (personalityMap.exists (cv_preferred_personality.str ())) { if (personalityMap.exists (cv_preferred_personality.as <StringRef> ())) {
personality = personalityMap[cv_preferred_personality.str ()]; personality = personalityMap[cv_preferred_personality.as <StringRef> ()];
} }
// do a holy random // do a holy random
@ -240,22 +240,22 @@ BotCreateResult BotManager::create (StringRef name, int difficulty, int personal
resultName = botName->name; resultName = botName->name;
} }
else { else {
resultName.assignf ("%s_%d.%d", product.nameLower, rg.get (100, 10000), rg.get (100, 10000)); // just pick ugly random name resultName.assignf ("%s_%d.%d", product.nameLower, rg (100, 10000), rg (100, 10000)); // just pick ugly random name
} }
} }
else { else {
resultName = name; resultName = name;
} }
const bool hasNamePrefix = !cv_name_prefix.str ().empty (); const bool hasNamePrefix = !cv_name_prefix.as <StringRef> ().empty ();
// disable save bots names if prefix is enabled // disable save bots names if prefix is enabled
if (hasNamePrefix && cv_save_bots_names.bool_ ()) { if (hasNamePrefix && cv_save_bots_names) {
cv_save_bots_names.set (0); cv_save_bots_names.set (0);
} }
if (hasNamePrefix) { if (hasNamePrefix) {
String prefixed; // temp buffer for storing modified name String prefixed; // temp buffer for storing modified name
prefixed.assignf ("%s %s", cv_name_prefix.str (), resultName); prefixed.assignf ("%s %s", cv_name_prefix.as <StringRef> (), resultName);
// buffer has been modified, copy to real name // buffer has been modified, copy to real name
resultName = cr::move (prefixed); resultName = cr::move (prefixed);
@ -336,7 +336,7 @@ void BotManager::addbot (StringRef name, int difficulty, int personality, int te
request.manual = manual; request.manual = manual;
// restore the bot name // restore the bot name
if (cv_save_bots_names.bool_ () && name.empty () && !m_saveBotNames.empty ()) { if (cv_save_bots_names && name.empty () && !m_saveBotNames.empty ()) {
request.name = m_saveBotNames.popFront (); request.name = m_saveBotNames.popFront ();
} }
@ -351,10 +351,10 @@ void BotManager::addbot (StringRef name, StringRef difficulty, StringRef persona
static StringRef any = "*"; static StringRef any = "*";
request.name = (name.empty () || name == any) ? StringRef ("\0") : name; request.name = (name.empty () || name == any) ? StringRef ("\0") : name;
request.difficulty = (difficulty.empty () || difficulty == any) ? -1 : difficulty.int_ (); request.difficulty = (difficulty.empty () || difficulty == any) ? -1 : difficulty.as <int> ();
request.team = (team.empty () || team == any) ? -1 : team.int_ (); request.team = (team.empty () || team == any) ? -1 : team.as <int> ();
request.skin = (skin.empty () || skin == any) ? -1 : skin.int_ (); request.skin = (skin.empty () || skin == any) ? -1 : skin.as <int> ();
request.personality = (personality.empty () || personality == any) ? -1 : personality.int_ (); request.personality = (personality.empty () || personality == any) ? -1 : personality.as <int> ();
request.manual = manual; request.manual = manual;
addbot (request.name, request.difficulty, request.personality, request.team, request.skin, request.manual); addbot (request.name, request.difficulty, request.personality, request.team, request.skin, request.manual);
@ -365,7 +365,7 @@ void BotManager::maintainQuota () {
// while creation process in process. // while creation process in process.
if (graph.length () < 1 || graph.hasChanged ()) { if (graph.length () < 1 || graph.hasChanged ()) {
if (cv_quota.int_ () > 0) { if (cv_quota.as <int> () > 0) {
ctrl.msg ("There is no graph found. Cannot create bot."); ctrl.msg ("There is no graph found. Cannot create bot.");
} }
cv_quota.set (0); cv_quota.set (0);
@ -383,7 +383,7 @@ void BotManager::maintainQuota () {
const BotCreateResult createResult = create (request.name, request.difficulty, request.personality, request.team, request.skin); const BotCreateResult createResult = create (request.name, request.difficulty, request.personality, request.team, request.skin);
if (request.manual) { if (request.manual) {
cv_quota.set (cr::min (cv_quota.int_ () + 1, game.maxClients ())); cv_quota.set (cr::min (cv_quota.as <int> () + 1, game.maxClients ()));
} }
// check the result of creation // check the result of creation
@ -403,14 +403,14 @@ void BotManager::maintainQuota () {
m_addRequests.clear (); m_addRequests.clear ();
cv_quota.set (getBotCount ()); cv_quota.set (getBotCount ());
} }
m_maintainTime = game.time () + cv_quota_adding_interval.float_ (); m_maintainTime = game.time () + cv_quota_adding_interval.as <float> ();
} }
// now keep bot number up to date // now keep bot number up to date
if (m_quotaMaintainTime > game.time ()) { if (m_quotaMaintainTime > game.time ()) {
return; return;
} }
cv_quota.set (cr::clamp <int> (cv_quota.int_ (), 0, game.maxClients ())); cv_quota.set (cr::clamp <int> (cv_quota.as <int> (), 0, game.maxClients ()));
const int totalHumansInGame = getHumansCount (); const int totalHumansInGame = getHumansCount ();
const int humanPlayersInGame = getHumansCount (true); const int humanPlayersInGame = getHumansCount (true);
@ -419,29 +419,29 @@ void BotManager::maintainQuota () {
return; return;
} }
int desiredBotCount = cv_quota.int_ (); int desiredBotCount = cv_quota.as <int> ();
int botsInGame = getBotCount (); int botsInGame = getBotCount ();
if (cv_quota_mode.str () == "fill") { if (cv_quota_mode.as <StringRef> () == "fill") {
botsInGame += humanPlayersInGame; botsInGame += humanPlayersInGame;
} }
else if (cv_quota_mode.str () == "match") { else if (cv_quota_mode.as <StringRef> () == "match") {
int detectQuotaMatch = cv_quota_match.int_ () == 0 ? cv_quota.int_ () : cv_quota_match.int_ (); int detectQuotaMatch = cv_quota_match.as <int> () == 0 ? cv_quota.as <int> () : cv_quota_match.as <int> ();
desiredBotCount = cr::max <int> (0, detectQuotaMatch * humanPlayersInGame); desiredBotCount = cr::max <int> (0, detectQuotaMatch * humanPlayersInGame);
} }
if (cv_join_after_player.bool_ () && humanPlayersInGame == 0) { if (cv_join_after_player && humanPlayersInGame == 0) {
desiredBotCount = 0; desiredBotCount = 0;
} }
int maxClients = game.maxClients (); int maxClients = game.maxClients ();
if (cv_autovacate.bool_ ()) { if (cv_autovacate) {
if (cv_kick_after_player_connect.bool_ ()) { if (cv_kick_after_player_connect) {
desiredBotCount = cr::min <int> (desiredBotCount, maxClients - (totalHumansInGame + cv_autovacate_keep_slots.int_ ())); desiredBotCount = cr::min <int> (desiredBotCount, maxClients - (totalHumansInGame + cv_autovacate_keep_slots.as <int> ()));
} }
else { else {
desiredBotCount = cr::min <int> (desiredBotCount, maxClients - (humanPlayersInGame + cv_autovacate_keep_slots.int_ ())); desiredBotCount = cr::min <int> (desiredBotCount, maxClients - (humanPlayersInGame + cv_autovacate_keep_slots.as <int> ()));
} }
} }
else { else {
@ -482,11 +482,11 @@ void BotManager::maintainQuota () {
} }
else { else {
// clear the saved names when quota balancing ended // clear the saved names when quota balancing ended
if (cv_save_bots_names.bool_ () && !m_saveBotNames.empty ()) { if (cv_save_bots_names && !m_saveBotNames.empty ()) {
m_saveBotNames.clear (); m_saveBotNames.clear ();
} }
} }
m_quotaMaintainTime = game.time () + cv_quota_maintain_interval.float_ (); m_quotaMaintainTime = game.time () + cv_quota_maintain_interval.as <float> ();
} }
void BotManager::maintainLeaders () { void BotManager::maintainLeaders () {
@ -503,7 +503,7 @@ void BotManager::maintainLeaders () {
} }
void BotManager::maintainAutoKill () { void BotManager::maintainAutoKill () {
const float killDelay = cv_autokill_delay.float_ (); const float killDelay = cv_autokill_delay.as <float> ();
if (killDelay < 1.0f || m_roundOver) { if (killDelay < 1.0f || m_roundOver) {
return; return;
@ -594,15 +594,15 @@ void BotManager::resetFilters () {
void BotManager::decrementQuota (int by) { void BotManager::decrementQuota (int by) {
if (by != 0) { if (by != 0) {
cv_quota.set (cr::clamp <int> (cv_quota.int_ () - by, 0, cv_quota.int_ ())); cv_quota.set (cr::clamp <int> (cv_quota.as <int> () - by, 0, cv_quota.as <int> ()));
return; return;
} }
cv_quota.set (0); cv_quota.set (0);
} }
void BotManager::initQuota () { void BotManager::initQuota () {
m_maintainTime = game.time () + cv_join_delay.float_ (); m_maintainTime = game.time () + cv_join_delay.as <float> ();
m_quotaMaintainTime = game.time () + cv_join_delay.float_ (); m_quotaMaintainTime = game.time () + cv_join_delay.as <float> ();
m_addRequests.clear (); m_addRequests.clear ();
} }
@ -611,8 +611,8 @@ void BotManager::serverFill (int selection, int personality, int difficulty, int
// this function fill server with bots, with specified team & personality // this function fill server with bots, with specified team & personality
// always keep one slot // always keep one slot
const int maxClients = cv_autovacate.bool_ () const int maxClients = cv_autovacate
? game.maxClients () - cv_autovacate_keep_slots.int_ () - (game.isDedicated () ? 0 : getHumansCount ()) : game.maxClients (); ? game.maxClients () - cv_autovacate_keep_slots.as <int> () - (game.isDedicated () ? 0 : getHumansCount ()) : game.maxClients ();
if (getBotCount () >= maxClients - getHumansCount ()) { if (getBotCount () >= maxClients - getHumansCount ()) {
return; return;
@ -636,7 +636,7 @@ void BotManager::serverFill (int selection, int personality, int difficulty, int
void BotManager::kickEveryone (bool instant, bool zeroQuota) { void BotManager::kickEveryone (bool instant, bool zeroQuota) {
// this function drops all bot clients from server (this function removes only yapb's) // this function drops all bot clients from server (this function removes only yapb's)
if (cv_quota.bool_ () && hasBotsOnline ()) { if (cv_quota && hasBotsOnline ()) {
ctrl.msg ("Bots are removed from server."); ctrl.msg ("Bots are removed from server.");
} }
@ -645,7 +645,7 @@ void BotManager::kickEveryone (bool instant, bool zeroQuota) {
} }
// if everyone is kicked, clear the saved bot names // if everyone is kicked, clear the saved bot names
if (cv_save_bots_names.bool_ () && !m_saveBotNames.empty ()) { if (cv_save_bots_names && !m_saveBotNames.empty ()) {
m_saveBotNames.clear (); m_saveBotNames.clear ();
} }
@ -794,7 +794,7 @@ void BotManager::setLastWinner (int winner) {
m_lastWinner = winner; m_lastWinner = winner;
m_roundOver = true; m_roundOver = true;
if (cv_radio_mode.int_ () != 2) { if (cv_radio_mode.as <int> () != 2) {
return; return;
} }
auto notify = findAliveBot (); auto notify = findAliveBot ();
@ -893,7 +893,7 @@ void BotManager::listBots () {
}; };
for (const auto &bot : bots) { for (const auto &bot : bots) {
auto timelimitStr = cv_rotate_bots.bool_ () ? strings.format ("%-3.0f secs", bot->m_stayTime - game.time ()) : "unlimited"; auto timelimitStr = cv_rotate_bots ? strings.format ("%-3.0f secs", bot->m_stayTime - game.time ()) : "unlimited";
ctrl.msg ("[%-2.1d]\t%-22.16s\t%-10.12s\t%-3.4s\t%-3.1d\t%-3.1d\t%-3.4s\t%s", ctrl.msg ("[%-2.1d]\t%-22.16s\t%-10.12s\t%-3.4s\t%-3.1d\t%-3.1d\t%-3.4s\t%s",
bot->index (), bot->pev->netname.chars (), bot->m_personality == Personality::Rusher ? "rusher" : bot->m_personality == Personality::Normal ? "normal" : "careful", bot->index (), bot->pev->netname.chars (), bot->m_personality == Personality::Rusher ? "rusher" : bot->m_personality == Personality::Normal ? "normal" : "careful",
@ -975,7 +975,7 @@ void BotManager::updateTeamEconomics (int team, bool setTrue) {
// that have not enough money to buy primary (with economics), and if this result higher 80%, player is can't // that have not enough money to buy primary (with economics), and if this result higher 80%, player is can't
// buy primary weapons. // buy primary weapons.
if (setTrue || !cv_economics_rounds.bool_ ()) { if (setTrue || !cv_economics_rounds) {
m_economicsGood[team] = true; m_economicsGood[team] = true;
return; // don't check economics while economics disable return; // don't check economics while economics disable
} }
@ -1011,10 +1011,10 @@ void BotManager::updateTeamEconomics (int team, bool setTrue) {
void BotManager::updateBotDifficulties () { void BotManager::updateBotDifficulties () {
// if min/max difficulty is specified this should not have effect // if min/max difficulty is specified this should not have effect
if (cv_difficulty_min.int_ () != Difficulty::Invalid || cv_difficulty_max.int_ () != Difficulty::Invalid || cv_difficulty_auto.bool_ ()) { if (cv_difficulty_min.as <int> () != Difficulty::Invalid || cv_difficulty_max.as <int> () != Difficulty::Invalid || cv_difficulty_auto) {
return; return;
} }
const auto difficulty = cv_difficulty.int_ (); const auto difficulty = cv_difficulty.as <int> ();
if (difficulty != m_lastDifficulty) { if (difficulty != m_lastDifficulty) {
@ -1033,11 +1033,11 @@ void BotManager::balanceBotDifficulties () {
}; };
// with nightmare difficulty, there is no balance // with nightmare difficulty, there is no balance
if (cv_whose_your_daddy.bool_ ()) { if (cv_whose_your_daddy) {
return; return;
} }
if (cv_difficulty_auto.bool_ () && m_difficultyBalanceTime < game.time ()) { if (cv_difficulty_auto && m_difficultyBalanceTime < game.time ()) {
const auto ratioPlayer = getAverageTeamKPD (false); const auto ratioPlayer = getAverageTeamKPD (false);
const auto ratioBots = getAverageTeamKPD (true); const auto ratioBots = getAverageTeamKPD (true);
@ -1053,7 +1053,7 @@ void BotManager::balanceBotDifficulties () {
updateDifficulty (bot.get (), -1); updateDifficulty (bot.get (), -1);
} }
} }
m_difficultyBalanceTime = game.time () + cv_difficulty_auto_balance_interval.float_ (); m_difficultyBalanceTime = game.time () + cv_difficulty_auto_balance_interval.as <float> ();
} }
} }
@ -1090,12 +1090,12 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "_ah", "0"); engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "_ah", "0");
if (!game.is (GameFlags::Legacy)) { if (!game.is (GameFlags::Legacy)) {
if (cv_show_latency.int_ () == 1) { if (cv_show_latency.as <int> () == 1) {
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*bot", "1"); engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*bot", "1");
} }
auto avatar = conf.getRandomAvatar (); auto avatar = conf.getRandomAvatar ();
if (cv_show_avatars.bool_ () && !avatar.empty ()) { if (cv_show_avatars && !avatar.empty ()) {
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*sid", avatar.chars ()); engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*sid", avatar.chars ());
} }
} }
@ -1124,32 +1124,32 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
m_moneyAmount = 0; m_moneyAmount = 0;
m_logotypeIndex = conf.getRandomLogoIndex (); m_logotypeIndex = conf.getRandomLogoIndex ();
if (cv_rotate_bots.bool_ ()) { if (cv_rotate_bots) {
m_stayTime = game.time () + rg.get (cv_rotate_stay_min.float_ (), cv_rotate_stay_max.float_ ()); m_stayTime = game.time () + rg (cv_rotate_stay_min.as <float> (), cv_rotate_stay_max.as <float> ());
} }
else { else {
m_stayTime = game.time () + kInfiniteDistance; m_stayTime = game.time () + kInfiniteDistance;
} }
// assign how talkative this bot will be // assign how talkative this bot will be
m_sayTextBuffer.chatDelay = rg.get (3.8f, 10.0f); m_sayTextBuffer.chatDelay = rg (3.8f, 10.0f);
m_sayTextBuffer.chatProbability = rg.get (10, 100); m_sayTextBuffer.chatProbability = rg (10, 100);
m_isAlive = false; m_isAlive = false;
m_weaponBurstMode = BurstMode::Off; m_weaponBurstMode = BurstMode::Off;
m_difficulty = cr::clamp (static_cast <Difficulty> (difficulty), Difficulty::Noob, Difficulty::Expert); m_difficulty = cr::clamp (static_cast <Difficulty> (difficulty), Difficulty::Noob, Difficulty::Expert);
auto minDifficulty = cv_difficulty_min.int_ (); auto minDifficulty = cv_difficulty_min.as <int> ();
auto maxDifficulty = cv_difficulty_max.int_ (); auto maxDifficulty = cv_difficulty_max.as <int> ();
// if we're have min/max difficulty specified, choose value from they // if we're have min/max difficulty specified, choose value from they
if (minDifficulty != Difficulty::Invalid && maxDifficulty != Difficulty::Invalid) { if (minDifficulty != Difficulty::Invalid && maxDifficulty != Difficulty::Invalid) {
if (maxDifficulty > minDifficulty) { if (maxDifficulty > minDifficulty) {
cr::swap (maxDifficulty, minDifficulty); cr::swap (maxDifficulty, minDifficulty);
} }
m_difficulty = rg.get (minDifficulty, maxDifficulty); m_difficulty = rg (minDifficulty, maxDifficulty);
} }
m_basePing = rg.get (cv_ping_base_min.int_ (), cv_ping_base_max.int_ ()); m_basePing = rg (cv_ping_base_min.as <int> (), cv_ping_base_max.as <int> ());
m_previousThinkTime = game.time () - 0.1f; m_previousThinkTime = game.time () - 0.1f;
m_frameInterval = game.time (); m_frameInterval = game.time ();
@ -1158,26 +1158,26 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
m_kpdRatio = 0.0f; m_kpdRatio = 0.0f;
// stuff from jk_botti // stuff from jk_botti
m_playServerTime = 60.0f * rg.get (30.0f, 240.0f); m_playServerTime = 60.0f * rg (30.0f, 240.0f);
m_joinServerTime = plat.seconds () - m_playServerTime * rg.get (0.2f, 0.8f); m_joinServerTime = plat.seconds () - m_playServerTime * rg (0.2f, 0.8f);
switch (personality) { switch (personality) {
case 1: case 1:
m_personality = Personality::Rusher; m_personality = Personality::Rusher;
m_baseAgressionLevel = rg.get (0.7f, 1.0f); m_baseAgressionLevel = rg (0.7f, 1.0f);
m_baseFearLevel = rg.get (0.0f, 0.4f); m_baseFearLevel = rg (0.0f, 0.4f);
break; break;
case 2: case 2:
m_personality = Personality::Careful; m_personality = Personality::Careful;
m_baseAgressionLevel = rg.get (0.2f, 0.5f); m_baseAgressionLevel = rg (0.2f, 0.5f);
m_baseFearLevel = rg.get (0.7f, 1.0f); m_baseFearLevel = rg (0.7f, 1.0f);
break; break;
default: default:
m_personality = Personality::Normal; m_personality = Personality::Normal;
m_baseAgressionLevel = rg.get (0.4f, 0.7f); m_baseAgressionLevel = rg (0.4f, 0.7f);
m_baseFearLevel = rg.get (0.4f, 0.7f); m_baseFearLevel = rg (0.4f, 0.7f);
break; break;
} }
@ -1187,7 +1187,7 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
m_currentWeapon = 0; // current weapon is not assigned at start m_currentWeapon = 0; // current weapon is not assigned at start
m_weaponType = WeaponType::None; // current weapon type is not assigned at start m_weaponType = WeaponType::None; // current weapon type is not assigned at start
m_voicePitch = rg.get (80, 115); // assign voice pitch m_voicePitch = rg (80, 115); // assign voice pitch
// copy them over to the temp level variables // copy them over to the temp level variables
m_agressionLevel = m_baseAgressionLevel; m_agressionLevel = m_baseAgressionLevel;
@ -1220,8 +1220,8 @@ float Bot::getConnectionTime () {
const auto current = plat.seconds (); const auto current = plat.seconds ();
if (current - m_joinServerTime > m_playServerTime || current - m_joinServerTime <= 0.0f) { if (current - m_joinServerTime > m_playServerTime || current - m_joinServerTime <= 0.0f) {
m_playServerTime = 60.0f * rg.get (30.0f, 240.0f); m_playServerTime = 60.0f * rg (30.0f, 240.0f);
m_joinServerTime = current - m_playServerTime * rg.get (0.2f, 0.8f); m_joinServerTime = current - m_playServerTime * rg (0.2f, 0.8f);
} }
return current - m_joinServerTime; return current - m_joinServerTime;
} }
@ -1283,7 +1283,7 @@ bool BotManager::isTeamStacked (int team) {
if (team != Team::CT && team != Team::Terrorist) { if (team != Team::CT && team != Team::Terrorist) {
return false; return false;
} }
const int limitTeams = mp_limitteams.int_ (); const int limitTeams = mp_limitteams.as <int> ();
if (!limitTeams) { if (!limitTeams) {
return false; return false;
@ -1304,7 +1304,7 @@ void BotManager::erase (Bot *bot) {
continue; continue;
} }
if (!bot->m_kickedByRotation && cv_save_bots_names.bool_ ()) { if (!bot->m_kickedByRotation && cv_save_bots_names) {
m_saveBotNames.emplaceLast (bot->pev->netname.str ()); m_saveBotNames.emplaceLast (bot->pev->netname.str ());
} }
bot->markStale (); bot->markStale ();
@ -1321,7 +1321,7 @@ void BotManager::handleDeath (edict_t *killer, edict_t *victim) {
const auto killerTeam = game.getRealTeam (killer); const auto killerTeam = game.getRealTeam (killer);
const auto victimTeam = game.getRealTeam (victim); const auto victimTeam = game.getRealTeam (victim);
if (cv_radio_mode.int_ () == 2) { if (cv_radio_mode.as <int> () == 2) {
// need to send congrats on well placed shot // need to send congrats on well placed shot
for (const auto &notify : bots) { for (const auto &notify : bots) {
if (notify->m_isAlive if (notify->m_isAlive
@ -1443,14 +1443,14 @@ void Bot::newRound () {
m_preventFlashing = 0.0f; m_preventFlashing = 0.0f;
m_timeTeamOrder = 0.0f; m_timeTeamOrder = 0.0f;
m_askCheckTime = rg.get (30.0f, 90.0f); m_askCheckTime = rg (30.0f, 90.0f);
m_minSpeed = 260.0f; m_minSpeed = 260.0f;
m_prevSpeed = 0.0f; m_prevSpeed = 0.0f;
m_prevVelocity = 0.0f; m_prevVelocity = 0.0f;
m_prevOrigin = Vector (kInfiniteDistance, kInfiniteDistance, kInfiniteDistance); m_prevOrigin = Vector (kInfiniteDistance, kInfiniteDistance, kInfiniteDistance);
m_prevTime = game.time (); m_prevTime = game.time ();
m_lookUpdateTime = game.time (); m_lookUpdateTime = game.time ();
m_changeViewTime = game.time () + (rg.chance (25) ? mp_freezetime.float_ () : 0.0f); m_changeViewTime = game.time () + (rg.chance (25) ? mp_freezetime.as <float> () : 0.0f);
m_aimErrorTime = game.time (); m_aimErrorTime = game.time ();
m_viewDistance = Frustum::kMaxViewDistance; m_viewDistance = Frustum::kMaxViewDistance;
@ -1555,8 +1555,8 @@ void Bot::newRound () {
m_flashLevel = 100; m_flashLevel = 100;
m_checkDarkTime = game.time (); m_checkDarkTime = game.time ();
m_knifeAttackTime = game.time () + rg.get (1.3f, 2.6f); m_knifeAttackTime = game.time () + rg (1.3f, 2.6f);
m_nextBuyTime = game.time () + rg.get (0.6f, 2.0f); m_nextBuyTime = game.time () + rg (0.6f, 2.0f);
m_buyPending = false; m_buyPending = false;
m_inBombZone = false; m_inBombZone = false;
@ -1568,7 +1568,7 @@ void Bot::newRound () {
m_shieldCheckTime = 0.0f; m_shieldCheckTime = 0.0f;
m_zoomCheckTime = 0.0f; m_zoomCheckTime = 0.0f;
m_strafeSetTime = 0.0f; m_strafeSetTime = 0.0f;
m_combatStrafeDir = Dodge::None; m_dodgeStrafeDir = Dodge::None;
m_fightStyle = Fight::None; m_fightStyle = Fight::None;
m_lastFightStyleCheck = 0.0f; m_lastFightStyleCheck = 0.0f;
m_stuckTimestamp = 0.0f; m_stuckTimestamp = 0.0f;
@ -1583,7 +1583,7 @@ void Bot::newRound () {
m_defendHostage = false; m_defendHostage = false;
m_headedTime = 0.0f; m_headedTime = 0.0f;
m_timeLogoSpray = game.time () + rg.get (5.0f, 30.0f); m_timeLogoSpray = game.time () + rg (5.0f, 30.0f);
m_spawnTime = game.time (); m_spawnTime = game.time ();
m_lastChatTime = game.time (); m_lastChatTime = game.time ();
@ -1600,8 +1600,8 @@ void Bot::newRound () {
m_ignoredBreakable.clear (); m_ignoredBreakable.clear ();
// ignore enemies for some time if needed // ignore enemies for some time if needed
if (cv_ignore_enemies_after_spawn_time.float_ () > 0.0f) { if (cv_ignore_enemies_after_spawn_time.as <float> () > 0.0f) {
m_enemyIgnoreTimer = game.time () + cv_ignore_enemies_after_spawn_time.float_ (); m_enemyIgnoreTimer = game.time () + cv_ignore_enemies_after_spawn_time.as <float> ();
} }
else { else {
m_enemyIgnoreTimer = 0.0f; m_enemyIgnoreTimer = 0.0f;
@ -1620,11 +1620,11 @@ void Bot::newRound () {
if (rg.chance (50)) { if (rg.chance (50)) {
pushChatterMessage (Chatter::NewRound); pushChatterMessage (Chatter::NewRound);
} }
auto thinkFps = cr::clamp (cv_think_fps.float_ (), 30.0f, 90.0f); auto thinkFps = cr::clamp (cv_think_fps.as <float> (), 30.0f, 90.0f);
auto updateInterval = 1.0f / thinkFps; auto updateInterval = 1.0f / thinkFps;
if (game.is (GameFlags::Xash3D)) { if (game.is (GameFlags::Xash3D)) {
if (cv_think_fps_disable.bool_ ()) { if (cv_think_fps_disable) {
updateInterval = 0.0f; updateInterval = 0.0f;
} }
else if (thinkFps < 50) { else if (thinkFps < 50) {
@ -1657,7 +1657,7 @@ void Bot::resetPathSearchType () {
} }
// if debug goal - set the fastest // if debug goal - set the fastest
if (cv_debug_goal.int_ () != kInvalidNodeIndex) { if (cv_debug_goal.as <int> () != kInvalidNodeIndex) {
m_pathType = FindPath::Fast; m_pathType = FindPath::Fast;
} }
@ -1749,7 +1749,7 @@ void Bot::updateTeamJoin () {
m_startAction = BotMsg::None; // switch back to idle m_startAction = BotMsg::None; // switch back to idle
if (m_wantedTeam == -1) { if (m_wantedTeam == -1) {
char teamJoin = cv_join_team.str ()[0]; char teamJoin = cv_join_team.as <StringRef> ()[0];
if (teamJoin == 'C' || teamJoin == 'c') { if (teamJoin == 'C' || teamJoin == 'c') {
m_wantedTeam = 2; m_wantedTeam = 2;
@ -1772,7 +1772,7 @@ void Bot::updateTeamJoin () {
m_wantedTeam = 1; m_wantedTeam = 1;
} }
else { else {
m_wantedTeam = rg.get (1, 2); m_wantedTeam = rg (1, 2);
} }
} }
@ -1788,16 +1788,16 @@ void Bot::updateTeamJoin () {
// setup enforced skin based on selected team // setup enforced skin based on selected team
if (m_wantedTeam == 1 || botTeam == Team::Terrorist) { if (m_wantedTeam == 1 || botTeam == Team::Terrorist) {
enforcedSkin = cv_botskin_t.int_ (); enforcedSkin = cv_botskin_t.as <int> ();
} }
else if (m_wantedTeam == 2 || botTeam == Team::CT) { else if (m_wantedTeam == 2 || botTeam == Team::CT) {
enforcedSkin = cv_botskin_ct.int_ (); enforcedSkin = cv_botskin_ct.as <int> ();
} }
enforcedSkin = cr::clamp (enforcedSkin, 0, maxChoice); enforcedSkin = cr::clamp (enforcedSkin, 0, maxChoice);
// try to choice manually // try to choice manually
if (m_wantedSkin < 1 || m_wantedSkin > maxChoice) { if (m_wantedSkin < 1 || m_wantedSkin > maxChoice) {
m_wantedSkin = rg.get (1, maxChoice); // use random if invalid m_wantedSkin = rg (1, maxChoice); // use random if invalid
} }
// and set enforced if any // and set enforced if any
@ -1852,7 +1852,7 @@ void BotManager::captureChatRadio (StringRef cmd, StringRef arg, edict_t *ent) {
// check if this player alive, and issue something // check if this player alive, and issue something
if ((target.flags & ClientFlags::Alive) && target.radio != 0 && cmd.startsWith ("menuselect")) { if ((target.flags & ClientFlags::Alive) && target.radio != 0 && cmd.startsWith ("menuselect")) {
auto radioCommand = arg.int_ (); auto radioCommand = arg.as <int> ();
if (radioCommand != 0) { if (radioCommand != 0) {
radioCommand += 10 * (target.radio - 1); radioCommand += 10 * (target.radio - 1);
@ -1872,7 +1872,7 @@ void BotManager::captureChatRadio (StringRef cmd, StringRef arg, edict_t *ent) {
target.radio = 0; target.radio = 0;
} }
else if (cmd.startsWith ("radio")) { else if (cmd.startsWith ("radio")) {
target.radio = cmd.substr (5).int_ (); target.radio = cmd.substr (5).as <int> ();
} }
} }
@ -1890,7 +1890,7 @@ void BotManager::notifyBombDefuse () {
&& task != Task::DefuseBomb && task != Task::DefuseBomb
&& task != Task::EscapeFromBomb) { && task != Task::EscapeFromBomb) {
if (bot->m_team == Team::Terrorist && bot->pev->origin.distanceSq (bombPos) < cr::sqrf (384.0f)) { if (bot->m_team == Team::Terrorist && bot->pev->origin.distanceSq (bombPos) < cr::sqrf (512.0f)) {
bot->clearSearchNodes (); bot->clearSearchNodes ();
bot->m_pathType = FindPath::Fast; bot->m_pathType = FindPath::Fast;
@ -1955,7 +1955,7 @@ void BotManager::updateInterestingEntities () {
m_interestingEntities.push (e); m_interestingEntities.push (e);
} }
if (cv_attack_monsters.bool_ () && util.isMonster (e)) { if (cv_attack_monsters && util.isMonster (e)) {
m_interestingEntities.push (e); m_interestingEntities.push (e);
} }
@ -2012,7 +2012,7 @@ void BotManager::selectLeaders (int team, bool reset) {
// terrorist carrying a bomb needs to have some company // terrorist carrying a bomb needs to have some company
if (rg.chance (75)) { if (rg.chance (75)) {
if (cv_radio_mode.int_ () == 2) { if (cv_radio_mode.as <int> () == 2) {
bot->pushChatterMessage (Chatter::GoingToPlantBomb); bot->pushChatterMessage (Chatter::GoingToPlantBomb);
} }
else { else {
@ -2098,13 +2098,13 @@ void BotManager::initRound () {
practice.update (); // update practice data on round start practice.update (); // update practice data on round start
// calculate the round mid/end in world time // calculate the round mid/end in world time
m_timeRoundStart = game.time () + mp_freezetime.float_ (); m_timeRoundStart = game.time () + mp_freezetime.as <float> ();
m_timeRoundMid = m_timeRoundStart + mp_roundtime.float_ () * 60.0f * 0.5f; m_timeRoundMid = m_timeRoundStart + mp_roundtime.as <float> () * 60.0f * 0.5f;
m_timeRoundEnd = m_timeRoundStart + mp_roundtime.float_ () * 60.0f; m_timeRoundEnd = m_timeRoundStart + mp_roundtime.as <float> () * 60.0f;
} }
void BotManager::setBombPlanted (bool isPlanted) { void BotManager::setBombPlanted (bool isPlanted) {
if (cv_ignore_objectives.bool_ ()) { if (cv_ignore_objectives) {
m_bombPlanted = false; m_bombPlanted = false;
return; return;
} }

View file

@ -43,7 +43,7 @@ void MessageDispatcher::netMsgTextMsg () {
// set balance for all players // set balance for all players
bots.forEach ([] (Bot *bot) { bots.forEach ([] (Bot *bot) {
bot->m_moneyAmount = mp_startmoney.int_ (); bot->m_moneyAmount = mp_startmoney.as <int> ();
return false; return false;
}); });
@ -63,7 +63,7 @@ void MessageDispatcher::netMsgTextMsg () {
// clear only camp tasks // clear only camp tasks
notify->clearTask (Task::Camp); notify->clearTask (Task::Camp);
if (cv_radio_mode.int_ () == 2 && rg.chance (55) && notify->m_team == Team::CT) { if (cv_radio_mode.as <int> () == 2 && rg.chance (55) && notify->m_team == Team::CT) {
notify->pushChatterMessage (Chatter::WhereIsTheC4); notify->pushChatterMessage (Chatter::WhereIsTheC4);
} }
} }

View file

@ -163,11 +163,11 @@ int Bot::findBestGoal () {
} }
} }
const float goalDesire = rg.get (0.0f, 100.0f) + offensive; const float goalDesire = rg (0.0f, 100.0f) + offensive;
const float forwardDesire = rg.get (0.0f, 100.0f) + offensive; const float forwardDesire = rg (0.0f, 100.0f) + offensive;
const float backoffDesire = rg.get (0.0f, 100.0f) + defensive; const float backoffDesire = rg (0.0f, 100.0f) + defensive;
float campDesire = rg.get (0.0f, 100.0f) + defensive; float campDesire = rg (0.0f, 100.0f) + defensive;
if (!usesCampGun ()) { if (!usesCampGun ()) {
campDesire *= 0.5f; campDesire *= 0.5f;
@ -226,7 +226,7 @@ int Bot::findBestGoalWhenBombAction () {
result = findDefendNode (bombOrigin); result = findDefendNode (bombOrigin);
const Path &path = graph[result]; const Path &path = graph[result];
const float bombTimer = mp_c4timer.float_ (); const float bombTimer = mp_c4timer.as <float> ();
const float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin); const float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
if (timeMidBlowup > game.time ()) { if (timeMidBlowup > game.time ()) {
@ -334,7 +334,7 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offensive) {
// rusher bots does not care any danger (idea from pbmm) // rusher bots does not care any danger (idea from pbmm)
if (m_personality == Personality::Rusher) { if (m_personality == Personality::Rusher) {
const auto randomGoal = goalChoices[rg.get (0, 3)]; const auto randomGoal = goalChoices[rg (0, 3)];
if (graph.exists (randomGoal)) { if (graph.exists (randomGoal)) {
return m_chosenGoalIndex = randomGoal; return m_chosenGoalIndex = randomGoal;
@ -454,7 +454,7 @@ void Bot::ignoreCollision () {
} }
void Bot::doPlayerAvoidance (const Vector &normal) { void Bot::doPlayerAvoidance (const Vector &normal) {
if (cv_has_team_semiclip.bool_ () || game.is (GameFlags::FreeForAll)) { if (cv_has_team_semiclip || game.is (GameFlags::FreeForAll)) {
return; // no player avoiding when with semiclip plugin return; // no player avoiding when with semiclip plugin
} }
@ -517,7 +517,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
// is player that near now or in future that we need to steer away? // is player that near now or in future that we need to steer away?
if (movedDistanceSq <= cr::sqrf (64.0f) || (distanceSq <= cr::sqrf (72.0f) && nextFrameDistanceSq < distanceSq)) { if (movedDistanceSq <= cr::sqrf (64.0f) || (distanceSq <= cr::sqrf (72.0f) && nextFrameDistanceSq < distanceSq)) {
auto dir = (pev->origin - m_hindrance->v.origin).normalize2d_apx (); const auto &dir = (pev->origin - m_hindrance->v.origin).normalize2d_apx ();
// to start strafing, we have to first figure out if the target is on the left side or right side // to start strafing, we have to first figure out if the target is on the left side or right side
if ((dir | right.normalize2d_apx ()) > 0.0f) { if ((dir | right.normalize2d_apx ()) > 0.0f) {
@ -570,7 +570,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
// not stuck? // not stuck?
if (!m_isStuck) { if (!m_isStuck) {
if (m_probeTime + rg.get (0.75f, 1.15f) < game.time ()) { if (m_probeTime + rg (0.75f, 1.15f) < game.time ()) {
resetCollision (); // reset collision memory if not being stuck for 0.5 secs resetCollision (); // reset collision memory if not being stuck for 0.5 secs
} }
else { else {
@ -928,7 +928,7 @@ bool Bot::updateNavigation () {
// pressing the jump button gives the illusion of the bot actual jumping. // pressing the jump button gives the illusion of the bot actual jumping.
if (isOnFloor () || isOnLadder ()) { if (isOnFloor () || isOnLadder ()) {
if (m_desiredVelocity.length2d () > 0.0f) { if (m_desiredVelocity.length2d () > 0.0f) {
pev->velocity = m_desiredVelocity + m_desiredVelocity * m_frameInterval; pev->velocity = m_desiredVelocity;
} }
else { else {
auto feet = pev->origin + pev->mins; auto feet = pev->origin + pev->mins;
@ -965,12 +965,12 @@ bool Bot::updateNavigation () {
// cool down a little if next path after current will be jump // cool down a little if next path after current will be jump
if (m_jumpSequence) { if (m_jumpSequence) {
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg.get (0.75, 1.2f) + m_frameInterval, false); startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg (0.75f, 1.2f) + m_frameInterval, false);
m_jumpSequence = false; m_jumpSequence = false;
} }
} }
} }
else if (!cv_jasonmode.bool_ () && usesKnife () && isOnFloor () && getCurrentTaskId () != Task::EscapeFromBomb) { else if (!cv_jasonmode && usesKnife () && isOnFloor () && getCurrentTaskId () != Task::EscapeFromBomb) {
selectBestWeapon (); selectBestWeapon ();
} }
} }
@ -1031,7 +1031,7 @@ bool Bot::updateNavigation () {
&& cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f && cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f
&& (client.ent->v.movetype == MOVETYPE_FLY)) { && (client.ent->v.movetype == MOVETYPE_FLY)) {
const auto numPreviousNode = rg.get (0, 2); const auto numPreviousNode = rg (0, 2);
for (int i = 0; i < numPreviousNode; ++i) { for (int i = 0; i < numPreviousNode; ++i) {
if (graph.exists (m_previousNodes[i]) && (graph[m_previousNodes[i]].flags & NodeFlag::Ladder)) { if (graph.exists (m_previousNodes[i]) && (graph[m_previousNodes[i]].flags & NodeFlag::Ladder)) {
@ -1115,7 +1115,7 @@ bool Bot::updateNavigation () {
util.findNearestPlayer (reinterpret_cast <void **> (&nearest), ent (), 192.0f, false, false, true, true, false); util.findNearestPlayer (reinterpret_cast <void **> (&nearest), ent (), 192.0f, false, false, true, true, false);
// check if enemy is penetrable // check if enemy is penetrable
if (util.isAlive (nearest) && isPenetrableObstacle (nearest->v.origin) && !cv_ignore_enemies.bool_ ()) { if (util.isAlive (nearest) && isPenetrableObstacle (nearest->v.origin) && !cv_ignore_enemies) {
m_seeEnemyTime = game.time (); m_seeEnemyTime = game.time ();
m_states |= Sense::SeeingEnemy | Sense::SuspectEnemy; m_states |= Sense::SeeingEnemy | Sense::SuspectEnemy;
@ -1137,7 +1137,7 @@ bool Bot::updateNavigation () {
} }
} }
float desiredDistanceSq = cr::sqrf (4.0f); float desiredDistanceSq = cr::sqrf (8.0f);
const float nodeDistanceSq = pev->origin.distanceSq (m_pathOrigin); const float nodeDistanceSq = pev->origin.distanceSq (m_pathOrigin);
// initialize the radius for a special node type, where the node is considered to be reached // initialize the radius for a special node type, where the node is considered to be reached
@ -1145,7 +1145,7 @@ bool Bot::updateNavigation () {
desiredDistanceSq = cr::sqrf (50.0f); desiredDistanceSq = cr::sqrf (50.0f);
} }
else if (isDucking () || (m_pathFlags & NodeFlag::Goal)) { else if (isDucking () || (m_pathFlags & NodeFlag::Goal)) {
desiredDistanceSq = cr::sqrf (12.0f); desiredDistanceSq = cr::sqrf (9.0f);
// on cs_ maps goals are usually hostages, so increase reachability distance for them, they (hostages) picked anyway // on cs_ maps goals are usually hostages, so increase reachability distance for them, they (hostages) picked anyway
if (game.mapIs (MapFlags::HostageRescue) && (m_pathFlags & NodeFlag::Goal)) { if (game.mapIs (MapFlags::HostageRescue) && (m_pathFlags & NodeFlag::Goal)) {
@ -1155,17 +1155,14 @@ bool Bot::updateNavigation () {
else if (m_pathFlags & NodeFlag::Ladder) { else if (m_pathFlags & NodeFlag::Ladder) {
desiredDistanceSq = cr::sqrf (16.0f); desiredDistanceSq = cr::sqrf (16.0f);
} }
else if (m_pathFlags & NodeFlag::Camp) {
desiredDistanceSq = cr::sqrf (32.0f);
}
else if (m_currentTravelFlags & PathFlag::Jump) { else if (m_currentTravelFlags & PathFlag::Jump) {
desiredDistanceSq = 0.0f; desiredDistanceSq = 0.0f;
} }
else if (m_path->number == cv_debug_goal.int_ ()) { else if (m_path->number == cv_debug_goal.as <int> ()) {
desiredDistanceSq = 0.0f; desiredDistanceSq = 0.0f;
} }
else if (isOccupiedNode (m_path->number)) { else if (isOccupiedNode (m_path->number)) {
desiredDistanceSq = cr::sqrf (120.0f); desiredDistanceSq = cr::sqrf (148.0f);
} }
else { else {
desiredDistanceSq = cr::max (cr::sqrf (m_path->radius), desiredDistanceSq); desiredDistanceSq = cr::max (cr::sqrf (m_path->radius), desiredDistanceSq);
@ -1180,7 +1177,7 @@ bool Bot::updateNavigation () {
} }
// needs precise placement - check if we get past the point // needs precise placement - check if we get past the point
if (desiredDistanceSq < cr::sqrf (16.0f) if (desiredDistanceSq < cr::sqrf (22.0f)
&& nodeDistanceSq < cr::sqrf (30.0f) && nodeDistanceSq < cr::sqrf (30.0f)
&& m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) >= nodeDistanceSq) { && m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) >= nodeDistanceSq) {
@ -1720,10 +1717,10 @@ bool Bot::findNextBestNode () {
// choice from found // choice from found
if (lessIndex[2] != kInvalidNodeIndex) { if (lessIndex[2] != kInvalidNodeIndex) {
index = rg.get (0, 2); index = rg (0, 2);
} }
else if (lessIndex[1] != kInvalidNodeIndex) { else if (lessIndex[1] != kInvalidNodeIndex) {
index = rg.get (0, 1); index = rg (0, 1);
} }
else if (lessIndex[0] != kInvalidNodeIndex) { else if (lessIndex[0] != kInvalidNodeIndex) {
index = 0; index = 0;
@ -1739,7 +1736,13 @@ bool Bot::findNextBestNode () {
if (selected == kInvalidNodeIndex) { if (selected == kInvalidNodeIndex) {
selected = findNearestNode (); selected = findNearestNode ();
} }
// mark bot as searching for new best next node
if (selected != kInvalidNodeIndex) {
m_lostReachableNodeTimer.start (pev->origin.distanceSq (graph[selected].origin) / cr::sqrf (pev->maxspeed) * 4.0f);
}
changeNodeIndex (selected); changeNodeIndex (selected);
return true; return true;
} }
@ -1806,7 +1809,7 @@ void Bot::findValidNode () {
int Bot::changeNodeIndex (int index) { int Bot::changeNodeIndex (int index) {
if (index == kInvalidNodeIndex) { if (index == kInvalidNodeIndex) {
return 0; return kInvalidNodeIndex;
} }
m_previousNodes[4] = m_previousNodes[3]; m_previousNodes[4] = m_previousNodes[3];
m_previousNodes[3] = m_previousNodes[2]; m_previousNodes[3] = m_previousNodes[2];
@ -2077,7 +2080,7 @@ int Bot::findDefendNode (const Vector &origin) {
break; break;
} }
} }
return nodeIndex[rg.get (0, (index - 1) / 2)]; return nodeIndex[rg (0, (index - 1) / 2)];
} }
int Bot::findCoverNode (float maxDistance) { int Bot::findCoverNode (float maxDistance) {
@ -2334,8 +2337,8 @@ bool Bot::advanceMovement () {
} }
if (m_baseAgressionLevel < kills && hasPrimaryWeapon ()) { if (m_baseAgressionLevel < kills && hasPrimaryWeapon ()) {
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (static_cast <float> (m_difficulty / 2), static_cast <float> (m_difficulty)) * 5.0f, true); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (static_cast <float> (m_difficulty / 2), static_cast <float> (m_difficulty)) * 5.0f, true);
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, findDefendNode (graph[nextIndex].origin), game.time () + rg.get (3.0f, 10.0f), true); startTask (Task::MoveToPosition, TaskPri::MoveToPosition, findDefendNode (graph[nextIndex].origin), game.time () + rg (3.0f, 10.0f), true);
} }
} }
else if (bots.canPause () && !isOnLadder () && !isInWater () && !m_currentTravelFlags && isOnFloor ()) { else if (bots.canPause () && !isOnLadder () && !isInWater () && !m_currentTravelFlags && isOnFloor ()) {
@ -2366,7 +2369,7 @@ bool Bot::advanceMovement () {
for (const auto &link : m_path->links) { for (const auto &link : m_path->links) {
if (link.index == destIndex) { if (link.index == destIndex) {
m_currentTravelFlags = link.flags; m_currentTravelFlags = link.flags;
m_desiredVelocity = link.velocity - link.velocity * m_frameInterval; m_desiredVelocity = link.velocity;
m_jumpFinished = false; m_jumpFinished = false;
isCurrentJump = true; isCurrentJump = true;
@ -2467,7 +2470,7 @@ void Bot::setPathOrigin () {
Vector orgs[kMaxAlternatives] {}; Vector orgs[kMaxAlternatives] {};
for (int i = 0; i < kMaxAlternatives; ++i) { for (int i = 0; i < kMaxAlternatives; ++i) {
orgs[i] = m_pathOrigin + Vector (rg.get (-m_path->radius, m_path->radius), rg.get (-m_path->radius, m_path->radius), 0.0f); orgs[i] = m_pathOrigin + Vector (rg (-m_path->radius, m_path->radius), rg (-m_path->radius, m_path->radius), 0.0f);
} }
float nearestDistanceSq = kInfiniteDistance; float nearestDistanceSq = kInfiniteDistance;
@ -2487,7 +2490,7 @@ void Bot::setPathOrigin () {
} }
if (nearestIndex == kInvalidNodeIndex) { if (nearestIndex == kInvalidNodeIndex) {
m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius); m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg (-90.0f, 90.0f)), 0.0f).forward () * rg (0.0f, m_path->radius);
} }
} }
@ -2938,7 +2941,7 @@ bool Bot::isDeadlyMove (const Vector &to) {
TraceResult tr {}; TraceResult tr {};
constexpr auto kUnitsDown = 1000.0f; constexpr auto kUnitsDown = 1000.0f;
constexpr auto kFallLimit = 150.0f; constexpr auto kFallLimit = 160.0f;
Vector check = to, down = to; Vector check = to, down = to;
down.z -= kUnitsDown; // straight down 1000 units down.z -= kUnitsDown; // straight down 1000 units
@ -2981,7 +2984,7 @@ bool Bot::isNotSafeToMove (const Vector &to) {
// simplified version of isDeadlyMove() just for combat movement checking // simplified version of isDeadlyMove() just for combat movement checking
constexpr auto kUnitsDown = 1000.0f; constexpr auto kUnitsDown = 1000.0f;
constexpr auto kFallLimit = 150.0f; constexpr auto kFallLimit = 160.0f;
TraceResult tr {}; TraceResult tr {};
game.testLine (to, to + Vector { 0.0f, 0.0f, -kUnitsDown }, TraceIgnore::Monsters, ent (), &tr); game.testLine (to, to + Vector { 0.0f, 0.0f, -kUnitsDown }, TraceIgnore::Monsters, ent (), &tr);
@ -3031,7 +3034,7 @@ int Bot::getRandomCampDir () {
count--; count--;
if (count >= 0) { if (count >= 0) {
return indices[rg.get (0, count)]; return indices[rg (0, count)];
} }
return graph.random (); return graph.random ();
} }
@ -3146,33 +3149,22 @@ bool Bot::isReachableNode (int index) {
if (!graph.exists (index)) { if (!graph.exists (index)) {
return false; return false;
} }
const Vector &src = pev->origin; const auto &src = pev->origin;
const Vector &dst = graph[index].origin; const auto &dst = graph[index].origin;
// is the destination close enough? // is the destination close enough?
if (dst.distanceSq (src) >= cr::sqrf (400.0f)) { if (dst.distanceSq (src) > cr::sqrf (600.0f)) {
return false; return false;
} }
// some one seems to camp at this node
if (isOccupiedNode (index, true)) {
return false;
}
TraceResult tr {};
game.testHull (src, dst, TraceIgnore::Monsters, head_hull, ent (), &tr);
// if node is visible from current position (even behind head)...
if (tr.flFraction >= 1.0f && !tr.fStartSolid) {
// it's should be not a problem to reach node inside water... // it's should be not a problem to reach node inside water...
if (pev->waterlevel == 2 || pev->waterlevel == 3) { if (pev->waterlevel == 2 || pev->waterlevel == 3) {
return true; return true;
} }
const float ladderDistSq = dst.distanceSq2d (src); const float distanceSq2d = dst.distanceSq2d (src);
// check for ladder // check for ladder
const bool nonLadder = !(graph[index].flags & NodeFlag::Ladder) || ladderDistSq > cr::sqrf (16.0f); const bool nonLadder = !(graph[index].flags & NodeFlag::Ladder) || distanceSq2d > cr::sqrf (16.0f);
// is dest node higher than src? (62 is max jump height) // is dest node higher than src? (62 is max jump height)
if (nonLadder && dst.z > src.z + 62.0f) { if (nonLadder && dst.z > src.z + 62.0f) {
@ -3183,9 +3175,17 @@ bool Bot::isReachableNode (int index) {
if (nonLadder && dst.z < src.z - 100.0f) { if (nonLadder && dst.z < src.z - 100.0f) {
return false; // can't reach this one return false; // can't reach this one
} }
return true;
// some one seems to camp at this node
if (isOccupiedNode (index, true)) {
return false; // can't reach this one
} }
return false;
TraceResult tr {};
game.testLine (src, dst, TraceIgnore::Monsters, ent (), &tr);
// if node is visible from current position (even behind head)...
return tr.flFraction >= 1.0f;
} }
bool Bot::isOnLadderPath () { bool Bot::isOnLadderPath () {
@ -3309,7 +3309,7 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) {
// fallback to shortest path // fallback to shortest path
findShortestPath (srcIndex, destIndex); // A* found no path, try floyd pathfinder instead findShortestPath (srcIndex, destIndex); // A* found no path, try floyd pathfinder instead
if (cv_debug.bool_ ()) { if (cv_debug) {
fprintf (stderr, "A* Search for bot \"%s\" has failed. Falling back to shortest-path algorithm. Seems to be graph is broken.\n", pev->netname.chars ()); fprintf (stderr, "A* Search for bot \"%s\" has failed. Falling back to shortest-path algorithm. Seems to be graph is broken.\n", pev->netname.chars ());
} }
break; break;

View file

@ -117,7 +117,7 @@ float Heuristic::hfunctionPathDist (int index, int, int goalIndex) {
const float y = start.origin.y - goal.origin.y; const float y = start.origin.y - goal.origin.y;
const float z = start.origin.z - goal.origin.z; const float z = start.origin.z - goal.origin.z;
switch (cv_path_heuristic_mode.int_ ()) { switch (cv_path_heuristic_mode.as <int> ()) {
case 0: case 0:
return cr::max (cr::max (cr::abs (x), cr::abs (y)), cr::abs (z)); // chebyshev distance return cr::max (cr::max (cr::abs (x), cr::abs (y)), cr::abs (z)); // chebyshev distance
@ -255,7 +255,7 @@ AStarResult AStarAlgo::find (int botTeam, int srcIndex, int destIndex, NodeAdder
m_routeQue.clear (); m_routeQue.clear ();
m_routeQue.emplace (srcIndex, srcRoute->g); m_routeQue.emplace (srcIndex, srcRoute->g);
const bool postSmoothPath = cv_path_astar_post_smooth.bool_ () && vistab.isReady (); const bool postSmoothPath = cv_path_astar_post_smooth && vistab.isReady ();
// always clear constructed path // always clear constructed path
m_constructedPath.clear (); m_constructedPath.clear ();
@ -264,8 +264,8 @@ AStarResult AStarAlgo::find (int botTeam, int srcIndex, int destIndex, NodeAdder
auto rsRandomizer = 1.0f; auto rsRandomizer = 1.0f;
// randomize path on round start now and then // randomize path on round start now and then
if (cv_path_randomize_on_round_start.bool_ () && bots.getRoundStartTime () + 4.0f > game.time ()) { if (cv_path_randomize_on_round_start && bots.getRoundStartTime () + 4.0f > game.time ()) {
rsRandomizer = rg.get (0.5f, static_cast <float> (botTeam) * 2.0f + 5.0f); rsRandomizer = rg (0.5f, static_cast <float> (botTeam) * 2.0f + 5.0f);
} }
while (!m_routeQue.empty ()) { while (!m_routeQue.empty ()) {
@ -512,7 +512,7 @@ PathPlanner::PathPlanner () {
void PathPlanner::init () { void PathPlanner::init () {
const int length = graph.length (); const int length = graph.length ();
const float limitInMb = cv_path_floyd_memory_limit.float_ (); const float limitInMb = cv_path_floyd_memory_limit.as <float> ();
const float memoryUse = static_cast <float> (sizeof (FloydWarshallAlgo::Matrix) * cr::sqrf (static_cast <size_t> (length)) / 1024 / 1024); const float memoryUse = static_cast <float> (sizeof (FloydWarshallAlgo::Matrix) * cr::sqrf (static_cast <size_t> (length)) / 1024 / 1024);
// if we're have too much memory for floyd matrices, planner will use dijkstra or uniform planner for other than pathfinding needs // if we're have too much memory for floyd matrices, planner will use dijkstra or uniform planner for other than pathfinding needs
@ -528,7 +528,7 @@ void PathPlanner::init () {
} }
bool PathPlanner::hasRealPathDistance () const { bool PathPlanner::hasRealPathDistance () const {
return !m_memoryLimitHit || !cv_path_dijkstra_simple_distance.bool_ (); return !m_memoryLimitHit || !cv_path_dijkstra_simple_distance;
} }
bool PathPlanner::find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance) { bool PathPlanner::find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance) {
@ -553,7 +553,7 @@ float PathPlanner::dist (int srcIndex, int destIndex) {
// limit hit, use dijkstra // limit hit, use dijkstra
if (m_memoryLimitHit) { if (m_memoryLimitHit) {
if (cv_path_dijkstra_simple_distance.bool_ ()) { if (cv_path_dijkstra_simple_distance) {
return graph[srcIndex].origin.distance2d (graph[destIndex].origin); return graph[srcIndex].origin.distance2d (graph[destIndex].origin);
} }
return static_cast <float> (m_dijkstra->dist (srcIndex, destIndex)); return static_cast <float> (m_dijkstra->dist (srcIndex, destIndex));

View file

@ -154,6 +154,7 @@ void BotPractice::save () {
return; // no action return; // no action
} }
SmallArray <DangerSaveRestore> data; SmallArray <DangerSaveRestore> data;
data.reserve (m_data.length ());
// copy hash-map data to our vector // copy hash-map data to our vector
m_data.foreach ([&data] (const DangerStorage &ds, const PracticeData &pd) { m_data.foreach ([&data] (const DangerStorage &ds, const PracticeData &pd) {

View file

@ -152,7 +152,7 @@ void BotSounds::simulateNoise (int playerIndex) {
} }
} }
else { else {
if (mp_footsteps.bool_ ()) { if (mp_footsteps) {
// moves fast enough? // moves fast enough?
noise.dist = 1280.0f * (client.ent->v.velocity.length2d () / 260.0f); noise.dist = 1280.0f * (client.ent->v.velocity.length2d () / 260.0f);
noise.last = game.time () + 0.3f; noise.last = game.time () + 0.3f;

View file

@ -16,8 +16,8 @@ template <typename U> bool BotStorage::load (SmallArray <U> &data, ExtenHeader *
extern ConVar cv_debug, cv_graph_url; extern ConVar cv_debug, cv_graph_url;
// graphs can be downloaded... // graphs can be downloaded...
const auto isGraph = !!(type.option & StorageOption::Graph); const bool isGraph = !!(type.option & StorageOption::Graph);
const auto isDebug = cv_debug.bool_ (); const bool isDebug = cv_debug;
MemFile file (filename); // open the file MemFile file (filename); // open the file
data.clear (); data.clear ();
@ -46,7 +46,7 @@ template <typename U> bool BotStorage::load (SmallArray <U> &data, ExtenHeader *
String lowercaseMapName = game.getMapName (); String lowercaseMapName = game.getMapName ();
lowercaseMapName = lowercaseMapName.lowercase (); lowercaseMapName = lowercaseMapName.lowercase ();
auto downloadAddress = cv_graph_url.str (); auto downloadAddress = cv_graph_url.as <StringRef> ();
auto toDownload = buildPath (storageToBotFile (type.option), false); auto toDownload = buildPath (storageToBotFile (type.option), false);
auto fromDownload = strings.format ("%s://%s/graph/%s.graph", product.httpScheme, downloadAddress, lowercaseMapName); auto fromDownload = strings.format ("%s://%s/graph/%s.graph", product.httpScheme, downloadAddress, lowercaseMapName);
@ -272,7 +272,7 @@ template <typename U> bool BotStorage::save (const SmallArray <U> &data, ExtenHe
extern ConVar cv_debug; extern ConVar cv_debug;
// notify only about graph // notify only about graph
if (isGraph || cv_debug.bool_ ()) { if (isGraph || cv_debug) {
ctrl.msg ("Successfully saved Bots %s data.", type.name); ctrl.msg ("Successfully saved Bots %s data.", type.name);
} }
} }

View file

@ -233,7 +233,7 @@ bool BotSupport::isShootableBreakable (edict_t *ent) {
if (game.isNullEntity (ent) || ent == game.getStartEntity ()) { if (game.isNullEntity (ent) || ent == game.getStartEntity ()) {
return false; return false;
} }
const auto limit = cv_breakable_health_limit.float_ (); const auto limit = cv_breakable_health_limit.as <float> ();
// not shootable // not shootable
if (ent->v.health >= limit) { if (ent->v.health >= limit) {
@ -263,7 +263,7 @@ bool BotSupport::isFakeClient (edict_t *ent) {
void BotSupport::checkWelcome () { void BotSupport::checkWelcome () {
// the purpose of this function, is to send quick welcome message, to the listenserver entity. // the purpose of this function, is to send quick welcome message, to the listenserver entity.
if (game.isDedicated () || !cv_display_welcome_text.bool_ () || !m_needToSendWelcome) { if (game.isDedicated () || !cv_display_welcome_text || !m_needToSendWelcome) {
return; return;
} }
@ -271,7 +271,7 @@ void BotSupport::checkWelcome () {
auto receiveEnt = game.getLocalEntity (); auto receiveEnt = game.getLocalEntity ();
if (isAlive (receiveEnt) && m_welcomeReceiveTime < 1.0f && needToSendMsg) { if (isAlive (receiveEnt) && m_welcomeReceiveTime < 1.0f && needToSendMsg) {
m_welcomeReceiveTime = game.time () + 2.0f + mp_freezetime.float_ (); // receive welcome message in four seconds after game has commencing m_welcomeReceiveTime = game.time () + 2.0f + mp_freezetime.as <float> (); // receive welcome message in four seconds after game has commencing
} }
if (m_welcomeReceiveTime > 0.0f && m_welcomeReceiveTime < game.time () && needToSendMsg) { if (m_welcomeReceiveTime > 0.0f && m_welcomeReceiveTime < game.time () && needToSendMsg) {
@ -309,16 +309,16 @@ void BotSupport::checkWelcome () {
textParams.channel = 1; textParams.channel = 1;
textParams.x = -1.0f; textParams.x = -1.0f;
textParams.y = sendLegacyWelcome ? 0.0f : -1.0f; textParams.y = sendLegacyWelcome ? 0.0f : -1.0f;
textParams.effect = rg.get (1, 2); textParams.effect = rg (1, 2);
textParams.r1 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg.get (33, 255)); textParams.r1 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg (33, 255));
textParams.g1 = static_cast <uint8_t> (sendLegacyWelcome ? 0 : rg.get (33, 255)); textParams.g1 = static_cast <uint8_t> (sendLegacyWelcome ? 0 : rg (33, 255));
textParams.b1 = static_cast <uint8_t> (sendLegacyWelcome ? 0 : rg.get (33, 255)); textParams.b1 = static_cast <uint8_t> (sendLegacyWelcome ? 0 : rg (33, 255));
textParams.a1 = static_cast <uint8_t> (0); textParams.a1 = static_cast <uint8_t> (0);
textParams.r2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg.get (230, 255)); textParams.r2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg (230, 255));
textParams.g2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg.get (230, 255)); textParams.g2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg (230, 255));
textParams.b2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg.get (230, 255)); textParams.b2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg (230, 255));
textParams.a2 = static_cast <uint8_t> (200); textParams.a2 = static_cast <uint8_t> (200);
textParams.fadeinTime = 0.0078125f; textParams.fadeinTime = 0.0078125f;
@ -425,7 +425,7 @@ void BotSupport::calculatePings () {
} }
void BotSupport::syncCalculatePings () { void BotSupport::syncCalculatePings () {
if (!game.is (GameFlags::HasFakePings) || cv_show_latency.int_ () != 2) { if (!game.is (GameFlags::HasFakePings) || cv_show_latency.as <int> () != 2) {
return; return;
} }
MutexScopedLock lock (m_cs); MutexScopedLock lock (m_cs);
@ -434,7 +434,7 @@ void BotSupport::syncCalculatePings () {
int numHumans = 0; int numHumans = 0;
// only count player pings if we're allowed to // only count player pings if we're allowed to
if (cv_count_players_for_fakeping.bool_ ()) { if (cv_count_players_for_fakeping) {
// first get average ping on server, and store real client pings // first get average ping on server, and store real client pings
for (auto &client : m_clients) { for (auto &client : m_clients) {
if (!(client.flags & ClientFlags::Used) || isFakeClient (client.ent)) { if (!(client.flags & ClientFlags::Used) || isFakeClient (client.ent)) {
@ -454,7 +454,7 @@ void BotSupport::syncCalculatePings () {
// https://github.com/fwgs/xash3d-fwgs/blob/f5b9826fd9bbbdc5293c1ff522de11ce28d3c9f2/engine/server/sv_game.c#L4443 // https://github.com/fwgs/xash3d-fwgs/blob/f5b9826fd9bbbdc5293c1ff522de11ce28d3c9f2/engine/server/sv_game.c#L4443
// store normal client ping // store normal client ping
client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping : rg.get (8, 16)); // getting player ping sometimes fails client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping : rg (8, 16)); // getting player ping sometimes fails
++numHumans; ++numHumans;
average.first += ping; average.first += ping;
@ -466,13 +466,13 @@ void BotSupport::syncCalculatePings () {
average.second /= numHumans; average.second /= numHumans;
} }
else { else {
average.first = rg.get (10, 20); average.first = rg (10, 20);
average.second = rg.get (5, 10); average.second = rg (5, 10);
} }
} }
else { else {
average.first = rg.get (10, 20); average.first = rg (10, 20);
average.second = rg.get (5, 10); average.second = rg (5, 10);
} }
// now calculate bot ping based on average from players // now calculate bot ping based on average from players
@ -488,14 +488,14 @@ void BotSupport::syncCalculatePings () {
} }
const int part = static_cast <int> (static_cast <float> (average.first) * 0.2f); const int part = static_cast <int> (static_cast <float> (average.first) * 0.2f);
int botPing = bot->m_basePing + rg.get (average.first - part, average.first + part) + rg.get (bot->m_difficulty / 2, bot->m_difficulty); int botPing = bot->m_basePing + rg (average.first - part, average.first + part) + rg (bot->m_difficulty / 2, bot->m_difficulty);
const int botLoss = rg.get (average.second / 2, average.second); const int botLoss = rg (average.second / 2, average.second);
if (botPing < 2) { if (botPing < 2) {
botPing = rg.get (10, 23); botPing = rg (10, 23);
} }
else if (botPing > 100) { else if (botPing > 100) {
botPing = rg.get (30, 40); botPing = rg (30, 40);
} }
client.ping = getPingBitmask (client.ent, botLoss, botPing); client.ping = getPingBitmask (client.ent, botLoss, botPing);
} }
@ -520,7 +520,7 @@ void BotSupport::emitPings (edict_t *to) {
// no ping, no fun // no ping, no fun
if (!client.ping) { if (!client.ping) {
client.ping = getPingBitmask (client.ent, rg.get (5, 10), rg.get (15, 40)); client.ping = getPingBitmask (client.ent, rg (5, 10), rg (15, 40));
} }
msg.start (MSG_ONE_UNRELIABLE, SVC_PINGS, nullptr, to) msg.start (MSG_ONE_UNRELIABLE, SVC_PINGS, nullptr, to)
@ -565,7 +565,7 @@ String BotSupport::getCurrentDateTime () {
} }
StringRef BotSupport::getFakeSteamId (edict_t *ent) { StringRef BotSupport::getFakeSteamId (edict_t *ent) {
if (!cv_enable_fake_steamids.bool_ () || !isPlayer (ent)) { if (!cv_enable_fake_steamids || !isPlayer (ent)) {
return "BOT"; return "BOT";
} }
auto botNameHash = StringRef::fnv1a32 (ent->v.netname.chars ()); auto botNameHash = StringRef::fnv1a32 (ent->v.netname.chars ());
@ -610,7 +610,7 @@ public:
}; };
float BotSupport::getWaveLength (StringRef filename) { float BotSupport::getWaveLength (StringRef filename) {
auto filePath = strings.joinPath (cv_chatter_path.str (), strings.format ("%s.wav", filename)); auto filePath = strings.joinPath (cv_chatter_path.as <StringRef> (), strings.format ("%s.wav", filename));
MemFile fp (filePath); MemFile fp (filePath);

View file

@ -18,7 +18,7 @@ ConVar cv_random_knife_attacks ("random_knife_attacks", "1", "Allows or disallow
void Bot::normal_ () { void Bot::normal_ () {
m_aimFlags |= AimFlags::Nav; m_aimFlags |= AimFlags::Nav;
const int debugGoal = cv_debug_goal.int_ (); const int debugGoal = cv_debug_goal.as <int> ();
// user forced a node as a goal? // user forced a node as a goal?
if (debugGoal != kInvalidNodeIndex) { if (debugGoal != kInvalidNodeIndex) {
@ -46,14 +46,14 @@ void Bot::normal_ () {
} }
// bots rushing with knife, when have no enemy (thanks for idea to nicebot project) // bots rushing with knife, when have no enemy (thanks for idea to nicebot project)
if (cv_random_knife_attacks.bool_ () && usesKnife () && (game.isNullEntity (m_lastEnemy) || !util.isAlive (m_lastEnemy)) && game.isNullEntity (m_enemy) && m_knifeAttackTime < game.time () && !m_hasHostage && !hasShield () && numFriendsNear (pev->origin, 96.0f) == 0) { if (cv_random_knife_attacks && usesKnife () && (game.isNullEntity (m_lastEnemy) || !util.isAlive (m_lastEnemy)) && game.isNullEntity (m_enemy) && m_knifeAttackTime < game.time () && !m_hasHostage && !hasShield () && numFriendsNear (pev->origin, 96.0f) == 0) {
if (rg.chance (40)) { if (rg.chance (40)) {
pev->button |= IN_ATTACK; pev->button |= IN_ATTACK;
} }
else { else {
pev->button |= IN_ATTACK2; pev->button |= IN_ATTACK2;
} }
m_knifeAttackTime = game.time () + rg.get (2.5f, 6.0f); m_knifeAttackTime = game.time () + rg (2.5f, 6.0f);
} }
const auto &prop = conf.getWeaponProp (m_currentWeapon); const auto &prop = conf.getWeaponProp (m_currentWeapon);
@ -92,7 +92,7 @@ void Bot::normal_ () {
if (!(m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy)) if (!(m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy))
&& m_seeEnemyTime + 5.0f < game.time () && m_seeEnemyTime + 5.0f < game.time ()
&& !m_reloadState && m_timeLogoSpray < game.time () && !m_reloadState && m_timeLogoSpray < game.time ()
&& cv_spraypaints.bool_ () && cv_spraypaints
&& rg.chance (50) && rg.chance (50)
&& m_moveSpeed > getShiftSpeed () && m_moveSpeed > getShiftSpeed ()
&& game.isNullEntity (m_pickupItem)) { && game.isNullEntity (m_pickupItem)) {
@ -103,7 +103,7 @@ void Bot::normal_ () {
} }
// reached node is a camp node // reached node is a camp node
if ((m_pathFlags & NodeFlag::Camp) && !game.is (GameFlags::CSDM) && cv_camping_allowed.bool_ () && !isKnifeMode ()) { if ((m_pathFlags & NodeFlag::Camp) && !game.is (GameFlags::CSDM) && cv_camping_allowed && !isKnifeMode ()) {
const bool allowedCampWeapon = hasPrimaryWeapon () const bool allowedCampWeapon = hasPrimaryWeapon ()
|| hasShield () || hasShield ()
|| (hasSecondaryWeapon () && !hasPrimaryWeapon () && m_numFriendsLeft > game.maxClients () / 6); || (hasSecondaryWeapon () && !hasPrimaryWeapon () && m_numFriendsLeft > game.maxClients () / 6);
@ -153,7 +153,7 @@ void Bot::normal_ () {
if (!(m_states & (Sense::SeeingEnemy | Sense::HearingEnemy)) && !m_reloadState) { if (!(m_states & (Sense::SeeingEnemy | Sense::HearingEnemy)) && !m_reloadState) {
m_reloadState = Reload::Primary; m_reloadState = Reload::Primary;
} }
m_timeCamping = game.time () + rg.get (cv_camping_time_min.float_ (), cv_camping_time_max.float_ ()); m_timeCamping = game.time () + rg (cv_camping_time_min.as <float> (), cv_camping_time_max.as <float> ());
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, m_timeCamping, true); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, m_timeCamping, true);
m_lookAtSafe = m_pathOrigin + m_path->start.forward () * 500.0f; m_lookAtSafe = m_pathOrigin + m_path->start.forward () * 500.0f;
@ -185,8 +185,8 @@ void Bot::normal_ () {
else if (m_team == Team::Terrorist && rg.chance (75) && !game.mapIs (MapFlags::Demolition)) { else if (m_team == Team::Terrorist && rg.chance (75) && !game.mapIs (MapFlags::Demolition)) {
const int index = findDefendNode (m_path->origin); const int index = findDefendNode (m_path->origin);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (60.0f, 120.0f), true); // push camp task on to stack startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (60.0f, 120.0f), true); // push camp task on to stack
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (5.0f, 10.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (5.0f, 10.0f), true); // push move command
// decide to duck or not to duck // decide to duck or not to duck
selectCampButtons (index); selectCampButtons (index);
@ -202,7 +202,7 @@ void Bot::normal_ () {
pushRadioMessage (Radio::NeedBackup); pushRadioMessage (Radio::NeedBackup);
pushChatterMessage (Chatter::ScaredEmotion); pushChatterMessage (Chatter::ScaredEmotion);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (4.0f, 8.0f), true); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (4.0f, 8.0f), true);
} }
else { else {
startTask (Task::PlantBomb, TaskPri::PlantBomb, kInvalidNodeIndex, 0.0f, false); startTask (Task::PlantBomb, TaskPri::PlantBomb, kInvalidNodeIndex, 0.0f, false);
@ -211,14 +211,14 @@ void Bot::normal_ () {
else if (m_team == Team::CT) { else if (m_team == Team::CT) {
if (!bots.isBombPlanted () && numFriendsNear (pev->origin, 210.0f) < 4) { if (!bots.isBombPlanted () && numFriendsNear (pev->origin, 210.0f) < 4) {
const int index = findDefendNode (m_path->origin); const int index = findDefendNode (m_path->origin);
float campTime = rg.get (25.0f, 40.f); float campTime = rg (25.0f, 40.f);
// rusher bots don't like to camp too much // rusher bots don't like to camp too much
if (m_personality == Personality::Rusher) { if (m_personality == Personality::Rusher) {
campTime *= 0.5f; campTime *= 0.5f;
} }
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + campTime, true); // push camp task on to stack startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + campTime, true); // push camp task on to stack
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (5.0f, 11.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (5.0f, 11.0f), true); // push move command
// decide to duck or not to duck // decide to duck or not to duck
selectCampButtons (index); selectCampButtons (index);
@ -267,7 +267,7 @@ void Bot::normal_ () {
} }
const float shiftSpeed = getShiftSpeed (); const float shiftSpeed = getShiftSpeed ();
if ((!cr::fzero (m_moveSpeed) && m_moveSpeed > shiftSpeed) && (cv_walking_allowed.bool_ () && mp_footsteps.bool_ ()) if ((!cr::fzero (m_moveSpeed) && m_moveSpeed > shiftSpeed) && (cv_walking_allowed && mp_footsteps)
&& m_difficulty >= Difficulty::Normal && m_difficulty >= Difficulty::Normal
&& (m_heardSoundTime + 6.0f >= game.time () || (m_states & Sense::HearingEnemy)) && (m_heardSoundTime + 6.0f >= game.time () || (m_states & Sense::HearingEnemy))
&& pev->origin.distanceSq (m_lastEnemyOrigin) < cr::sqrf (768.0f) && pev->origin.distanceSq (m_lastEnemyOrigin) < cr::sqrf (768.0f)
@ -278,21 +278,21 @@ void Bot::normal_ () {
} }
// bot hasn't seen anything in a long time and is asking his teammates to report in // bot hasn't seen anything in a long time and is asking his teammates to report in
if (cv_radio_mode.int_ () > 1 if (cv_radio_mode.as <int> () > 1
&& bots.getLastRadio (m_team) != Radio::ReportInTeam && bots.getLastRadio (m_team) != Radio::ReportInTeam
&& bots.getRoundStartTime () + 20.0f < game.time () && bots.getRoundStartTime () + 20.0f < game.time ()
&& m_askCheckTime < game.time () && rg.chance (15) && m_askCheckTime < game.time () && rg.chance (15)
&& m_seeEnemyTime + rg.get (45.0f, 80.0f) < game.time () && m_seeEnemyTime + rg (45.0f, 80.0f) < game.time ()
&& numFriendsNear (pev->origin, 1024.0f) == 0) { && numFriendsNear (pev->origin, 1024.0f) == 0) {
pushRadioMessage (Radio::ReportInTeam); pushRadioMessage (Radio::ReportInTeam);
m_askCheckTime = game.time () + rg.get (45.0f, 80.0f); m_askCheckTime = game.time () + rg (45.0f, 80.0f);
// make sure everyone else will not ask next few moments // make sure everyone else will not ask next few moments
for (const auto &bot : bots) { for (const auto &bot : bots) {
if (bot->m_isAlive) { if (bot->m_isAlive) {
bot->m_askCheckTime = game.time () + rg.get (5.0f, 30.0f); bot->m_askCheckTime = game.time () + rg (5.0f, 30.0f);
} }
} }
} }
@ -322,7 +322,7 @@ void Bot::spraypaint_ () {
// paint the actual logo decal // paint the actual logo decal
util.decalTrace (pev, &tr, m_logotypeIndex); util.decalTrace (pev, &tr, m_logotypeIndex);
m_timeLogoSpray = game.time () + rg.get (60.0f, 90.0f); m_timeLogoSpray = game.time () + rg (60.0f, 90.0f);
} }
} }
else { else {
@ -390,7 +390,7 @@ void Bot::huntEnemy_ () {
} }
// bots skill higher than 60? // bots skill higher than 60?
if (cv_walking_allowed.bool_ () && mp_footsteps.bool_ () && m_difficulty >= Difficulty::Normal && !isKnifeMode ()) { if (cv_walking_allowed && mp_footsteps && m_difficulty >= Difficulty::Normal && !isKnifeMode ()) {
// then make him move slow if near enemy // then make him move slow if near enemy
if (!(m_currentTravelFlags & PathFlag::Jump)) { if (!(m_currentTravelFlags & PathFlag::Jump)) {
if (m_currentNodeIndex != kInvalidNodeIndex) { if (m_currentNodeIndex != kInvalidNodeIndex) {
@ -417,7 +417,7 @@ void Bot::seekCover_ () {
m_prevGoalIndex = kInvalidNodeIndex; m_prevGoalIndex = kInvalidNodeIndex;
// start hide task // start hide task
startTask (Task::Hide, TaskPri::Hide, kInvalidNodeIndex, game.time () + rg.get (3.0f, 12.0f), false); startTask (Task::Hide, TaskPri::Hide, kInvalidNodeIndex, game.time () + rg (3.0f, 12.0f), false);
// get a valid look direction // get a valid look direction
const Vector &dest = getCampDirection (m_lastEnemyOrigin); const Vector &dest = getCampDirection (m_lastEnemyOrigin);
@ -470,7 +470,7 @@ void Bot::seekCover_ () {
destIndex = findCoverNode (900.0f); destIndex = findCoverNode (900.0f);
if (destIndex == kInvalidNodeIndex) { if (destIndex == kInvalidNodeIndex) {
m_retreatTime = game.time () + rg.get (1.0f, 2.0f); m_retreatTime = game.time () + rg (1.0f, 2.0f);
m_prevGoalIndex = kInvalidNodeIndex; m_prevGoalIndex = kInvalidNodeIndex;
completeTask (); completeTask ();
@ -594,7 +594,7 @@ void Bot::blind_ () {
} }
void Bot::camp_ () { void Bot::camp_ () {
if (!cv_camping_allowed.bool_ () || m_isCreature) { if (!cv_camping_allowed || m_isCreature) {
completeTask (); completeTask ();
return; return;
} }
@ -637,7 +637,7 @@ void Bot::camp_ () {
}; };
if (m_nextCampDirTime < game.time ()) { if (m_nextCampDirTime < game.time ()) {
m_nextCampDirTime = game.time () + rg.get (2.0f, 5.0f); m_nextCampDirTime = game.time () + rg (2.0f, 5.0f);
if (m_pathFlags & NodeFlag::Camp) { if (m_pathFlags & NodeFlag::Camp) {
Vector dest; Vector dest;
@ -838,7 +838,7 @@ void Bot::plantBomb_ () {
pushRadioMessage (Radio::NeedBackup); pushRadioMessage (Radio::NeedBackup);
} }
const auto index = findDefendNode (pev->origin); const auto index = findDefendNode (pev->origin);
const auto guardTime = mp_c4timer.float_ () * 0.5f + mp_c4timer.float_ () * 0.25f; const auto guardTime = mp_c4timer.as <float> () * 0.5f + mp_c4timer.as <float> () * 0.25f;
// push camp task on to stack // push camp task on to stack
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + guardTime, true); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + guardTime, true);
@ -871,18 +871,18 @@ void Bot::defuseBomb_ () {
if (bot->m_team == m_team && bot->m_isAlive) { if (bot->m_team == m_team && bot->m_isAlive) {
auto defendPoint = graph.getFarest (bot->pev->origin); auto defendPoint = graph.getFarest (bot->pev->origin);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true); // push camp task on to stack startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (30.0f, 60.0f), true); // push camp task on to stack
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, defendPoint, game.time () + rg.get (3.0f, 6.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, defendPoint, game.time () + rg (3.0f, 6.0f), true); // push move command
} }
} }
graph.setBombOrigin (true); graph.setBombOrigin (true);
if (m_numFriendsLeft != 0 && rg.chance (50)) { if (m_numFriendsLeft != 0 && rg.chance (50)) {
if (timeToBlowUp <= 3.0f) { if (timeToBlowUp <= 3.0f) {
if (cv_radio_mode.int_ () == 2) { if (cv_radio_mode.as <int> () == 2) {
pushChatterMessage (Chatter::BarelyDefused); pushChatterMessage (Chatter::BarelyDefused);
} }
else if (cv_radio_mode.int_ () == 1) { else if (cv_radio_mode.as <int> () == 1) {
pushRadioMessage (Radio::SectorClear); pushRadioMessage (Radio::SectorClear);
} }
} }
@ -1083,7 +1083,7 @@ void Bot::followUser_ () {
} }
m_aimFlags |= AimFlags::Nav; m_aimFlags |= AimFlags::Nav;
if (cv_walking_allowed.bool_ () && m_targetEntity->v.maxspeed < m_moveSpeed && !isKnifeMode ()) { if (cv_walking_allowed && m_targetEntity->v.maxspeed < m_moveSpeed && !isKnifeMode ()) {
m_moveSpeed = getShiftSpeed (); m_moveSpeed = getShiftSpeed ();
} }
@ -1324,7 +1324,7 @@ void Bot::doublejump_ () {
game.testLine (src, dest, TraceIgnore::None, ent (), &tr); game.testLine (src, dest, TraceIgnore::None, ent (), &tr);
if (tr.flFraction < 1.0f && tr.pHit == m_doubleJumpEntity && inJump) { if (tr.flFraction < 1.0f && tr.pHit == m_doubleJumpEntity && inJump) {
m_duckForJump = game.time () + rg.get (3.0f, 5.0f); m_duckForJump = game.time () + rg (3.0f, 5.0f);
getTask ()->time = game.time (); getTask ()->time = game.time ();
} }
return; return;
@ -1394,7 +1394,7 @@ void Bot::escapeFromBomb_ () {
else if (!hasActiveGoal ()) { else if (!hasActiveGoal ()) {
int bestIndex = kInvalidNodeIndex; int bestIndex = kInvalidNodeIndex;
const float safeRadius = rg.get (1513.0f, 2048.0f); const float safeRadius = rg (1513.0f, 2048.0f);
float nearestDistanceSq = kInfiniteDistance; float nearestDistanceSq = kInfiniteDistance;
for (const auto &path : graph) { for (const auto &path : graph) {

View file

@ -75,7 +75,7 @@ void Bot::checkDarkness () {
const auto skyColor = illum.getSkyColor (); const auto skyColor = illum.getSkyColor ();
const auto flashOn = (pev->effects & EF_DIMLIGHT); const auto flashOn = (pev->effects & EF_DIMLIGHT);
if (mp_flashlight.bool_ () && !m_hasNVG) { if (mp_flashlight && !m_hasNVG) {
const auto tid = getCurrentTaskId (); const auto tid = getCurrentTaskId ();
if (!flashOn && if (!flashOn &&
@ -105,7 +105,7 @@ void Bot::checkDarkness () {
issueCommand ("nightvision"); issueCommand ("nightvision");
} }
} }
m_checkDarkTime = game.time () + rg.get (2.0f, 4.0f); m_checkDarkTime = game.time () + rg (2.0f, 4.0f);
} }
void Bot::changePitch (float speed) { void Bot::changePitch (float speed) {
@ -203,7 +203,7 @@ void Bot::updateLookAngles () {
if (m_difficulty == Difficulty::Expert if (m_difficulty == Difficulty::Expert
&& (m_aimFlags & AimFlags::Enemy) && (m_aimFlags & AimFlags::Enemy)
&& (m_wantsToFire || usesSniper ()) && (m_wantsToFire || usesSniper ())
&& cv_whose_your_daddy.bool_ ()) { && cv_whose_your_daddy) {
pev->v_angle = direction; pev->v_angle = direction;
pev->v_angle.clampAngles (); pev->v_angle.clampAngles ();
@ -311,10 +311,10 @@ void Bot::updateLookAnglesNewbie (const Vector &direction, float delta) {
randomize = randomization; randomize = randomization;
} }
// randomize targeted location bit (slightly towards the ground) // randomize targeted location bit (slightly towards the ground)
m_randomizedIdealAngles = m_idealAngles + Vector (rg.get (-randomize.x * 0.5f, randomize.x * 1.5f), rg.get (-randomize.y, randomize.y), 0.0f); m_randomizedIdealAngles = m_idealAngles + Vector (rg (-randomize.x * 0.5f, randomize.x * 1.5f), rg (-randomize.y, randomize.y), 0.0f);
// set next time to do this // set next time to do this
m_randomizeAnglesTime = game.time () + rg.get (0.4f, offsetDelay); m_randomizeAnglesTime = game.time () + rg (0.4f, offsetDelay);
} }
float stiffnessMultiplier = noTargetRatio; float stiffnessMultiplier = noTargetRatio;
@ -425,6 +425,16 @@ void Bot::setAimDirection () {
flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath); flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
m_canChooseAimDirection = false; m_canChooseAimDirection = false;
} }
// don't switch view right away after loosing focus with current enemy
if ((m_shootTime + 1.5f > game.time () || m_seeEnemyTime + 1.5 > game.time ())
&& m_forgetLastVictimTimer.elapsed ()
&& !m_lastEnemyOrigin.empty ()
&& util.isAlive (m_lastEnemy)
&& game.isNullEntity (m_enemy)) {
flags |= AimFlags::LastEnemy;
}
} }
if (flags & AimFlags::Override) { if (flags & AimFlags::Override) {
@ -500,14 +510,14 @@ void Bot::setAimDirection () {
predictNode = kInvalidNodeIndex; predictNode = kInvalidNodeIndex;
pathLength = kInfiniteDistanceLong; pathLength = kInfiniteDistanceLong;
} }
return graph.exists (predictNode) && pathLength < cv_max_nodes_for_predict.int_ (); return graph.exists (predictNode) && pathLength < cv_max_nodes_for_predict.as <int> ();
}; };
if (changePredictedEnemy) { if (changePredictedEnemy) {
if (isPredictedIndexApplicable ()) { if (isPredictedIndexApplicable ()) {
m_lookAtPredict = graph[predictNode].origin; m_lookAtPredict = graph[predictNode].origin;
m_timeNextTracking = game.time () + rg.get (0.5f, 1.0f); m_timeNextTracking = game.time () + rg (0.5f, 1.0f);
m_trackingEdict = m_lastEnemy; m_trackingEdict = m_lastEnemy;
} }
else { else {

View file

@ -41,7 +41,7 @@ void GraphVistable::rebuild () {
sourceCrouch.z += -18.0f + 12.0f; sourceCrouch.z += -18.0f + 12.0f;
sourceStand.z += 28.0f; sourceStand.z += 28.0f;
} }
auto end = m_sliceIndex + rg.get (250, 400); auto end = m_sliceIndex + rg (250, 400);
if (end > m_length) { if (end > m_length) {
end = m_length; end = m_length;
@ -122,7 +122,7 @@ void GraphVistable::rebuild () {
m_curIndex++; m_curIndex++;
} }
else { else {
m_sliceIndex += rg.get (250, 400); m_sliceIndex += rg (250, 400);
} }
// notify host about rebuilding // notify host about rebuilding