crlib: replace random number generator with wyhash.

Benchmarks shows about 4x increased PRNG perfomance increase comparing to old one. Should slightly reduce per-bot CPU usage.
This commit is contained in:
ds 2020-09-29 19:23:26 +03:00
commit 726ea72965
13 changed files with 189 additions and 179 deletions

View file

@ -272,8 +272,10 @@ public:
} }
void shuffle () { void shuffle () {
for (size_t i = length_; i >= 1; --i) { int32 shuffleLength = length <int32> ();
cr::swap (contents_[i - 1], contents_[rg.int_ (i, length_ - 2)]);
for (int32 i = shuffleLength; i >= 1; --i) {
cr::swap (contents_[i - 1], contents_[rg.get (i, shuffleLength - 2)]);
} }
} }
@ -352,11 +354,11 @@ public:
} }
const T &random () const { const T &random () const {
return contents_[rg.int_ <size_t> (0, length_ - 1)]; return contents_[rg.get (0, length <int32> () - 1)];
} }
T &random () { T &random () {
return contents_[rg.int_ <size_t> (0u, length_ - 1u)]; return contents_[rg.get (0, length <int32> () - 1)];
} }
T *data () { T *data () {

View file

@ -443,7 +443,7 @@ public:
if (boundarySlash != String::InvalidIndex) { if (boundarySlash != String::InvalidIndex) {
boundaryName = localPath.substr (boundarySlash + 1); boundaryName = localPath.substr (boundarySlash + 1);
} }
StringRef boundaryLine = strings.format ("---crlib_upload_boundary_%d%d%d%d", rg.int_ (0, 9), rg.int_ (0, 9), rg.int_ (0, 9), rg.int_ (0, 9)); StringRef boundaryLine = strings.format ("---crlib_upload_boundary_%d%d%d%d", rg.get (0, 9), rg.get (0, 9), rg.get (0, 9), rg.get (0, 9));
String request, start, end; String request, start, end;
start.appendf ("--%s\r\n", boundaryLine); start.appendf ("--%s\r\n", boundaryLine);

View file

@ -20,49 +20,57 @@
CR_NAMESPACE_BEGIN CR_NAMESPACE_BEGIN
// random number generator see: https://github.com/preshing/RandomSequence/ // based on: https://github.com/jeudesprits/PSWyhash/blob/master/Sources/CWyhash/include/wyhash.h
class Random final : public Singleton <Random> { class Random : public Singleton <Random> {
private: private:
uint32 index_, offset_; uint64 div_ { static_cast <uint64> (1) << 32ull };
uint64 divider_; uint64 state_ { static_cast <uint64> (time (nullptr)) };
public: public:
explicit Random () { Random () = default;
const auto base = static_cast <uint32> (time (nullptr));
const auto offset = base + 1;
index_ = premute (premute (base) + 0x682f0161);
offset_ = premute (premute (offset) + 0x46790905);
divider_ = (static_cast <uint64> (1)) << 32;
}
~Random () = default; ~Random () = default;
private: private:
uint32 premute (uint32 index) { uint64 wyrand64 () {
static constexpr auto prime = 4294967291u; constexpr uint64 wyp0 = 0xa0761d6478bd642full, wyp1 = 0xe7037ed1a0b428dbull;
state_ += wyp0;
if (index >= prime) { return mul (state_ ^ wyp1, state_);
return index;
}
const uint32 residue = (static_cast <uint64> (index) * index) % prime;
return (index <= prime / 2) ? residue : prime - residue;
} }
uint32 generate () { uint32 wyrand32 () {
return premute ((premute (index_++) + offset_) ^ 0x5bf03635); return static_cast <uint32> (wyrand64 ());
}
private:
uint64_t rotr (uint64 v, uint32 k) {
return (v >> k) | (v << (64 - k));
}
uint64 mul (uint64 a, uint64 b) {
uint64 hh = (a >> 32) * (b >> 32);
uint64 hl = (b >> 32) * static_cast <uint32> (b);
uint64 lh = static_cast <uint32> (a) * (b >> 32);
uint64 ll = static_cast <uint64> (static_cast <double> (a) * static_cast <double> (b));
return rotr (hl, 32) ^ rotr (lh, 32) ^ hh ^ ll;
} }
public: public:
template <typename U> U int_ (U low, U high) { template <typename U, typename Void = void> U get (U, U) = delete;
return static_cast <U> (generate () * (static_cast <double> (high) - static_cast <double> (low) + 1.0) / divider_ + static_cast <double> (low));
template <typename Void = void> int32 get (int32 low, int32 high) {
return static_cast <int32> (wyrand32 () * (static_cast <double> (high) - static_cast <double> (low) + 1.0) / div_ + static_cast <double> (low));
} }
float float_ (float low, float high) { template <typename Void = void> float get (float low, float high) {
return static_cast <float> (generate () * (static_cast <double> (high) - static_cast <double> (low)) / (divider_ - 1) + static_cast <double> (low)); return static_cast <float> (wyrand32 () * (static_cast <double> (high) - static_cast <double> (low)) / (div_ - 1) + static_cast <double> (low));
} }
template <typename U> bool chance (const U max, const U maxChance = 100) { public:
return int_ <U> (0, maxChance) < max; bool chance (int32 limit) {
return get <int32> (0, 100) < limit;
} }
}; };

View file

@ -53,8 +53,6 @@ public:
SimdWrap (__m128 m) : m (m) SimdWrap (__m128 m) : m (m)
{ } { }
public: public:
SimdWrap normalize () { SimdWrap normalize () {
return { _mm_div_ps (m, _mm_sqrt_ps (wrap_dp_sse2 (m, m))) }; return { _mm_div_ps (m, _mm_sqrt_ps (wrap_dp_sse2 (m, m))) };

View file

@ -1093,6 +1093,7 @@ public:
int getNearestToPlantedBomb (); int getNearestToPlantedBomb ();
float getFrameInterval (); float getFrameInterval ();
float getConnectionTime ();
BotTask *getTask (); BotTask *getTask ();
public: public:

View file

@ -338,7 +338,7 @@ void Bot::avoidGrenades () {
pev->v_angle.y = cr::normalizeAngles ((game.getEntityWorldOrigin (pent) - getEyesPos ()).angles ().y + 180.0f); pev->v_angle.y = cr::normalizeAngles ((game.getEntityWorldOrigin (pent) - getEyesPos ()).angles ().y + 180.0f);
m_canChooseAimDirection = false; m_canChooseAimDirection = false;
m_preventFlashing = game.time () + rg.float_ (1.0f, 2.0f); m_preventFlashing = game.time () + rg.get (1.0f, 2.0f);
} }
} }
else if (strcmp (model, "hegrenade.mdl") == 0) { else if (strcmp (model, "hegrenade.mdl") == 0) {
@ -480,7 +480,7 @@ void Bot::setIdealReactionTimers (bool actual) {
return; return;
} }
m_idealReactionTime = rg.float_ (tweak->reaction[0], tweak->reaction[1]); m_idealReactionTime = rg.get (tweak->reaction[0], tweak->reaction[1]);
} }
void Bot::updatePickups () { void Bot::updatePickups () {
@ -667,8 +667,8 @@ void Bot::updatePickups () {
if (!m_defendHostage && m_personality != Personality::Rusher && m_difficulty > Difficulty::Normal && rg.chance (15) && m_timeCamping + 15.0f < game.time ()) { if (!m_defendHostage && m_personality != Personality::Rusher && m_difficulty > Difficulty::Normal && rg.chance (15) && m_timeCamping + 15.0f < game.time ()) {
int index = findDefendNode (origin); int index = findDefendNode (origin);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.float_ (30.0f, 60.0f), true); // push camp task on to stack startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true); // push camp task on to stack
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.float_ (3.0f, 6.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (3.0f, 6.0f), true); // push move command
if (graph[index].vis.crouch <= graph[index].vis.stand) { if (graph[index].vis.crouch <= graph[index].vis.stand) {
m_campButtons |= IN_DUCK; m_campButtons |= IN_DUCK;
@ -795,8 +795,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) {
int index = findDefendNode (origin); int index = findDefendNode (origin);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.float_ (30.0f, 70.0f), true); // push camp task on to stack startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 70.0f), true); // push camp task on to stack
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.float_ (10.0f, 30.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (10.0f, 30.0f), true); // push move command
if (graph[index].vis.crouch <= graph[index].vis.stand) { if (graph[index].vis.crouch <= graph[index].vis.stand) {
m_campButtons |= IN_DUCK; m_campButtons |= IN_DUCK;
@ -1036,7 +1036,7 @@ void Bot::checkMsgQueue () {
} }
m_buyPending = false; m_buyPending = false;
m_nextBuyTime = game.time () + rg.float_ (0.5f, 1.3f); m_nextBuyTime = game.time () + rg.get (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.float_ () <= 1.0f) {
@ -1268,7 +1268,7 @@ int Bot::pickBestWeapon (int *vec, int count, int moneySave) {
for (int *begin = vec, *end = vec + count - 1; begin < end; ++begin, --end) { for (int *begin = vec, *end = vec + count - 1; begin < end; ++begin, --end) {
cr::swap (*end, *begin); cr::swap (*end, *begin);
} }
return vec[static_cast <int> (static_cast <float> (count - 1) * pick (rg.float_ (1.0f, cr::powf (10.0f, buyFactor))) / buyFactor + 0.5f)]; return vec[static_cast <int> (static_cast <float> (count - 1) * pick (rg.get (1.0f, cr::powf (10.0f, buyFactor))) / buyFactor + 0.5f)];
} }
int chance = 95; int chance = 95;
@ -1288,11 +1288,11 @@ int Bot::pickBestWeapon (int *vec, int count, int moneySave) {
auto &weapon = info[vec[i]]; auto &weapon = info[vec[i]];
// if wea have enough money for weapon buy it // if wea have enough money for weapon buy it
if (weapon.price + moneySave < m_moneyAmount + rg.int_ (50, 200) && rg.chance (chance)) { if (weapon.price + moneySave < m_moneyAmount + rg.get (50, 200) && rg.chance (chance)) {
return vec[i]; return vec[i];
} }
} }
return vec[rg.int_ (0, count - 1)]; return vec[rg.get (0, count - 1)];
} }
void Bot::buyStuff () { void Bot::buyStuff () {
@ -1302,7 +1302,7 @@ void Bot::buyStuff () {
m_nextBuyTime = game.time (); m_nextBuyTime = game.time ();
if (!m_ignoreBuyDelay) { if (!m_ignoreBuyDelay) {
m_nextBuyTime += rg.float_ (0.3f, 0.5f); m_nextBuyTime += rg.get (0.3f, 0.5f);
} }
int count = 0, weaponCount = 0; int count = 0, weaponCount = 0;
@ -1445,7 +1445,7 @@ void Bot::buyStuff () {
} }
// save money for grenade for example? // save money for grenade for example?
moneySave = rg.int_ (500, 1000); moneySave = rg.get (500, 1000);
if (bots.getLastWinner () == m_team) { if (bots.getLastWinner () == m_team) {
moneySave = 0; moneySave = 0;
@ -1501,7 +1501,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.int_ (50, 80) && teamHasGoodEconomics && (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) { if (pev->armorvalue < rg.get (50, 80) && teamHasGoodEconomics && (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) {
// if bot is rich, buy kevlar + helmet, else buy a single kevlar // if bot is rich, buy kevlar + helmet, else buy a single kevlar
if (m_moneyAmount > 1500 && !isWeaponRestricted (Weapon::ArmorHelm)) { if (m_moneyAmount > 1500 && !isWeaponRestricted (Weapon::ArmorHelm)) {
issueCommand ("buyequip;menuselect 2"); issueCommand ("buyequip;menuselect 2");
@ -1513,7 +1513,7 @@ void Bot::buyStuff () {
break; break;
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 || (isFirstRound && hasDefaultPistols && rg.chance (50)) || (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg.int_ (2000, 3000)) || (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg.int_ (7500, 9000))) { if (isPistolMode || (isFirstRound && hasDefaultPistols && rg.chance (50)) || (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg.get (2000, 3000)) || (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg.get (7500, 9000))) {
do { do {
pref--; pref--;
@ -1545,7 +1545,7 @@ void Bot::buyStuff () {
continue; continue;
} }
if (selectedWeapon->price <= (m_moneyAmount - rg.int_ (100, 200))) { if (selectedWeapon->price <= (m_moneyAmount - rg.get (100, 200))) {
choices[weaponCount++] = *pref; choices[weaponCount++] = *pref;
} }
@ -1557,7 +1557,7 @@ void Bot::buyStuff () {
// choose randomly from the best ones... // choose randomly from the best ones...
if (weaponCount > 1) { if (weaponCount > 1) {
chosenWeapon = pickBestWeapon (choices, weaponCount, rg.int_ (100, 200)); chosenWeapon = pickBestWeapon (choices, weaponCount, rg.get (100, 200));
} }
else { else {
chosenWeapon = choices[weaponCount - 1]; chosenWeapon = choices[weaponCount - 1];
@ -1589,7 +1589,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 <= 5; ++i) { for (int i = 0; i <= 5; ++i) {
issueCommand ("buyammo%d", rg.int_ (1, 2)); // simulate human issueCommand ("buyammo%d", rg.get (1, 2)); // simulate human
} }
// buy enough secondary ammo // buy enough secondary ammo
@ -1617,13 +1617,13 @@ void Bot::buyStuff () {
} }
// buy a concussion grenade, i.e., 'flashbang' // buy a concussion grenade, i.e., 'flashbang'
if (conf.chanceToBuyGrenade (1) && m_moneyAmount >= 300 && teamHasGoodEconomics && !isWeaponRestricted (Weapon::Flashbang)) { if (conf.chanceToBuyGrenade (1) && m_moneyAmount >= 300 && !isWeaponRestricted (Weapon::Flashbang)) {
issueCommand ("buyequip"); issueCommand ("buyequip");
issueCommand ("menuselect 3"); issueCommand ("menuselect 3");
} }
// buy a smoke grenade // buy a smoke grenade
if (conf.chanceToBuyGrenade (2) && m_moneyAmount >= 400 && teamHasGoodEconomics && !isWeaponRestricted (Weapon::Smoke)) { if (conf.chanceToBuyGrenade (2) && m_moneyAmount >= 400 && !isWeaponRestricted (Weapon::Smoke)) {
issueCommand ("buyequip"); issueCommand ("buyequip");
issueCommand ("menuselect 5"); issueCommand ("menuselect 5");
} }
@ -1933,13 +1933,13 @@ 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 > 50.0f ? 100.0f : m_healthValue)) * tempFear; // retreat level depends on bot health float retreatLevel = (100.0f - (m_healthValue > 50.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.float_ (2.0f, 4.0f) < game.time ()) { if (m_numEnemiesLeft > m_numFriendsLeft / 2 && m_retreatTime < game.time () && m_seeEnemyTime - rg.get (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.float_ (3.0f, 15.0f); m_retreatTime = game.time () + rg.get (3.0f, 15.0f);
if (timeSeen > timeHeard) { if (timeSeen > timeHeard) {
timeSeen += 10.0f; timeSeen += 10.0f;
@ -2291,11 +2291,11 @@ void Bot::checkRadioQueue () {
} }
} }
} }
else if (m_radioOrder != Chatter::GoingToPlantBomb && rg.chance (15)) { else if (m_radioOrder != Chatter::GoingToPlantBomb && rg.chance (25)) {
pushRadioMessage (Radio::Negative); pushRadioMessage (Radio::Negative);
} }
} }
else if (m_radioOrder != Chatter::GoingToPlantBomb && rg.chance (25)) { else if (m_radioOrder != Chatter::GoingToPlantBomb && rg.chance (35)) {
pushRadioMessage (Radio::Negative); pushRadioMessage (Radio::Negative);
} }
} }
@ -2308,7 +2308,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.float_ (30.0f, 60.0f), false); startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), false);
} }
} }
break; break;
@ -2402,7 +2402,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.float_ (1024.0f, 2048.0f); m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg.get (1024.0f, 2048.0f);
clearSearchNodes (); clearSearchNodes ();
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true); startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true);
@ -2457,7 +2457,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.float_ (1024.0f, 2048.0f); m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg.get (1024.0f, 2048.0f);
clearSearchNodes (); clearSearchNodes ();
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true); startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true);
@ -2488,7 +2488,7 @@ void Bot::checkRadioQueue () {
m_agressionLevel = 0.0f; m_agressionLevel = 0.0f;
} }
if (getCurrentTaskId () == Task::Camp) { if (getCurrentTaskId () == Task::Camp) {
getTask ()->time += rg.float_ (10.0f, 15.0f); getTask ()->time += rg.get (10.0f, 15.0f);
} }
else { else {
// don't pause/camp anymore // don't pause/camp anymore
@ -2642,7 +2642,7 @@ void Bot::checkRadioQueue () {
pushRadioMessage (Radio::RogerThat); pushRadioMessage (Radio::RogerThat);
if (getCurrentTaskId () == Task::Camp) { if (getCurrentTaskId () == Task::Camp) {
getTask ()->time = game.time () + rg.float_ (30.0f, 60.0f); getTask ()->time = game.time () + rg.get (30.0f, 60.0f);
} }
else { else {
// don't pause anymore // don't pause anymore
@ -2680,9 +2680,9 @@ void Bot::checkRadioQueue () {
int index = findDefendNode (m_radioEntity->v.origin); 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.float_ (30.0f, 60.0f), true); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true);
// push move command // push move command
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.float_ (30.0f, 60.0f), true); startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (30.0f, 60.0f), true);
if (graph[index].vis.crouch <= graph[index].vis.stand) { if (graph[index].vis.crouch <= graph[index].vis.stand) {
m_campButtons |= IN_DUCK; m_campButtons |= IN_DUCK;
@ -2808,7 +2808,7 @@ void Bot::updateAimDir () {
auto radius = graph[index].radius; auto radius = graph[index].radius;
if (radius > 0.0f) { if (radius > 0.0f) {
return Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.float_ (-90.0f, 90.0f)), 0.0f).forward () * rg.float_ (2.0f, 4.0); return Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (2.0f, 4.0f);
} }
return nullptr; return nullptr;
}; };
@ -3037,7 +3037,7 @@ void Bot::choiceFreezetimeEntity () {
m_lookAt = bot->pev->origin + bot->pev->view_ofs; m_lookAt = bot->pev->origin + bot->pev->view_ofs;
} }
} }
m_changeViewTime = game.time () + rg.float_ (1.25, 2.0f); m_changeViewTime = game.time () + rg.get (1.25f, 2.0f);
} }
void Bot::normal_ () { void Bot::normal_ () {
@ -3070,7 +3070,7 @@ void Bot::normal_ () {
else { else {
pev->button |= IN_ATTACK2; pev->button |= IN_ATTACK2;
} }
m_knifeAttackTime = game.time () + rg.float_ (2.5f, 6.0f); m_knifeAttackTime = game.time () + rg.get (2.5f, 6.0f);
} }
const auto &prop = conf.getWeaponProp (m_currentWeapon); const auto &prop = conf.getWeaponProp (m_currentWeapon);
@ -3144,7 +3144,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.float_ (10.0f, 25.0f); m_timeCamping = game.time () + rg.get (10.0f, 25.0f);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, m_timeCamping, true); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, m_timeCamping, true);
m_camp = m_path->origin + m_path->start.forward () * 500.0f; m_camp = m_path->origin + m_path->start.forward () * 500.0f;
@ -3176,8 +3176,8 @@ void Bot::normal_ () {
else if (m_team == Team::Terrorist && rg.chance (75)) { else if (m_team == Team::Terrorist && rg.chance (75)) {
int index = findDefendNode (m_path->origin); int index = findDefendNode (m_path->origin);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.float_ (60.0f, 120.0f), true); // push camp task on to stack startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (60.0f, 120.0f), true); // push camp task on to stack
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.float_ (5.0f, 10.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (5.0f, 10.0f), true); // push move command
auto &path = graph[index]; auto &path = graph[index];
@ -3199,7 +3199,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.float_ (4.0f, 8.0f), true); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (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);
@ -3209,14 +3209,14 @@ void Bot::normal_ () {
if (!bots.isBombPlanted () && numFriendsNear (pev->origin, 210.0f) < 4) { if (!bots.isBombPlanted () && numFriendsNear (pev->origin, 210.0f) < 4) {
int index = findDefendNode (m_path->origin); int index = findDefendNode (m_path->origin);
float campTime = rg.float_ (25.0f, 40.f); float campTime = rg.get (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.float_ (5.0f, 11.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (5.0f, 11.0f), true); // push move command
auto &path = graph[index]; auto &path = graph[index];
@ -3277,15 +3277,15 @@ 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 && m_seeEnemyTime + rg.float_ (45.0f, 80.0f) < game.time () && bots.getLastRadio (m_team) != Radio::ReportInTeam && rg.chance (15) && bots.getRoundStartTime () + 20.0f < game.time () && m_askCheckTime < game.time () && numFriendsNear (pev->origin, 1024.0f) == 0) { if (cv_radio_mode.int_ () > 1 && bots.getLastRadio (m_team) != Radio::ReportInTeam && bots.getRoundStartTime () + 20.0f < game.time () && m_askCheckTime < game.time () && rg.chance (15) && m_seeEnemyTime + rg.get (45.0f, 80.0f) < game.time () && numFriendsNear (pev->origin, 1024.0f) == 0) {
pushRadioMessage (Radio::ReportInTeam); pushRadioMessage (Radio::ReportInTeam);
m_askCheckTime = game.time () + rg.float_ (45.0f, 80.0f); m_askCheckTime = game.time () + rg.get (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_notKilled) { if (bot->m_notKilled) {
bot->m_askCheckTime = game.time () + rg.float_ (5.0f, 30.0f); bot->m_askCheckTime = game.time () + rg.get (5.0f, 30.0f);
} }
} }
} }
@ -3315,7 +3315,7 @@ void Bot::spraypaint_ () {
// paint the actual logo decal // paint the actual logo decal
util.traceDecals (pev, &tr, m_logotypeIndex); util.traceDecals (pev, &tr, m_logotypeIndex);
m_timeLogoSpray = game.time () + rg.float_ (60.0f, 90.0f); m_timeLogoSpray = game.time () + rg.get (60.0f, 90.0f);
} }
} }
else { else {
@ -3416,7 +3416,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.float_ (3.0f, 12.0f), false); startTask (Task::Hide, TaskPri::Hide, kInvalidNodeIndex, game.time () + rg.get (3.0f, 12.0f), false);
Vector dest = m_lastEnemyOrigin; Vector dest = m_lastEnemyOrigin;
// get a valid look direction // get a valid look direction
@ -3470,7 +3470,7 @@ void Bot::seekCover_ () {
destIndex = findCoverNode (usesSniper () ? 256.0f : 512.0f); destIndex = findCoverNode (usesSniper () ? 256.0f : 512.0f);
if (destIndex == kInvalidNodeIndex) { if (destIndex == kInvalidNodeIndex) {
m_retreatTime = game.time () + rg.float_ (5.0f, 10.0f); m_retreatTime = game.time () + rg.get (5.0f, 10.0f);
m_prevGoalIndex = kInvalidNodeIndex; m_prevGoalIndex = kInvalidNodeIndex;
completeTask (); completeTask ();
@ -3589,7 +3589,7 @@ void Bot::camp_ () {
findValidNode (); findValidNode ();
if (m_nextCampDirTime < game.time ()) { if (m_nextCampDirTime < game.time ()) {
m_nextCampDirTime = game.time () + rg.float_ (2.0f, 5.0f); m_nextCampDirTime = game.time () + rg.get (2.0f, 5.0f);
if (m_path->flags & NodeFlag::Camp) { if (m_path->flags & NodeFlag::Camp) {
Vector dest; Vector dest;
@ -3644,7 +3644,7 @@ void Bot::camp_ () {
} }
if (--numFoundPoints >= 0) { if (--numFoundPoints >= 0) {
m_camp = graph[campPoints[rg.int_ (0, numFoundPoints)]].origin; m_camp = graph[campPoints[rg.get (0, numFoundPoints)]].origin;
} }
else { else {
m_camp = graph[findCampingDirection ()].origin; m_camp = graph[findCampingDirection ()].origin;
@ -3843,8 +3843,8 @@ void Bot::defuseBomb_ () {
if (bot->m_team == m_team && bot->m_notKilled) { if (bot->m_team == m_team && bot->m_notKilled) {
auto defendPoint = graph.getFarest (bot->pev->origin); auto defendPoint = graph.getFarest (bot->pev->origin);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.float_ (30.0f, 60.0f), true); // push camp task on to stack startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true); // push camp task on to stack
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, defendPoint, game.time () + rg.float_ (3.0f, 6.0f), true); // push move command startTask (Task::MoveToPosition, TaskPri::MoveToPosition, defendPoint, game.time () + rg.get (3.0f, 6.0f), true); // push move command
} }
} }
graph.setBombOrigin (true); graph.setBombOrigin (true);
@ -4310,7 +4310,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.float_ (3.0f, 5.0f); m_duckForJump = game.time () + rg.get (3.0f, 5.0f);
getTask ()->time = game.time (); getTask ()->time = game.time ();
} }
return; return;
@ -4383,7 +4383,7 @@ void Bot::escapeFromBomb_ () {
clearSearchNodes (); clearSearchNodes ();
int lastSelectedGoal = kInvalidNodeIndex, minPathDistance = kInfiniteDistanceLong; int lastSelectedGoal = kInvalidNodeIndex, minPathDistance = kInfiniteDistanceLong;
float safeRadius = rg.float_ (1513.0f, 2048.0f); float safeRadius = rg.get (1513.0f, 2048.0f);
for (int i = 0; i < graph.length (); ++i) { for (int i = 0; i < graph.length (); ++i) {
if ((graph[i].origin - graph.getBombOrigin ()).length () < safeRadius || isOccupiedNode (i)) { if ((graph[i].origin - graph.getBombOrigin ()).length () < safeRadius || isOccupiedNode (i)) {
@ -4658,8 +4658,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.float_ (5.0f, 7.5f) < game.time ()) { if (m_checkKnifeSwitch && m_buyingFinished && m_spawnTime + rg.get (5.0f, 7.5f) < game.time ()) {
if (rg.int_ (1, 100) < 2 && cv_spraypaints.bool_ ()) { if (rg.get (1, 100) < 2 && cv_spraypaints.bool_ ()) {
startTask (Task::Spraypaint, TaskPri::Spraypaint, kInvalidNodeIndex, game.time () + 1.0f, false); startTask (Task::Spraypaint, TaskPri::Spraypaint, kInvalidNodeIndex, game.time () + 1.0f, false);
} }
@ -4680,7 +4680,7 @@ void Bot::checkSpawnConditions () {
} }
// check if we already switched weapon mode // check if we already switched weapon mode
if (m_checkWeaponSwitch && m_buyingFinished && m_spawnTime + rg.float_ (3.0f, 4.5f) < game.time ()) { if (m_checkWeaponSwitch && m_buyingFinished && m_spawnTime + rg.get (3.0f, 4.5f) < game.time ()) {
if (hasShield () && isShieldDrawn ()) { if (hasShield () && isShieldDrawn ()) {
pev->button |= IN_ATTACK2; pev->button |= IN_ATTACK2;
} }
@ -5161,7 +5161,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_maxViewDistance = rg.float_ (10.0f, 20.0f); m_maxViewDistance = rg.get (10.0f, 20.0f);
m_blindTime = game.time () + static_cast <float> (alpha - 200) / 16.0f; m_blindTime = game.time () + static_cast <float> (alpha - 200) / 16.0f;
if (m_blindTime < game.time ()) { if (m_blindTime < game.time ()) {
@ -5776,7 +5776,7 @@ void Bot::enteredBuyZone (int buyState) {
const int *econLimit = conf.getEconLimit (); const int *econLimit = conf.getEconLimit ();
// if bot is in buy zone, try to buy ammo for this weapon... // if bot is in buy zone, try to buy ammo for this weapon...
if (m_seeEnemyTime + 12.0f < game.time () && m_lastEquipTime + 15.0f < game.time () && m_inBuyZone && (bots.getRoundStartTime () + rg.float_ (10.0f, 20.0f) + mp_buytime.float_ () < game.time ()) && !bots.isBombPlanted () && m_moneyAmount > econLimit[EcoLimit::PrimaryGreater]) { if (m_seeEnemyTime + 12.0f < game.time () && m_lastEquipTime + 15.0f < game.time () && m_inBuyZone && (bots.getRoundStartTime () + rg.get (10.0f, 20.0f) + mp_buytime.float_ () < game.time ()) && !bots.isBombPlanted () && m_moneyAmount > econLimit[EcoLimit::PrimaryGreater]) {
m_ignoreBuyDelay = true; m_ignoreBuyDelay = true;
m_buyingFinished = false; m_buyingFinished = false;
m_buyState = buyState; m_buyState = buyState;

View file

@ -61,19 +61,19 @@ void BotSupport::addChatErrors (String &line) {
if (rg.chance (8) && strcmp (cv_language.str (), "en") == 0) { if (rg.chance (8) && strcmp (cv_language.str (), "en") == 0) {
line.lowercase (); line.lowercase ();
} }
auto length = line.length (); auto length = static_cast <int32> (line.length ());
if (length > 15) { if (length > 15) {
size_t percentile = line.length () / 2; auto percentile = length / 2;
// "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 (rg.int_ (length / 8, length - length / 8), 1); line.erase (rg.get (length / 8, length - length / 8), 1);
} }
// "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 = rg.int_ (length / 8, 3 * length / 8); // choose random position in string size_t pos = rg.get (length / 8, 3 * length / 8); // choose random position in string
cr::swap (line[pos], line[pos + 1]); cr::swap (line[pos], line[pos + 1]);
} }
} }
@ -301,10 +301,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.float_ (m_sayTextBuffer.chatDelay / 2, m_sayTextBuffer.chatDelay)) { if (m_sayTextBuffer.timeNextChat < game.time () + rg.get (m_sayTextBuffer.chatDelay / 2, m_sayTextBuffer.chatDelay)) {
String replyText; String replyText;
if (rg.chance (m_sayTextBuffer.chatProbability + rg.int_ (40, 70)) && checkChatKeywords (replyText)) { if (rg.chance (m_sayTextBuffer.chatProbability + rg.get (40, 70)) && checkChatKeywords (replyText)) {
prepareChatMessage (replyText); prepareChatMessage (replyText);
pushMsgQueue (BotMsg::Say); pushMsgQueue (BotMsg::Say);
@ -329,7 +329,7 @@ void Bot::checkForChat () {
} }
// bot chatting turned on? // bot chatting turned on?
if (m_lastChatTime + rg.float_ (6.0f, 10.0f) < game.time () && bots.getLastChatTimestamp () + rg.float_ (2.5f, 5.0f) < game.time () && !isReplyingToChat ()) { if (m_lastChatTime + rg.get (6.0f, 10.0f) < game.time () && bots.getLastChatTimestamp () + rg.get (2.5f, 5.0f) < game.time () && !isReplyingToChat ()) {
if (conf.hasChatBank (Chat::Dead)) { if (conf.hasChatBank (Chat::Dead)) {
StringRef phrase = conf.pickRandomFromChatBank (Chat::Dead); StringRef phrase = conf.pickRandomFromChatBank (Chat::Dead);
bool sayBufferExists = false; bool sayBufferExists = false;
@ -355,7 +355,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.int_ (4, 6)) { if (static_cast <int> (m_sayTextBuffer.lastUsedSentences.length ()) > rg.get (4, 6)) {
m_sayTextBuffer.lastUsedSentences.clear (); m_sayTextBuffer.lastUsedSentences.clear ();
} }
} }

View file

@ -421,8 +421,8 @@ Vector Bot::getBodyOffsetError (float distance) {
const float error = distance / (cr::clamp (m_difficulty, 1, 3) * 1000.0f); const float error = distance / (cr::clamp (m_difficulty, 1, 3) * 1000.0f);
Vector &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins; Vector &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins;
m_aimLastError = Vector (rg.float_ (mins.x * error, maxs.x * error), rg.float_ (mins.y * error, maxs.y * error), rg.float_ (mins.z * error, maxs.z * error)); m_aimLastError = Vector (rg.get (mins.x * error, maxs.x * error), rg.get (mins.y * error, maxs.y * error), rg.get (mins.z * error, maxs.z * error));
m_aimErrorTime = game.time () + rg.float_ (0.5f, 1.0f); m_aimErrorTime = game.time () + rg.get (0.5f, 1.0f);
} }
return m_aimLastError; return m_aimLastError;
} }
@ -526,9 +526,6 @@ float Bot::getEnemyBodyOffsetCorrection (float distance) {
else if (distance > kSprayDistance && distance <= kDoubleSprayDistance) { else if (distance > kSprayDistance && distance <= kDoubleSprayDistance) {
distanceIndex = DistanceIndex::Middle; distanceIndex = DistanceIndex::Middle;
} }
else if (distance < kSprayDistance) {
distanceIndex = DistanceIndex::Short;
}
return offsetRanges[m_weaponType][distanceIndex]; return offsetRanges[m_weaponType][distanceIndex];
} }
@ -692,7 +689,7 @@ bool Bot::needToPauseFiring (float distance) {
// check if we need to compensate recoil // check if we need to compensate recoil
if (cr::tanf (cr::sqrtf (cr::abs (xPunch * xPunch) + cr::abs (yPunch * yPunch))) * distance > offset + 30.0f + tolerance) { if (cr::tanf (cr::sqrtf (cr::abs (xPunch * xPunch) + cr::abs (yPunch * yPunch))) * distance > offset + 30.0f + tolerance) {
if (m_firePause < game.time ()) { if (m_firePause < game.time ()) {
m_firePause = rg.float_ (0.65f, 0.65f + 0.3f * tolerance); m_firePause = rg.get (0.65f, 0.65f + 0.3f * tolerance);
} }
m_firePause -= interval; m_firePause -= interval;
m_firePause += game.time (); m_firePause += game.time ();
@ -850,7 +847,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.float_ (minDelay[offset], maxDelay[offset]); m_shootTime = game.time () + 0.1f + rg.get (minDelay[offset], maxDelay[offset]);
m_zoomCheckTime = game.time (); m_zoomCheckTime = game.time ();
} }
} }
@ -922,7 +919,7 @@ void Bot::fireWeapons () {
m_reloadState = Reload::Primary; m_reloadState = Reload::Primary;
m_reloadCheckTime = game.time (); m_reloadCheckTime = game.time ();
if (rg.chance (cr::abs (m_difficulty * 25 - 100)) && rg.chance (5)) { if (rg.chance (cr::abs (m_difficulty * 25 - 100)) && rg.chance (15)) {
pushRadioMessage (Radio::NeedBackup); pushRadioMessage (Radio::NeedBackup);
} }
} }
@ -1068,7 +1065,7 @@ void Bot::attackMovement () {
} }
else if (usesRifle () || usesSubmachine ()) { else if (usesRifle () || usesSubmachine ()) {
if (m_lastFightStyleCheck + 3.0f < game.time ()) { if (m_lastFightStyleCheck + 3.0f < game.time ()) {
int rand = rg.int_ (1, 100); int rand = rg.get (1, 100);
if (distance < 450.0f) { if (distance < 450.0f) {
m_fightStyle = Fight::Strafe; m_fightStyle = Fight::Strafe;
@ -1113,7 +1110,7 @@ void Bot::attackMovement () {
if (rg.chance (30)) { if (rg.chance (30)) {
m_combatStrafeDir = (m_combatStrafeDir == Dodge::Left ? Dodge::Right : Dodge::Left); m_combatStrafeDir = (m_combatStrafeDir == Dodge::Left ? Dodge::Right : Dodge::Left);
} }
m_strafeSetTime = game.time () + rg.float_ (0.5f, 3.0f); m_strafeSetTime = game.time () + rg.get (0.5f, 3.0f);
} }
if (m_combatStrafeDir == Dodge::Right) { if (m_combatStrafeDir == Dodge::Right) {
@ -1122,7 +1119,7 @@ void Bot::attackMovement () {
} }
else { else {
m_combatStrafeDir = Dodge::Left; m_combatStrafeDir = Dodge::Left;
m_strafeSetTime = game.time () + rg.float_ (0.8f, 1.1f); m_strafeSetTime = game.time () + rg.get (0.8f, 1.1f);
} }
} }
else { else {
@ -1131,11 +1128,11 @@ void Bot::attackMovement () {
} }
else { else {
m_combatStrafeDir = Dodge::Right; m_combatStrafeDir = Dodge::Right;
m_strafeSetTime = game.time () + rg.float_ (0.8f, 1.1f); m_strafeSetTime = game.time () + rg.get (0.8f, 1.1f);
} }
} }
if (m_difficulty >= Difficulty::Hard && (m_jumpTime + 5.0f < game.time () && isOnFloor () && rg.int_ (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.length2d () > 120.0f) && !usesSniper ()) { if (m_difficulty >= Difficulty::Hard && (m_jumpTime + 5.0f < game.time () && isOnFloor () && rg.get (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.length2d () > 120.0f) && !usesSniper ()) {
pev->button |= IN_JUMP; pev->button |= IN_JUMP;
} }
@ -1517,7 +1514,7 @@ void Bot::updateTeamCommands () {
else if (memberExists && cv_radio_mode.int_ () == 2) { else if (memberExists && cv_radio_mode.int_ () == 2) {
pushChatterMessage (Chatter::ScaredEmotion); pushChatterMessage (Chatter::ScaredEmotion);
} }
m_timeTeamOrder = game.time () + rg.float_ (15.0f, 30.0f); m_timeTeamOrder = game.time () + rg.get (15.0f, 30.0f);
} }
bool Bot::isGroupOfEnemies (const Vector &location, int numEnemies, float radius) { bool Bot::isGroupOfEnemies (const Vector &location, int numEnemies, float radius) {

View file

@ -1573,7 +1573,7 @@ bool BotControl::executeCommands () {
String cmd; String cmd;
// give some help // give some help
if (hasArg (1) && m_args[1] == "help") { if (hasArg (1) && strValue (1) == "help") {
const auto hasSecondArg = hasArg (2); const auto hasSecondArg = hasArg (2);
for (auto &item : m_cmds) { for (auto &item : m_cmds) {
@ -1581,7 +1581,7 @@ bool BotControl::executeCommands () {
cmd = item.name.split ("/")[0]; cmd = item.name.split ("/")[0];
} }
if ((hasSecondArg && aliasMatch (item.name, m_args[2], cmd)) || !hasSecondArg) { if (!hasSecondArg || aliasMatch (item.name, strValue (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));
@ -1605,7 +1605,7 @@ bool BotControl::executeCommands () {
return true; return true;
} }
else { else {
msg ("No help found for \"%s\"", m_args[2]); msg ("No help found for \"%s\"", strValue (2));
} }
return true; return true;
} }

View file

@ -1152,8 +1152,8 @@ void BotGraph::calculatePathRadius (int index) {
for (float circleRadius = 0.0f; circleRadius < 360.0f; circleRadius += 20.0f) { for (float circleRadius = 0.0f; circleRadius < 360.0f; circleRadius += 20.0f) {
const auto &forward = direction.forward (); const auto &forward = direction.forward ();
Vector radiusStart = start + forward * scanDistance; auto radiusStart = start + forward * scanDistance;
Vector radiusEnd = start + forward * scanDistance; auto radiusEnd = start + forward * scanDistance;
game.testHull (radiusStart, radiusEnd, TraceIgnore::Monsters, head_hull, nullptr, &tr); game.testHull (radiusStart, radiusEnd, TraceIgnore::Monsters, head_hull, nullptr, &tr);
@ -1172,8 +1172,8 @@ void BotGraph::calculatePathRadius (int index) {
break; break;
} }
Vector dropStart = start + forward * scanDistance; auto dropStart = start + forward * scanDistance;
Vector dropEnd = dropStart - Vector (0.0f, 0.0f, scanDistance + 60.0f); auto dropEnd = dropStart - Vector (0.0f, 0.0f, scanDistance + 60.0f);
game.testHull (dropStart, dropEnd, TraceIgnore::Monsters, head_hull, nullptr, &tr); game.testHull (dropStart, dropEnd, TraceIgnore::Monsters, head_hull, nullptr, &tr);

View file

@ -173,7 +173,7 @@ BotCreateResult BotManager::create (StringRef name, int difficulty, int personal
difficulty = cv_difficulty.int_ (); difficulty = cv_difficulty.int_ ();
if (difficulty < 0 || difficulty > 4) { if (difficulty < 0 || difficulty > 4) {
difficulty = rg.int_ (3, 4); difficulty = rg.get (3, 4);
cv_difficulty.set (difficulty); cv_difficulty.set (difficulty);
} }
} }
@ -201,7 +201,7 @@ BotCreateResult BotManager::create (StringRef name, int difficulty, int personal
resultName = botName->name; resultName = botName->name;
} }
else { else {
resultName.assignf ("%s_%d.%d", product.folder, rg.int_ (100, 10000), rg.int_ (100, 10000)); // just pick ugly random name resultName.assignf ("%s_%d.%d", product.folder, rg.get (100, 10000), rg.get (100, 10000)); // just pick ugly random name
} }
} }
else { else {
@ -756,13 +756,7 @@ float BotManager::getConnectTime (int botId, float original) {
for (const auto &bot : m_bots) { for (const auto &bot : m_bots) {
if (bot->entindex () == botId) { if (bot->entindex () == botId) {
auto current = plat.seconds (); return bot->getConnectionTime ();
if (current - bot->m_joinServerTime > bot->m_playServerTime || current - bot->m_joinServerTime <= 0.0f) {
bot->m_playServerTime = 60.0f * rg.float_ (30.0f, 240.0f);
bot->m_joinServerTime = current - bot->m_playServerTime * rg.float_ (0.2f, 0.8f);
}
return current - bot->m_joinServerTime;
} }
} }
return original; return original;
@ -974,8 +968,8 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) {
m_logotypeIndex = conf.getRandomLogoIndex (); m_logotypeIndex = conf.getRandomLogoIndex ();
// assign how talkative this bot will be // assign how talkative this bot will be
m_sayTextBuffer.chatDelay = rg.float_ (3.8f, 10.0f); m_sayTextBuffer.chatDelay = rg.get (3.8f, 10.0f);
m_sayTextBuffer.chatProbability = rg.int_ (10, 100); m_sayTextBuffer.chatProbability = rg.get (10, 100);
m_notKilled = false; m_notKilled = false;
m_weaponBurstMode = BurstMode::Off; m_weaponBurstMode = BurstMode::Off;
@ -989,9 +983,9 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) {
if (maxDifficulty > minDifficulty) { if (maxDifficulty > minDifficulty) {
cr::swap (maxDifficulty, minDifficulty); cr::swap (maxDifficulty, minDifficulty);
} }
m_difficulty = rg.int_ (minDifficulty, maxDifficulty); m_difficulty = rg.get (minDifficulty, maxDifficulty);
} }
m_basePing = rg.int_ (7, 14); m_basePing = rg.get (7, 14);
m_lastCommandTime = game.time () - 0.1f; m_lastCommandTime = game.time () - 0.1f;
m_frameInterval = game.time (); m_frameInterval = game.time ();
@ -1000,26 +994,26 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) {
m_kpdRatio = 0.0f; m_kpdRatio = 0.0f;
// stuff from jk_botti // stuff from jk_botti
m_playServerTime = 60.0f * rg.float_ (30.0f, 240.0f); m_playServerTime = 60.0f * rg.get (30.0f, 240.0f);
m_joinServerTime = plat.seconds () - m_playServerTime * rg.float_ (0.2f, 0.8f); m_joinServerTime = plat.seconds () - m_playServerTime * rg.get (0.2f, 0.8f);
switch (personality) { switch (personality) {
case 1: case 1:
m_personality = Personality::Rusher; m_personality = Personality::Rusher;
m_baseAgressionLevel = rg.float_ (0.7f, 1.0f); m_baseAgressionLevel = rg.get (0.7f, 1.0f);
m_baseFearLevel = rg.float_ (0.0f, 0.4f); m_baseFearLevel = rg.get (0.0f, 0.4f);
break; break;
case 2: case 2:
m_personality = Personality::Careful; m_personality = Personality::Careful;
m_baseAgressionLevel = rg.float_ (0.2f, 0.5f); m_baseAgressionLevel = rg.get (0.2f, 0.5f);
m_baseFearLevel = rg.float_ (0.7f, 1.0f); m_baseFearLevel = rg.get (0.7f, 1.0f);
break; break;
default: default:
m_personality = Personality::Normal; m_personality = Personality::Normal;
m_baseAgressionLevel = rg.float_ (0.4f, 0.7f); m_baseAgressionLevel = rg.get (0.4f, 0.7f);
m_baseFearLevel = rg.float_ (0.4f, 0.7f); m_baseFearLevel = rg.get (0.4f, 0.7f);
break; break;
} }
@ -1029,7 +1023,7 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) {
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.int_ (80, 115); // assign voice pitch m_voicePitch = rg.get (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;
@ -1051,6 +1045,16 @@ float Bot::getFrameInterval () {
return m_frameInterval; return m_frameInterval;
} }
float Bot::getConnectionTime () {
auto current = plat.seconds ();
if (current - m_joinServerTime > m_playServerTime || current - m_joinServerTime <= 0.0f) {
m_playServerTime = 60.0f * rg.get (30.0f, 240.0f);
m_joinServerTime = current - m_playServerTime * rg.get (0.2f, 0.8f);
}
return current - m_joinServerTime;
}
int BotManager::getHumansCount (bool ignoreSpectators) { int BotManager::getHumansCount (bool ignoreSpectators) {
// this function returns number of humans playing on the server // this function returns number of humans playing on the server
@ -1227,7 +1231,7 @@ void Bot::newRound () {
m_preventFlashing = 0.0f; m_preventFlashing = 0.0f;
m_timeTeamOrder = 0.0f; m_timeTeamOrder = 0.0f;
m_askCheckTime = rg.float_ (30.0f, 90.0f); m_askCheckTime = rg.get (30.0f, 90.0f);
m_minSpeed = 260.0f; m_minSpeed = 260.0f;
m_prevSpeed = 0.0f; m_prevSpeed = 0.0f;
m_prevOrigin = Vector (kInfiniteDistance, kInfiniteDistance, kInfiniteDistance); m_prevOrigin = Vector (kInfiniteDistance, kInfiniteDistance, kInfiniteDistance);
@ -1331,8 +1335,8 @@ void Bot::newRound () {
m_flashLevel = 100.0f; m_flashLevel = 100.0f;
m_checkDarkTime = game.time (); m_checkDarkTime = game.time ();
m_knifeAttackTime = game.time () + rg.float_ (1.3f, 2.6f); m_knifeAttackTime = game.time () + rg.get (1.3f, 2.6f);
m_nextBuyTime = game.time () + rg.float_ (0.6f, 2.0f); m_nextBuyTime = game.time () + rg.get (0.6f, 2.0f);
m_buyPending = false; m_buyPending = false;
m_inBombZone = false; m_inBombZone = false;
@ -1357,7 +1361,7 @@ void Bot::newRound () {
m_defendHostage = false; m_defendHostage = false;
m_headedTime = 0.0f; m_headedTime = 0.0f;
m_timeLogoSpray = game.time () + rg.float_ (5.0f, 30.0f); m_timeLogoSpray = game.time () + rg.get (5.0f, 30.0f);
m_spawnTime = game.time (); m_spawnTime = game.time ();
m_lastChatTime = game.time (); m_lastChatTime = game.time ();
@ -1475,7 +1479,7 @@ void Bot::updateTeamJoin () {
int maxChoice = game.is (GameFlags::ConditionZero) ? 5 : 4; int maxChoice = game.is (GameFlags::ConditionZero) ? 5 : 4;
if (m_wantedClass < 1 || m_wantedClass > maxChoice) { if (m_wantedClass < 1 || m_wantedClass > maxChoice) {
m_wantedClass = rg.int_ (1, maxChoice); // use random if invalid m_wantedClass = rg.get (1, maxChoice); // use random if invalid
} }
// select the class the bot wishes to use... // select the class the bot wishes to use...

View file

@ -128,10 +128,10 @@ int Bot::findBestGoal () {
} }
} }
goalDesire = rg.float_ (0.0f, 100.0f) + offensive; goalDesire = rg.get (0.0f, 100.0f) + offensive;
forwardDesire = rg.float_ (0.0f, 100.0f) + offensive; forwardDesire = rg.get (0.0f, 100.0f) + offensive;
campDesire = rg.float_ (0.0f, 100.0f) + defensive; campDesire = rg.get (0.0f, 100.0f) + defensive;
backoffDesire = rg.float_ (0.0f, 100.0f) + defensive; backoffDesire = rg.get (0.0f, 100.0f) + defensive;
if (!usesCampGun ()) { if (!usesCampGun ()) {
campDesire *= 0.5f; campDesire *= 0.5f;
@ -214,7 +214,7 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive) {
} }
if (goalChoices[0] == kInvalidNodeIndex) { if (goalChoices[0] == kInvalidNodeIndex) {
return m_chosenGoalIndex = rg.int_ (0, graph.length () - 1); return m_chosenGoalIndex = rg.get (0, graph.length () - 1);
} }
bool sorting = false; bool sorting = false;
@ -651,7 +651,7 @@ bool Bot::updateNavigation () {
// if graph node radius non zero vary origin a bit depending on the body angles // if graph node radius non zero vary origin a bit depending on the body angles
if (m_path->radius > 0.0f) { if (m_path->radius > 0.0f) {
m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.float_ (-90.0f, 90.0f)), 0.0f).forward () * rg.float_ (0.0f, m_path->radius); m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius);
} }
m_navTimeset = game.time (); m_navTimeset = game.time ();
} }
@ -1535,7 +1535,7 @@ bool Bot::findBestNearestNode () {
int lessIndex[3] = { kInvalidNodeIndex, kInvalidNodeIndex , kInvalidNodeIndex }; int lessIndex[3] = { kInvalidNodeIndex, kInvalidNodeIndex , kInvalidNodeIndex };
auto &bucket = graph.getNodesInBucket (pev->origin); auto &bucket = graph.getNodesInBucket (pev->origin);
int numToSkip = cr::clamp (rg.int_ (0, 3), 0, static_cast <int> (bucket.length () / 2)); int numToSkip = cr::clamp (rg.get (0, 3), 0, static_cast <int> (bucket.length () / 2));
for (const int at : bucket) { for (const int at : bucket) {
bool skip = !!(at == m_currentNodeIndex); bool skip = !!(at == m_currentNodeIndex);
@ -1611,10 +1611,10 @@ bool Bot::findBestNearestNode () {
// choice from found // choice from found
if (lessIndex[2] != kInvalidNodeIndex) { if (lessIndex[2] != kInvalidNodeIndex) {
index = rg.int_ (0, 2); index = rg.get (0, 2);
} }
else if (lessIndex[1] != kInvalidNodeIndex) { else if (lessIndex[1] != kInvalidNodeIndex) {
index = rg.int_ (0, 1); index = rg.get (0, 1);
} }
else if (lessIndex[0] != kInvalidNodeIndex) { else if (lessIndex[0] != kInvalidNodeIndex) {
index = 0; index = 0;
@ -1828,7 +1828,7 @@ int Bot::findDefendNode (const Vector &origin) {
// some of points not found, return random one // some of points not found, return random one
if (srcIndex == kInvalidNodeIndex || posIndex == kInvalidNodeIndex) { if (srcIndex == kInvalidNodeIndex || posIndex == kInvalidNodeIndex) {
return rg.int_ (0, graph.length () - 1); return rg.get (0, graph.length () - 1);
} }
// find the best node now // find the best node now
@ -1895,7 +1895,7 @@ int Bot::findDefendNode (const Vector &origin) {
} }
if (found.empty ()) { if (found.empty ()) {
return rg.int_ (0, graph.length () - 1); // most worst case, since there a evil error in nodes return rg.get (0, graph.length () - 1); // most worst case, since there a evil error in nodes
} }
return found.random (); return found.random ();
} }
@ -1906,7 +1906,7 @@ int Bot::findDefendNode (const Vector &origin) {
break; break;
} }
} }
return nodeIndex[rg.int_ (0, (index -1) / 2)]; return nodeIndex[rg.get (0, (index -1) / 2)];
} }
int Bot::findCoverNode (float maxDistance) { int Bot::findCoverNode (float maxDistance) {
@ -2119,8 +2119,8 @@ bool Bot::advanceMovement () {
} }
if (m_baseAgressionLevel < kills && hasPrimaryWeapon ()) { if (m_baseAgressionLevel < kills && hasPrimaryWeapon ()) {
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.float_ (static_cast <float> (m_difficulty / 2), static_cast <float> (m_difficulty)) * 5.0f, true); 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::MoveToPosition, TaskPri::MoveToPosition, findDefendNode (graph[nextIndex].origin), game.time () + rg.float_ (3.0f, 10.0f), true); startTask (Task::MoveToPosition, TaskPri::MoveToPosition, findDefendNode (graph[nextIndex].origin), game.time () + rg.get (3.0f, 10.0f), true);
} }
} }
else if (bots.canPause () && !isOnLadder () && !isInWater () && !m_currentTravelFlags && isOnFloor ()) { else if (bots.canPause () && !isOnLadder () && !isInWater () && !m_currentTravelFlags && isOnFloor ()) {
@ -2206,7 +2206,7 @@ bool Bot::advanceMovement () {
// if wayzone radius non zero vary origin a bit depending on the body angles // if wayzone radius non zero vary origin a bit depending on the body angles
if (m_path->radius > 0.0f) { if (m_path->radius > 0.0f) {
m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.float_ (-90.0f, 90.0f)), 0.0f).forward () * rg.float_ (0.0f, m_path->radius); m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius);
} }
if (isOnLadder ()) { if (isOnLadder ()) {
@ -2799,9 +2799,9 @@ int Bot::findCampingDirection () {
count--; count--;
if (count >= 0) { if (count >= 0) {
return indices[rg.int_ (0, count)]; return indices[rg.get (0, count)];
} }
return rg.int_ (0, graph.length () - 1); return rg.get (0, graph.length () - 1);
} }
void Bot::updateBodyAngles () { void Bot::updateBodyAngles () {
@ -2910,10 +2910,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.float_ (-randomize.x * 0.5f, randomize.x * 1.5f), rg.float_ (-randomize.y, randomize.y), 0.0f); m_randomizedIdealAngles = m_idealAngles + Vector (rg.get (-randomize.x * 0.5f, randomize.x * 1.5f), rg.get (-randomize.y, randomize.y), 0.0f);
// set next time to do this // set next time to do this
m_randomizeAnglesTime = game.time () + rg.float_ (0.4f, offsetDelay); m_randomizeAnglesTime = game.time () + rg.get (0.4f, offsetDelay);
} }
float stiffnessMultiplier = noTargetRatio; float stiffnessMultiplier = noTargetRatio;

View file

@ -292,13 +292,13 @@ void BotSupport::checkWelcome () {
.writeShort (MessageWriter::fs16 (-1.0f, 13.0f)) .writeShort (MessageWriter::fs16 (-1.0f, 13.0f))
.writeShort (MessageWriter::fs16 (-1.0f, 13.0f)) .writeShort (MessageWriter::fs16 (-1.0f, 13.0f))
.writeByte (2) .writeByte (2)
.writeByte (rg.int_ (33, 255)) .writeByte (rg.get (33, 255))
.writeByte (rg.int_ (33, 255)) .writeByte (rg.get (33, 255))
.writeByte (rg.int_ (33, 255)) .writeByte (rg.get (33, 255))
.writeByte (0) .writeByte (0)
.writeByte (rg.int_ (230, 255)) .writeByte (rg.get (230, 255))
.writeByte (rg.int_ (230, 255)) .writeByte (rg.get (230, 255))
.writeByte (rg.int_ (230, 255)) .writeByte (rg.get (230, 255))
.writeByte (200) .writeByte (200)
.writeShort (MessageWriter::fu16 (0.0078125f, 8.0f)) .writeShort (MessageWriter::fu16 (0.0078125f, 8.0f))
.writeShort (MessageWriter::fu16 (2.0f, 8.0f)) .writeShort (MessageWriter::fu16 (2.0f, 8.0f))
@ -564,7 +564,7 @@ void BotSupport::calculatePings () {
engfuncs.pfnGetPlayerStats (client.ent, &ping, &loss); engfuncs.pfnGetPlayerStats (client.ent, &ping, &loss);
// store normal client ping // store normal client ping
client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping / 2 : rg.int_ (8, 16)); // getting player ping sometimes fails client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping / 2 : rg.get (8, 16)); // getting player ping sometimes fails
client.pingUpdate = true; // force resend ping client.pingUpdate = true; // force resend ping
++numHumans; ++numHumans;
@ -578,8 +578,8 @@ void BotSupport::calculatePings () {
average.second /= numHumans; average.second /= numHumans;
} }
else { else {
average.first = rg.int_ (30, 40); average.first = rg.get (30, 40);
average.second = rg.int_ (5, 10); average.second = rg.get (5, 10);
} }
// now calculate bot ping based on average from players // now calculate bot ping based on average from players
@ -595,14 +595,14 @@ void BotSupport::calculatePings () {
} }
int part = static_cast <int> (average.first * 0.2f); int part = static_cast <int> (average.first * 0.2f);
int botPing = bot->m_basePing + rg.int_ (average.first - part, average.first + part) + rg.int_ (bot->m_difficulty / 2, bot->m_difficulty); int botPing = bot->m_basePing + rg.get (average.first - part, average.first + part) + rg.get (bot->m_difficulty / 2, bot->m_difficulty);
int botLoss = rg.int_ (average.second / 2, average.second); int botLoss = rg.get (average.second / 2, average.second);
if (botPing <= 5) { if (botPing <= 5) {
botPing = rg.int_ (10, 23); botPing = rg.get (10, 23);
} }
else if (botPing > 70) { else if (botPing > 70) {
botPing = rg.int_ (30, 40); botPing = rg.get (30, 40);
} }
client.ping = getPingBitmask (client.ent, botLoss, botPing); client.ping = getPingBitmask (client.ent, botLoss, botPing);
@ -627,7 +627,7 @@ void BotSupport::sendPings (edict_t *to) {
// no ping, no fun // no ping, no fun
if (!client.ping) { if (!client.ping) {
client.ping = getPingBitmask (client.ent, rg.int_ (5, 10), rg.int_ (15, 40)); client.ping = getPingBitmask (client.ent, rg.get (5, 10), rg.get (15, 40));
} }
msg.start (MSG_ONE_UNRELIABLE, kGamePingSVC, nullptr, to) msg.start (MSG_ONE_UNRELIABLE, kGamePingSVC, nullptr, to)