control: add g path_clean to remove all links from node (#475)

refactor: small cosmetic changes
This commit is contained in:
jeefo 2023-08-08 11:48:37 +03:00
commit fb301b7b19
No known key found for this signature in database
GPG key ID: 927BCA0779BEA8ED
23 changed files with 205 additions and 132 deletions

View file

@ -447,3 +447,8 @@ constexpr auto kSecondaryWeaponMask = (cr::bit (Weapon::P228) | cr::bit (Weapon:
// weapons < 7 are secondary // weapons < 7 are secondary
constexpr auto kPrimaryWeaponMinIndex = 7; constexpr auto kPrimaryWeaponMinIndex = 7;
// grenade model names
static constexpr StringRef kExplosiveModelName = "hegrenade.mdl";
static constexpr StringRef kFlashbangModelName = "flashbang.mdl";
static constexpr StringRef kSmokeModelName = "smokegrenade.mdl";

View file

@ -118,6 +118,7 @@ private:
int cmdNodePathCreate (); int cmdNodePathCreate ();
int cmdNodePathDelete (); int cmdNodePathDelete ();
int cmdNodePathSetAutoDistance (); int cmdNodePathSetAutoDistance ();
int cmdNodePathCleanAll ();
int cmdNodeAcquireEditor (); int cmdNodeAcquireEditor ();
int cmdNodeReleaseEditor (); int cmdNodeReleaseEditor ();
int cmdNodeUpload (); int cmdNodeUpload ();

View file

@ -111,7 +111,7 @@ public:
// provides utility functions to not call original engine (less call-cost) // provides utility functions to not call original engine (less call-cost)
class Game final : public Singleton <Game> { class Game final : public Singleton <Game> {
public: public:
using EntitySearch = Lambda <EntitySearchResult (edict_t *)>; using EntitySearch = const Lambda <EntitySearchResult (edict_t *)> &;
private: private:
int m_drawModels[DrawLine::Count] {}; int m_drawModels[DrawLine::Count] {};
@ -227,12 +227,12 @@ public:
} }
// get "maxplayers" limit on server // get "maxplayers" limit on server
int maxClients () const { int maxClients () const {
return globals->maxClients; return globals->maxClients;
} }
// get the fakeclient command interface // get the fakeclient command interface
bool isBotCmd () const { bool isBotCmd () const {
return !m_botArgs.empty (); return !m_botArgs.empty ();
} }

View file

@ -239,6 +239,7 @@ public:
void setRadius (int index, float radius); void setRadius (int index, float radius);
void pathCreate (char dir); void pathCreate (char dir);
void erasePath (); void erasePath ();
void resetPath (int index);
void cachePoint (int index); void cachePoint (int index);
void calculatePathRadius (int index); void calculatePathRadius (int index);
void addBasic (); void addBasic ();

View file

@ -20,7 +20,7 @@ struct BotRequest {
// manager class // manager class
class BotManager final : public Singleton <BotManager> { class BotManager final : public Singleton <BotManager> {
public: public:
using ForEachBot = Lambda <bool (Bot *)>; using ForEachBot = const Lambda <bool (Bot *)> &;
using UniqueBot = UniquePtr <Bot>; using UniqueBot = UniquePtr <Bot>;
private: private:

View file

@ -24,7 +24,7 @@ CR_DECLARE_SCOPED_ENUM (AStarResult,
) )
// node added // node added
using NodeAdderFn = Lambda <bool (int)>; using NodeAdderFn = const Lambda <bool (int)> &;
// route twin node // route twin node
template <typename HT> struct RouteTwin final { template <typename HT> struct RouteTwin final {

View file

@ -57,7 +57,7 @@ public:
// check if entity is a hostage entity // check if entity is a hostage entity
bool isHostageEntity (edict_t *ent); bool isHostageEntity (edict_t *ent);
// check if entity is a door enitty // check if entity is a door entity
bool isDoorEntity (edict_t *ent); bool isDoorEntity (edict_t *ent);
// this function is checking that pointed by ent pointer obstacle, can be destroyed // this function is checking that pointed by ent pointer obstacle, can be destroyed
@ -133,13 +133,13 @@ public:
} }
// gets the shooting cone deviation // gets the shooting cone deviation
float getShootingCone (edict_t *ent, const Vector &position) { float getShootingCone (edict_t *ent, const Vector &pos) {
return ent->v.v_angle.forward () | (position - (ent->v.origin + ent->v.view_ofs)).normalize (); // he's facing it, he meant it return ent->v.v_angle.forward () | (pos - (ent->v.origin + ent->v.view_ofs)).normalize (); // he's facing it, he meant it
} }
// check if origin is inside view cone of entity // check if position is inside view cone of entity
bool isInViewCone (const Vector &origin, edict_t *ent) { bool isInViewCone (const Vector &pos, edict_t *ent) {
return getShootingCone (ent, origin) >= cr::cosf (cr::deg2rad ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f)); return getShootingCone (ent, pos) >= cr::cosf (cr::deg2rad ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f));
} }
public: public:

View file

@ -366,6 +366,7 @@ private:
Vector m_lookAtPredict {}; // aiming vector when predicting Vector m_lookAtPredict {}; // aiming vector when predicting
Vector m_desiredVelocity {}; // desired velocity for jump nodes Vector m_desiredVelocity {}; // desired velocity for jump nodes
Vector m_breakableOrigin {}; // origin of breakable Vector m_breakableOrigin {}; // origin of breakable
Vector m_rightRef {}; // right referential vector
Array <edict_t *> m_ignoredBreakable {}; // list of ignored breakables Array <edict_t *> m_ignoredBreakable {}; // list of ignored breakables
Array <edict_t *> m_hostages {}; // pointer to used hostage entities Array <edict_t *> m_hostages {}; // pointer to used hostage entities
@ -485,7 +486,7 @@ private:
void findShortestPath (int srcIndex, int destIndex); void findShortestPath (int srcIndex, int destIndex);
void findPath (int srcIndex, int destIndex, FindPath pathType = FindPath::Fast); void findPath (int srcIndex, int destIndex, FindPath pathType = FindPath::Fast);
void syncFindPath (int srcIndex, int destIndex, FindPath pathType); void syncFindPath (int srcIndex, int destIndex, FindPath pathType);
void debugMsgInternal (const char *str); void debugMsgInternal (StringRef str);
void frame (); void frame ();
void resetCollision (); void resetCollision ();
void ignoreCollision (); void ignoreCollision ();
@ -509,6 +510,7 @@ private:
void syncUpdatePredictedIndex (); void syncUpdatePredictedIndex ();
void updatePredictedIndex (); void updatePredictedIndex ();
void refreshModelName (char *infobuffer); void refreshModelName (char *infobuffer);
void updateRightRef ();
void completeTask (); void completeTask ();
void executeTasks (); void executeTasks ();
@ -540,9 +542,9 @@ private:
void pickupItem_ (); void pickupItem_ ();
void shootBreakable_ (); void shootBreakable_ ();
edict_t *lookupButton (const char *target); edict_t *lookupButton (StringRef target);
edict_t *lookupBreakable (); edict_t *lookupBreakable ();
edict_t *setCorrectGrenadeVelocity (const char *model); edict_t *setCorrectGrenadeVelocity (StringRef model);
Vector getEnemyBodyOffset (); Vector getEnemyBodyOffset ();
Vector calcThrow (const Vector &start, const Vector &stop); Vector calcThrow (const Vector &start, const Vector &stop);

View file

@ -51,7 +51,7 @@ void Bot::pushMsgQueue (int message) {
if (message == BotMsg::Say) { if (message == BotMsg::Say) {
// notify other bots of the spoken text otherwise, bots won't respond to other bots (network messages aren't sent from bots) // notify other bots of the spoken text otherwise, bots won't respond to other bots (network messages aren't sent from bots)
int entityIndex = index (); const int entityIndex = index ();
for (const auto &other : bots) { for (const auto &other : bots) {
if (other->pev != pev) { if (other->pev != pev) {
@ -96,7 +96,7 @@ void Bot::avoidGrenades () {
} }
auto model = pent->v.model.str (9); auto model = pent->v.model.str (9);
if (m_preventFlashing < game.time () && m_personality == Personality::Rusher && m_difficulty == Difficulty::Expert && model == "flashbang.mdl") { if (m_preventFlashing < game.time () && m_personality == Personality::Rusher && m_difficulty == Difficulty::Expert && model == kFlashbangModelName) {
// don't look at flash bang // don't look at flash bang
if (!(m_states & Sense::SeeingEnemy)) { if (!(m_states & Sense::SeeingEnemy)) {
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);
@ -105,7 +105,7 @@ void Bot::avoidGrenades () {
m_preventFlashing = game.time () + rg.get (1.0f, 2.0f); m_preventFlashing = game.time () + rg.get (1.0f, 2.0f);
} }
} }
else if (game.isNullEntity (m_avoidGrenade) && model == "hegrenade.mdl") { else if (game.isNullEntity (m_avoidGrenade) && model == kExplosiveModelName) {
if (game.getTeam (pent->v.owner) == m_team || pent->v.owner == ent ()) { if (game.getTeam (pent->v.owner) == m_team || pent->v.owner == ent ()) {
continue; continue;
} }
@ -128,7 +128,7 @@ void Bot::avoidGrenades () {
} }
} }
} }
else if ((pent->v.flags & FL_ONGROUND) && model == "smokegrenade.mdl") { else if ((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 ();
@ -403,8 +403,8 @@ void Bot::updatePickups () {
pickupType = Pickup::Weapon; pickupType = Pickup::Weapon;
if (cv_pickup_ammo_and_kits.bool_ ()) { if (cv_pickup_ammo_and_kits.bool_ ()) {
int primaryWeaponCarried = bestPrimaryCarried (); const int primaryWeaponCarried = bestPrimaryCarried ();
int secondaryWeaponCarried = bestSecondaryCarried (); const int secondaryWeaponCarried = bestSecondaryCarried ();
const auto &config = conf.getWeapons (); const auto &config = conf.getWeapons ();
const auto &primary = config[primaryWeaponCarried]; const auto &primary = config[primaryWeaponCarried];
@ -493,13 +493,13 @@ void Bot::updatePickups () {
else if (!rateGroundWeapon (ent)) { else if (!rateGroundWeapon (ent)) {
allowPickup = false; allowPickup = false;
} }
else if ((pev->weapons & cr::bit (Weapon::Flashbang)) && model == "flashbang.mdl") { else if ((pev->weapons & cr::bit (Weapon::Flashbang)) && model == kFlashbangModelName) {
allowPickup = false; allowPickup = false;
} }
else if ((pev->weapons & cr::bit (Weapon::Explosive)) && model == "hegrenade.mdl") { else if ((pev->weapons & cr::bit (Weapon::Explosive)) && model == kExplosiveModelName) {
allowPickup = false; allowPickup = false;
} }
else if ((pev->weapons & cr::bit (Weapon::Smoke)) && model == "smokegrenade.mdl") { else if ((pev->weapons & cr::bit (Weapon::Smoke)) && model == kSmokeModelName) {
allowPickup = false; allowPickup = false;
} }
} }
@ -637,7 +637,6 @@ void Bot::updatePickups () {
} }
if (pev->origin.distanceSq (origin) > cr::sqrf (60.0f)) { if (pev->origin.distanceSq (origin) > cr::sqrf (60.0f)) {
if (!graph.isNodeReacheable (pev->origin, origin)) { if (!graph.isNodeReacheable (pev->origin, origin)) {
allowPickup = false; allowPickup = false;
} }
@ -840,7 +839,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 (), PATH_SEP, item.name)); msg.writeString (strings.format ("%s%s%s.wav", cv_chatter_path.str (), kPathSeparator, item.name));
}; };
for (auto &client : util.getClients ()) { for (auto &client : util.getClients ()) {
@ -3483,7 +3482,7 @@ void Bot::resetDoubleJump () {
m_jumpReady = false; m_jumpReady = false;
} }
void Bot::debugMsgInternal (const char *str) { void Bot::debugMsgInternal (StringRef str) {
if (game.isDedicated ()) { if (game.isDedicated ()) {
return; return;
} }

View file

@ -54,7 +54,7 @@ void BotSupport::addChatErrors (String &line) {
if (rg.chance (8) && cv_language.str () == "en") { if (rg.chance (8) && cv_language.str () == "en") {
line.lowercase (); line.lowercase ();
} }
auto length = static_cast <int32_t> (line.length ()); const auto length = static_cast <int32_t> (line.length ());
if (length > 15) { if (length > 15) {
const auto percentile = length / 2; const auto percentile = length / 2;
@ -106,6 +106,7 @@ bool BotSupport::checkKeywords (StringRef line, String &reply) {
if (!replyUsed) { if (!replyUsed) {
reply.assign (choosenReply); // update final buffer reply.assign (choosenReply); // update final buffer
usedReplies.push (choosenReply); // add to ignore list usedReplies.push (choosenReply); // add to ignore list
return true; return true;
} }
} }
@ -168,7 +169,7 @@ void Bot::prepareChatMessage (StringRef message) {
if (!(client.flags & ClientFlags::Used) || client.ent == ent ()) { if (!(client.flags & ClientFlags::Used) || client.ent == ent ()) {
continue; continue;
} }
int frags = static_cast <int> (client.ent->v.frags); const auto frags = static_cast <int> (client.ent->v.frags);
if (frags > highestFrags) { if (frags > highestFrags) {
highestFrags = frags; highestFrags = frags;

View file

@ -52,7 +52,7 @@ bool Bot::isEnemyHidden (edict_t *enemy) {
if (!cv_check_enemy_rendering.bool_ () || game.isNullEntity (enemy)) { if (!cv_check_enemy_rendering.bool_ () || game.isNullEntity (enemy)) {
return false; return false;
} }
entvars_t &v = enemy->v; const auto &v = enemy->v;
const bool enemyHasGun = (v.weapons & kPrimaryWeaponMask) || (v.weapons & kSecondaryWeaponMask); const bool enemyHasGun = (v.weapons & kPrimaryWeaponMask) || (v.weapons & kSecondaryWeaponMask);
const bool enemyGunfire = (v.button & IN_ATTACK) || (v.oldbuttons & IN_ATTACK); const bool enemyGunfire = (v.button & IN_ATTACK) || (v.oldbuttons & IN_ATTACK);
@ -94,7 +94,7 @@ bool Bot::isEnemyInvincible (edict_t *enemy) {
if (!cv_check_enemy_invincibility.bool_ () || game.isNullEntity (enemy)) { if (!cv_check_enemy_invincibility.bool_ () || game.isNullEntity (enemy)) {
return false; return false;
} }
const entvars_t &v = enemy->v; const auto &v = enemy->v;
if (v.solid < SOLID_BBOX) { if (v.solid < SOLID_BBOX) {
return true; return true;
@ -162,14 +162,15 @@ bool Bot::checkBodyParts (edict_t *target) {
return true; return true;
} }
constexpr auto standFeet = 34.0f; constexpr auto kStandFeet = 34.0f;
constexpr auto crouchFeet = 14.0f; constexpr auto kCrouchFeet = 14.0f;
constexpr auto kEdgeOffset = 13.0f;
if (target->v.flags & FL_DUCKING) { if (target->v.flags & FL_DUCKING) {
spot.z = target->v.origin.z - crouchFeet; spot.z = target->v.origin.z - kCrouchFeet;
} }
else { else {
spot.z = target->v.origin.z - standFeet; spot.z = target->v.origin.z - kStandFeet;
} }
game.testLine (eyes, spot, ignoreFlags, self, &result); game.testLine (eyes, spot, ignoreFlags, self, &result);
@ -179,12 +180,10 @@ bool Bot::checkBodyParts (edict_t *target) {
return true; return true;
} }
const float edgeOffset = 13.0f;
Vector dir = (target->v.origin - pev->origin).normalize2d (); Vector dir = (target->v.origin - pev->origin).normalize2d ();
Vector perp (-dir.y, dir.x, 0.0f); Vector perp (-dir.y, dir.x, 0.0f);
spot = target->v.origin + Vector (perp.x * edgeOffset, perp.y * edgeOffset, 0); spot = target->v.origin + Vector (perp.x * kEdgeOffset, perp.y * kEdgeOffset, 0);
game.testLine (eyes, spot, ignoreFlags, self, &result); game.testLine (eyes, spot, ignoreFlags, self, &result);
@ -194,7 +193,7 @@ bool Bot::checkBodyParts (edict_t *target) {
return true; return true;
} }
spot = target->v.origin - Vector (perp.x * edgeOffset, perp.y * edgeOffset, 0); spot = target->v.origin - Vector (perp.x * kEdgeOffset, perp.y * kEdgeOffset, 0);
game.testLine (eyes, spot, ignoreFlags, self, &result); game.testLine (eyes, spot, ignoreFlags, self, &result);
@ -554,7 +553,7 @@ Vector Bot::getCustomHeight (float distance) {
constexpr float offsetRanges[9][3] = { constexpr float offsetRanges[9][3] = {
{ 0.0f, 0.0f, 0.0f }, // none { 0.0f, 0.0f, 0.0f }, // none
{ 0.0f, 0.0f, 0.0f }, // melee { 0.0f, 0.0f, 0.0f }, // melee
{ 0.5f, -3.0f, -4.5f }, // pistol { 0.5f, -0.1f, -1.5f }, // pistol
{ 6.5f, 6.0f, -2.0f }, // shotgun { 6.5f, 6.0f, -2.0f }, // shotgun
{ 0.5f -7.5f, -9.5f }, // zoomrifle { 0.5f -7.5f, -9.5f }, // zoomrifle
{ 0.5f, -7.5f, -9.5f }, // rifle { 0.5f, -7.5f, -9.5f }, // rifle
@ -771,6 +770,9 @@ bool Bot::needToPauseFiring (float distance) {
else if (distance < kDoubleSprayDistance) { else if (distance < kDoubleSprayDistance) {
offset = 2.75f; offset = 2.75f;
} }
else if ((m_states & Sense::SuspectEnemy) && distance < kDoubleSprayDistance) {
return false;
}
const float xPunch = cr::sqrf (cr::deg2rad (pev->punchangle.x)); const float xPunch = cr::sqrf (cr::deg2rad (pev->punchangle.x));
const float yPunch = cr::sqrf (cr::deg2rad (pev->punchangle.y)); const float yPunch = cr::sqrf (cr::deg2rad (pev->punchangle.y));
@ -931,12 +933,12 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
pev->button |= IN_ATTACK; pev->button |= IN_ATTACK;
} }
constexpr float minDelay[] = { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.6f }; constexpr float kMinFireDelay[] = { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.6f };
constexpr float maxDelay[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.7f }; constexpr float kMaxFireDelay[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.7f };
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 (minDelay[offset], maxDelay[offset]); m_shootTime = game.time () + 0.1f + rg.get (kMinFireDelay[offset], kMaxFireDelay[offset]);
m_zoomCheckTime = game.time (); m_zoomCheckTime = game.time ();
} }
} }
@ -944,8 +946,8 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
void Bot::fireWeapons () { void Bot::fireWeapons () {
// this function will return true if weapon was fired, false otherwise // this function will return true if weapon was fired, false otherwise
//
// do not handle this if with grenade, as it's done it throw grendate task // do not handle this if with grenade, as it's done it throw grenade task
if (m_isUsingGrenade) { if (m_isUsingGrenade) {
return; return;
} }
@ -963,7 +965,7 @@ void Bot::fireWeapons () {
const auto tab = conf.getRawWeapons (); const auto tab = conf.getRawWeapons ();
const auto weapons = pev->weapons; const auto weapons = pev->weapons;
// if jason mode use knife only // if knife mode use knife only
if (isKnifeMode ()) { if (isKnifeMode ()) {
selectWeapons (distance, selectIndex, selectId, choosenWeapon); selectWeapons (distance, selectIndex, selectId, choosenWeapon);
return; return;
@ -1707,10 +1709,10 @@ void Bot::checkReload () {
float Bot::calculateScaleFactor (edict_t *ent) { float Bot::calculateScaleFactor (edict_t *ent) {
Vector entSize = ent->v.maxs - ent->v.mins; Vector entSize = ent->v.maxs - ent->v.mins;
float entArea = 2.0f * (entSize.x * entSize.y + entSize.y * entSize.z + entSize.x * entSize.z); const float entArea = 2.0f * (entSize.x * entSize.y + entSize.y * entSize.z + entSize.x * entSize.z);
Vector botSize = pev->maxs - pev->mins; Vector botSize = pev->maxs - pev->mins;
float botArea = 2.0f * (botSize.x * botSize.y + botSize.y * botSize.z + botSize.x * botSize.z); const float botArea = 2.0f * (botSize.x * botSize.y + botSize.y * botSize.z + botSize.x * botSize.z);
return entArea / botArea; return entArea / botArea;
} }
@ -1809,7 +1811,7 @@ Vector Bot::calcThrow (const Vector &start, const Vector &stop) {
return velocity * 0.7793f; return velocity * 0.7793f;
} }
edict_t *Bot::setCorrectGrenadeVelocity (const char *model) { edict_t *Bot::setCorrectGrenadeVelocity (StringRef model) {
edict_t *result = nullptr; edict_t *result = nullptr;
game.searchEntities ("classname", "grenade", [&] (edict_t *ent) { game.searchEntities ("classname", "grenade", [&] (edict_t *ent) {
@ -1856,11 +1858,11 @@ void Bot::checkGrenadesThrow () {
} }
// check if we have grenades to throw // check if we have grenades to throw
int grenadeToThrow = bestGrenadeCarried (); const auto grenadeToThrow = bestGrenadeCarried ();
// if we don't have grenades no need to check it this round again // if we don't have grenades no need to check it this round again
if (grenadeToThrow == -1) { if (grenadeToThrow == -1) {
m_grenadeCheckTime = game.time () + 15.0f; // changed since, conzero can drop grens from dead players m_grenadeCheckTime = game.time () + 15.0f; // changed since, czero can drop grenades from dead players
clearThrowStates (m_states); clearThrowStates (m_states);
return; return;
@ -2051,18 +2053,18 @@ bool Bot::isEnemyNoticeable (float range) {
if (m_enemyParts & Visibility::Other) { if (m_enemyParts & Visibility::Other) {
coverRatio += rg.get (10.0f, 25.0f); coverRatio += rg.get (10.0f, 25.0f);
} }
constexpr float closeRange = 300.0f; constexpr float kCloseRange = 300.0f;
constexpr float farRange = 1000.0f; constexpr float kFarRange = 1000.0f;
float rangeModifier; float rangeModifier;
if (range < closeRange) { if (range < kCloseRange) {
rangeModifier = 0.0f; rangeModifier = 0.0f;
} }
else if (range > farRange) { else if (range > kFarRange) {
rangeModifier = 1.0f; rangeModifier = 1.0f;
} }
else { else {
rangeModifier = (range - closeRange) / (farRange - closeRange); rangeModifier = (range - kCloseRange) / (kFarRange - kCloseRange);
} }
// harder to notice when crouched // harder to notice when crouched
@ -2072,13 +2074,13 @@ bool Bot::isEnemyNoticeable (float range) {
float playerSpeedSq = m_enemy->v.velocity.lengthSq (); float playerSpeedSq = m_enemy->v.velocity.lengthSq ();
float farChance, closeChance; float farChance, closeChance;
constexpr float runSpeed = cr::sqrf (200.0f); constexpr float kRunSpeed = cr::sqrf (200.0f);
constexpr float walkSpeed = cr::sqrf (30.0f); constexpr float kWalkSpeed = cr::sqrf (30.0f);
if (playerSpeedSq > runSpeed) { if (playerSpeedSq > kRunSpeed) {
return true; // running players are always easy to spot (must be standing to run) return true; // running players are always easy to spot (must be standing to run)
} }
else if (playerSpeedSq > walkSpeed) { else if (playerSpeedSq > kWalkSpeed) {
// walking players are less noticeable far away // walking players are less noticeable far away
if (isCrouching) { if (isCrouching) {
closeChance = 90.0f; closeChance = 90.0f;

View file

@ -124,6 +124,8 @@ void BotConfig::loadNamesConfig () {
String line; String line;
MemFile file; MemFile file;
constexpr auto kMaxNameLen = 32;
// naming initialization // naming initialization
if (openConfig ("names", "Name configuration file not found.", &file, true)) { if (openConfig ("names", "Name configuration file not found.", &file, true)) {
m_botNames.clear (); m_botNames.clear ();
@ -135,8 +137,8 @@ void BotConfig::loadNamesConfig () {
continue; continue;
} }
// max botname is 32 characters // max botname is 32 characters
if (line.length () > 32) { if (line.length () > kMaxNameLen - 1) {
line[32] = kNullChar; line[kMaxNameLen - 1] = kNullChar;
} }
m_botNames.emplace (line, -1); m_botNames.emplace (line, -1);
} }
@ -583,7 +585,7 @@ void BotConfig::loadDifficultyConfig () {
diff->aimError.z = values[8].float_ (); diff->aimError.z = values[8].float_ ();
}; };
// avatars initialization // difficulty initialization
if (openConfig ("difficulty", "Difficulty config file not found. Loading defaults.", &file)) { if (openConfig ("difficulty", "Difficulty config file not found. Loading defaults.", &file)) {
while (file.getLine (line)) { while (file.getLine (line)) {
@ -706,20 +708,20 @@ BotName *BotConfig::pickBotName () {
} }
for (size_t i = 0; i < m_botNames.length () * 2; ++i) { for (size_t i = 0; i < m_botNames.length () * 2; ++i) {
auto botName = &m_botNames.random (); auto bn = &m_botNames.random ();
if (botName->name.length () < 3 || botName->usedBy != -1) { if (bn->name.length () < 3 || bn->usedBy != -1) {
continue; continue;
} }
return botName; return bn;
} }
return nullptr; return nullptr;
} }
void BotConfig::clearUsedName (Bot *bot) { void BotConfig::clearUsedName (Bot *bot) {
for (auto &name : m_botNames) { for (auto &bn : m_botNames) {
if (name.usedBy == bot->index ()) { if (bn.usedBy == bot->index ()) {
name.usedBy = -1; bn.usedBy = -1;
break; break;
} }
} }

View file

@ -278,7 +278,7 @@ int BotControl::cmdCvars () {
if (isSave) { if (isSave) {
if (!cfg) { if (!cfg) {
msg ("Unable to write cvars to config file. File not accesssible"); msg ("Unable to write cvars to config file. File not accessible");
return BotCommandResult::Handled; return BotCommandResult::Handled;
} }
msg ("Bots cvars has been written to file."); msg ("Bots cvars has been written to file.");
@ -368,6 +368,7 @@ int BotControl::cmdNode () {
addGraphCmd ("path_create_jump", "path_create_jump [noarguments]", "Creates jumping path connection from nearest to faced node.", &BotControl::cmdNodePathCreate); addGraphCmd ("path_create_jump", "path_create_jump [noarguments]", "Creates jumping path connection from nearest to faced node.", &BotControl::cmdNodePathCreate);
addGraphCmd ("path_delete", "path_delete [noarguments]", "Deletes path from nearest to faced node.", &BotControl::cmdNodePathDelete); addGraphCmd ("path_delete", "path_delete [noarguments]", "Deletes path from nearest to faced node.", &BotControl::cmdNodePathDelete);
addGraphCmd ("path_set_autopath", "path_set_autopath [max_distance]", "Opens menu for setting autopath maximum distance.", &BotControl::cmdNodePathSetAutoDistance); addGraphCmd ("path_set_autopath", "path_set_autopath [max_distance]", "Opens menu for setting autopath maximum distance.", &BotControl::cmdNodePathSetAutoDistance);
addGraphCmd ("path_clean", "path_clean [index]", "Clean's up all types of connections from the node.", &BotControl::cmdNodePathCleanAll);
// camp points iterator // camp points iterator
addGraphCmd ("iterate_camp", "iterate_camp [begin|end|next]", "Allows to go through all camp points on map.", &BotControl::cmdNodeIterateCamp); addGraphCmd ("iterate_camp", "iterate_camp [begin|end|next]", "Allows to go through all camp points on map.", &BotControl::cmdNodeIterateCamp);
@ -756,6 +757,19 @@ int BotControl::cmdNodePathSetAutoDistance () {
return BotCommandResult::Handled; return BotCommandResult::Handled;
} }
int BotControl::cmdNodePathCleanAll () {
enum args { graph_cmd = 1, cmd, index };
auto requestedNode = kInvalidNodeIndex;
if (hasArg (index)) {
requestedNode = intValue (index);
}
graph.resetPath (requestedNode);
return BotCommandResult::Handled;
}
int BotControl::cmdNodeAcquireEditor () { int BotControl::cmdNodeAcquireEditor () {
enum args { graph_cmd = 1 }; enum args { graph_cmd = 1 };

View file

@ -803,7 +803,7 @@ bool Game::loadCSBinary () {
// search the libraries inside game dlls directory // search the libraries inside game dlls directory
for (const auto &lib : libs) { for (const auto &lib : libs) {
auto path = strings.joinPath (modname, "dlls", lib) + DLL_SUFFIX; auto path = strings.joinPath (modname, "dlls", lib) + kLibrarySuffix;
// if we can't read file, skip it // if we can't read file, skip it
if (!plat.fileExists (path.chars ())) { if (!plat.fileExists (path.chars ())) {
@ -1136,7 +1136,7 @@ void LightMeasure::initializeLightstyles () {
// reset all light styles // reset all light styles
for (auto &ls : m_lightstyle) { for (auto &ls : m_lightstyle) {
ls.length = 0; ls.length = 0;
ls.map[0] = 0; ls.map[0] = kNullChar;
} }
for (auto &lsv : m_lightstyleValue) { for (auto &lsv : m_lightstyleValue) {
@ -1226,7 +1226,7 @@ template <typename S, typename M> bool LightMeasure::recursiveLightPoint (const
if (surf->flags & SURF_DRAWTILED) { if (surf->flags & SURF_DRAWTILED) {
continue; // no lightmaps continue; // no lightmaps
} }
auto tex = surf->texinfo; const auto tex = surf->texinfo;
// see where in lightmap space our intersection point is // see where in lightmap space our intersection point is
const int s = static_cast <int> ((mid | Vector (tex->vecs[0])) + tex->vecs[0][3]); const int s = static_cast <int> ((mid | Vector (tex->vecs[0])) + tex->vecs[0][3]);

View file

@ -1135,6 +1135,45 @@ void BotGraph::erasePath () {
msg ("There is already no path on this node."); msg ("There is already no path on this node.");
} }
void BotGraph::resetPath (int index) {
int node = index;
if (!exists (node)) {
node = getEditorNearest ();
if (!exists (node)) {
msg ("Unable to find nearest node in 50 units.");
return;
}
}
// helper
auto destroy = [] (PathLink &link) -> void {
link.index = kInvalidNodeIndex;
link.distance = 0;
link.flags = 0;
link.velocity = nullptr;
};
// clean all incoming
for (auto &connected : m_paths) {
for (auto &link : connected.links) {
if (link.index == node) {
destroy (link);
}
}
}
// clean all outgoing connections
for (auto &link : m_paths[node].links) {
destroy (link);
}
emitNotify (NotifySound::Change);
// notify use something evil happened
msg ("All paths for node #%d has been reset.", node);
}
void BotGraph::cachePoint (int index) { void BotGraph::cachePoint (int index) {
const int node = exists (index) ? index : getEditorNearest (); const int node = exists (index) ? index : getEditorNearest ();
@ -1579,7 +1618,7 @@ bool BotGraph::loadGraphData () {
reset (); reset ();
// check if loaded // check if loaded
bool dataLoaded = bstor.load <Path> (m_paths, &exten, &outOptions); const bool dataLoaded = bstor.load <Path> (m_paths, &exten, &outOptions);
if (dataLoaded) { if (dataLoaded) {
initBuckets (); initBuckets ();
@ -1898,7 +1937,7 @@ void BotGraph::frame () {
for (auto &path : m_paths) { for (auto &path : m_paths) {
const float distanceSq = path.origin.distanceSq (m_editor->v.origin); const float distanceSq = path.origin.distanceSq (m_editor->v.origin);
// check if node is whitin a distance, and is visible // check if node is within a distance, and is visible
if (distanceSq < cr::sqrf (cv_graph_draw_distance.float_ ()) && ((util.isVisible (path.origin, m_editor) && util.isInViewCone (path.origin, m_editor)) || !util.isAlive (m_editor) || distanceSq < cr::sqrf (64.0f))) { if (distanceSq < cr::sqrf (cv_graph_draw_distance.float_ ()) && ((util.isVisible (path.origin, m_editor) && util.isInViewCone (path.origin, m_editor)) || !util.isAlive (m_editor) || distanceSq < cr::sqrf (64.0f))) {
// check the distance // check the distance
if (distanceSq < nearestDistanceSq) { if (distanceSq < nearestDistanceSq) {
@ -2128,7 +2167,7 @@ void BotGraph::frame () {
}; };
// very helpful stuff.. // very helpful stuff..
auto getNodeData = [&] (StringRef type, int node) -> String { auto getNodeData = [this] (StringRef type, int node) -> String {
String message, flags; String message, flags;
const auto &p = m_paths[node]; const auto &p = m_paths[node];

View file

@ -992,7 +992,7 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
// this function does core operation of creating bot, it's called by addbot (), // this function does core operation of creating bot, it's called by addbot (),
// when bot setup completed, (this is a bot class constructor) // when bot setup completed, (this is a bot class constructor)
int clientIndex = game.indexOfEntity (bot); const int clientIndex = game.indexOfEntity (bot);
pev = &bot->v; pev = &bot->v;
if (bot->pvPrivateData != nullptr) { if (bot->pvPrivateData != nullptr) {
@ -1176,25 +1176,25 @@ int BotManager::getAliveHumansCount () {
} }
int BotManager::getPlayerPriority (edict_t *ent) { int BotManager::getPlayerPriority (edict_t *ent) {
constexpr auto highPrio = 512; constexpr auto kHighPriority = 512;
// always check for only our own bots // always check for only our own bots
auto bot = bots[ent]; auto bot = bots[ent];
// if player just return high prio // if player just return high prio
if (!bot) { if (!bot) {
return game.indexOfEntity (ent) + highPrio; return game.indexOfEntity (ent) + kHighPriority;
} }
// give bots some priority // give bots some priority
if (bot->m_hasC4 || bot->m_isVIP || bot->m_hasHostage || bot->m_healthValue < ent->v.health) { if (bot->m_hasC4 || bot->m_isVIP || bot->m_hasHostage || bot->m_healthValue < ent->v.health) {
return bot->entindex () + highPrio; return bot->entindex () + kHighPriority;
} }
auto task = bot->getCurrentTaskId (); auto task = bot->getCurrentTaskId ();
// higher priority if camping or hiding // higher priority if camping or hiding
if (task == Task::Camp || task == Task::Hide) { if (task == Task::Camp || task == Task::Hide) {
return bot->entindex () + highPrio; return bot->entindex () + kHighPriority;
} }
return bot->entindex (); return bot->entindex ();
} }
@ -1229,7 +1229,7 @@ void BotManager::erase (Bot *bot) {
} }
bot->markStale (); bot->markStale ();
auto index = m_bots.index (e); const auto index = m_bots.index (e);
e.reset (); e.reset ();
m_bots.erase (index, 1); // remove from bots array m_bots.erase (index, 1); // remove from bots array
@ -1291,6 +1291,7 @@ void BotManager::handleDeath (edict_t *killer, edict_t *victim) {
if (victimBot != nullptr) { if (victimBot != nullptr) {
if (killerTeam == victimBot->m_team) { if (killerTeam == victimBot->m_team) {
victimBot->m_voteKickIndex = game.indexOfEntity (killer); victimBot->m_voteKickIndex = game.indexOfEntity (killer);
for (const auto &notify : bots) { for (const auto &notify : bots) {
if (notify->seesEntity (victim->v.origin)) { if (notify->seesEntity (victim->v.origin)) {
notify->pushChatterMessage (Chatter::TeamKill); notify->pushChatterMessage (Chatter::TeamKill);
@ -1502,6 +1503,9 @@ void Bot::newRound () {
m_goalHist.clear (); m_goalHist.clear ();
m_ignoredBreakable.clear (); m_ignoredBreakable.clear ();
// update refvec for blocked movement
updateRightRef ();
// and put buying into its message queue // and put buying into its message queue
pushMsgQueue (BotMsg::Buy); pushMsgQueue (BotMsg::Buy);
startTask (Task::Normal, TaskPri::Normal, kInvalidNodeIndex, 0.0f, true); startTask (Task::Normal, TaskPri::Normal, kInvalidNodeIndex, 0.0f, true);
@ -1618,7 +1622,7 @@ void Bot::updateTeamJoin () {
m_startAction = BotMsg::TeamSelect; m_startAction = BotMsg::TeamSelect;
} }
// if bot was unable to join team, and no menus popups, check for stacked team // if bot was unable to join team, and no menus pop-ups, check for stacked team
if (m_startAction == BotMsg::None) { if (m_startAction == BotMsg::None) {
if (++m_retryJoin > 3 && bots.isTeamStacked (m_wantedTeam - 1)) { if (++m_retryJoin > 3 && bots.isTeamStacked (m_wantedTeam - 1)) {
m_retryJoin = 0; m_retryJoin = 0;
@ -1710,7 +1714,7 @@ void BotManager::captureChatRadio (StringRef cmd, StringRef arg, edict_t *ent) {
} }
if (cmd.startsWith ("say")) { if (cmd.startsWith ("say")) {
const bool alive = util.isAlive (ent); const bool alive = util.isAlive (ent);
int team = -1; int team = -1;
if (cmd == "say_team") { if (cmd == "say_team") {
@ -1768,7 +1772,7 @@ void BotManager::notifyBombDefuse () {
const auto &bombPos = graph.getBombOrigin (); const auto &bombPos = graph.getBombOrigin ();
for (const auto &bot : bots) { for (const auto &bot : bots) {
auto task = bot->getCurrentTaskId (); const auto task = bot->getCurrentTaskId ();
if (!bot->m_defuseNotified && bot->m_notKilled && task != Task::MoveToPosition && task != Task::DefuseBomb && task != Task::EscapeFromBomb) { if (!bot->m_defuseNotified && bot->m_notKilled && task != Task::MoveToPosition && task != Task::DefuseBomb && 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 (384.0f)) {

View file

@ -87,7 +87,7 @@ void MessageDispatcher::netMsgVGUIMenu () {
enum args { menu = 0, min = 1 }; enum args { menu = 0, min = 1 };
// check the minimum states or existance of bot // check the minimum states or existence of bot
if (m_args.length () < min || !m_bot) { if (m_args.length () < min || !m_bot) {
return; return;
} }
@ -109,7 +109,7 @@ void MessageDispatcher::netMsgShowMenu () {
enum args { menu = 3, min = 4 }; enum args { menu = 3, min = 4 };
// check the minimum states or existance of bot // check the minimum states or existence of bot
if (m_args.length () < min || !m_bot) { if (m_args.length () < min || !m_bot) {
return; return;
} }
@ -144,7 +144,7 @@ void MessageDispatcher::netMsgWeaponList () {
} }
void MessageDispatcher::netMsgCurWeapon () { void MessageDispatcher::netMsgCurWeapon () {
// this message is sent when a weapon is selected (either by the bot chosing a weapon or by the server auto assigning the bot a weapon). In CS it's also called when Ammo is increased/decreased // this message is sent when a weapon is selected (either by the bot choosing a weapon or by the server auto assigning the bot a weapon). In CS it's also called when Ammo is increased/decreased
enum args { state = 0, id = 1, clip = 2, min = 3 }; enum args { state = 0, id = 1, clip = 2, min = 3 };
@ -524,7 +524,7 @@ void MessageDispatcher::start (edict_t *ent, int32_t type) {
m_current = m_handlers[msg] ? msg : NetMsg::None; m_current = m_handlers[msg] ? msg : NetMsg::None;
} }
// no messagem no processing // no message no processing
if (m_current == NetMsg::None) { if (m_current == NetMsg::None) {
return; return;
} }
@ -571,6 +571,6 @@ int32_t MessageDispatcher::id (NetMsg msg) {
Bot *MessageDispatcher::pickBot (int32_t index) { Bot *MessageDispatcher::pickBot (int32_t index) {
const auto &client = util.getClient (m_args[index].long_ - 1); const auto &client = util.getClient (m_args[index].long_ - 1);
// get the bot in this msg // get the bot in this message
return bots[client.ent]; return bots[client.ent];
} }

View file

@ -661,7 +661,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
} }
if (seesEntity (m_destOrigin)) { if (seesEntity (m_destOrigin)) {
auto right = m_moveAngles.right (); const auto &right = m_moveAngles.right ();
src = getEyesPos (); src = getEyesPos ();
src = src + right * 15.0f; src = src + right * 15.0f;
@ -910,7 +910,7 @@ bool Bot::updateNavigation () {
if (feet.z > pev->origin.z) { if (feet.z > pev->origin.z) {
feet = pev->origin + pev->maxs; feet = pev->origin + pev->maxs;
} }
feet = { pev->origin.x, pev->origin.y, feet.z }; feet = { pev->origin.x, pev->origin.y, feet.z };
// calculate like we do with grenades // calculate like we do with grenades
auto velocity = calcThrow (feet, node); auto velocity = calcThrow (feet, node);
@ -949,9 +949,8 @@ bool Bot::updateNavigation () {
} }
if ((m_pathFlags & NodeFlag::Ladder) || isOnLadder ()) { if ((m_pathFlags & NodeFlag::Ladder) || isOnLadder ()) {
constexpr auto kLadderOffset = Vector (0.0f, 0.0f, 16.0f);
if (m_pathOrigin.z >= (pev->origin.z + 16.0f)) { if (m_pathOrigin.z >= (pev->origin.z + 16.0f)) {
constexpr auto kLadderOffset = Vector (0.0f, 0.0f, 16.0f);
m_pathOrigin = m_path->origin + kLadderOffset; m_pathOrigin = m_path->origin + kLadderOffset;
} }
else if (m_pathOrigin.z < pev->origin.z + 16.0f && !isOnLadder () && isOnFloor () && !(pev->flags & FL_DUCKING)) { else if (m_pathOrigin.z < pev->origin.z + 16.0f && !isOnLadder () && isOnFloor () && !(pev->flags & FL_DUCKING)) {
@ -1059,7 +1058,7 @@ bool Bot::updateNavigation () {
ignoreCollision (); // don't consider being stuck ignoreCollision (); // don't consider being stuck
if (rg.chance (50)) { if (rg.chance (50)) {
// do not use door directrly under xash, or we will get failed assert in gamedll code // do not use door directly under xash, or we will get failed assert in gamedll code
if (game.is (GameFlags::Xash3D)) { if (game.is (GameFlags::Xash3D)) {
pev->button |= IN_USE; pev->button |= IN_USE;
} }
@ -1357,7 +1356,7 @@ bool Bot::updateLiftHandling () {
// bot is trying to find button inside a lift // bot is trying to find button inside a lift
if (m_liftState == LiftState::LookingButtonInside) { if (m_liftState == LiftState::LookingButtonInside) {
auto button = lookupButton (m_liftEntity->v.targetname.chars ()); auto button = lookupButton (m_liftEntity->v.targetname.str ());
// got a valid button entity ? // got a valid button entity ?
if (!game.isNullEntity (button) && pev->groundentity == m_liftEntity && m_buttonPushTime + 1.0f < game.time () && cr::fzero (m_liftEntity->v.velocity.z) && isOnFloor ()) { if (!game.isNullEntity (button) && pev->groundentity == m_liftEntity && m_buttonPushTime + 1.0f < game.time () && cr::fzero (m_liftEntity->v.velocity.z) && isOnFloor ()) {
@ -1406,7 +1405,7 @@ bool Bot::updateLiftHandling () {
} }
} }
else if (!game.isNullEntity (m_liftEntity)) { else if (!game.isNullEntity (m_liftEntity)) {
auto button = lookupButton (m_liftEntity->v.targetname.chars ()); auto button = lookupButton (m_liftEntity->v.targetname.str ());
// if we got a valid button entity // if we got a valid button entity
if (!game.isNullEntity (button)) { if (!game.isNullEntity (button)) {
@ -1702,18 +1701,18 @@ void Bot::findValidNode () {
findNextBestNode (); findNextBestNode ();
} }
else if (m_navTimeset + getEstimatedNodeReachTime () < game.time ()) { else if (m_navTimeset + getEstimatedNodeReachTime () < game.time ()) {
constexpr int maxDamageValue = PracticeLimit::Damage; constexpr int kMaxDamageValue = PracticeLimit::Damage;
// increase danger for both teams // increase danger for both teams
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) { for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
int damageValue = practice.getDamage (team, m_currentNodeIndex, m_currentNodeIndex); int damageValue = practice.getDamage (team, m_currentNodeIndex, m_currentNodeIndex);
damageValue = cr::clamp (damageValue + 100, 0, maxDamageValue); damageValue = cr::clamp (damageValue + 100, 0, kMaxDamageValue);
// affect nearby connected with victim nodes // affect nearby connected with victim nodes
for (auto &neighbour : m_path->links) { for (auto &neighbour : m_path->links) {
if (graph.exists (neighbour.index)) { if (graph.exists (neighbour.index)) {
int neighbourValue = practice.getDamage (team, neighbour.index, neighbour.index); int neighbourValue = practice.getDamage (team, neighbour.index, neighbour.index);
neighbourValue = cr::clamp (neighbourValue + 100, 0, maxDamageValue); neighbourValue = cr::clamp (neighbourValue + 100, 0, kMaxDamageValue);
practice.setDamage (m_team, neighbour.index, neighbour.index, neighbourValue); practice.setDamage (m_team, neighbour.index, neighbour.index, neighbourValue);
} }
@ -2062,8 +2061,8 @@ int Bot::findCoverNode (float maxDistance) {
} }
// use the 'real' pathfinding distances // use the 'real' pathfinding distances
float distance = planner.dist (srcIndex, path.number); const float distance = planner.dist (srcIndex, path.number);
float enemyDistance = planner.dist (enemyIndex, path.number); const float enemyDistance = planner.dist (enemyIndex, path.number);
if (distance >= enemyDistance) { if (distance >= enemyDistance) {
continue; continue;
@ -2408,6 +2407,10 @@ void Bot::setPathOrigin () {
} }
} }
void Bot::updateRightRef () {
m_rightRef = Vector { 0.0f, pev->angles.y, 0.0f }.right (); // convert current view angle to vectors for traceline math...
}
bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) { bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
// checks if bot is blocked in his movement direction (excluding doors) // checks if bot is blocked in his movement direction (excluding doors)
@ -2416,7 +2419,6 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
// first do a trace from the bot's eyes forward... // first do a trace from the bot's eyes forward...
auto src = getEyesPos (); auto src = getEyesPos ();
auto forward = src + normal * 24.0f; auto forward = src + normal * 24.0f;
auto right = Vector (0.0f, pev->angles.y, 0.0f).right ();
auto checkDoor = [] (TraceResult *result) { auto checkDoor = [] (TraceResult *result) {
if (!game.mapIs (MapFlags::HasDoors)) { if (!game.mapIs (MapFlags::HasDoors)) {
@ -2437,10 +2439,13 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
} }
constexpr auto kVec00N16 = Vector (0.0f, 0.0f, -16.0f); constexpr auto kVec00N16 = Vector (0.0f, 0.0f, -16.0f);
// right referential vector
updateRightRef ();
// bot's head is clear, check at shoulder level... // bot's head is clear, check at shoulder level...
// trace from the bot's shoulder left diagonal forward to the right shoulder... // trace from the bot's shoulder left diagonal forward to the right shoulder...
src = getEyesPos () + kVec00N16 - right * -16.0f; src = getEyesPos () + kVec00N16 - m_rightRef * -16.0f;
forward = getEyesPos () + kVec00N16 + right * 16.0f + normal * 24.0f; forward = getEyesPos () + kVec00N16 + m_rightRef * 16.0f + normal * 24.0f;
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr); game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
@ -2451,8 +2456,8 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
// bot's head is clear, check at shoulder level... // bot's head is clear, check at shoulder level...
// trace from the bot's shoulder right diagonal forward to the left shoulder... // trace from the bot's shoulder right diagonal forward to the left shoulder...
src = getEyesPos () + kVec00N16 + right * 16.0f; src = getEyesPos () + kVec00N16 + m_rightRef * 16.0f;
forward = getEyesPos () + kVec00N16 - right * -16.0f + normal * 24.0f; forward = getEyesPos () + kVec00N16 - m_rightRef * -16.0f + normal * 24.0f;
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr); game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
@ -2487,8 +2492,8 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
constexpr auto kVec00N24 = Vector (0.0f, 0.0f, -24.0f); constexpr auto kVec00N24 = Vector (0.0f, 0.0f, -24.0f);
// trace from the left waist to the right forward waist pos // trace from the left waist to the right forward waist pos
src = pev->origin + kVec00N17 - right * -16.0f; src = pev->origin + kVec00N17 - m_rightRef * -16.0f;
forward = pev->origin + kVec00N17 + right * 16.0f + normal * 24.0f; forward = pev->origin + kVec00N17 + m_rightRef * 16.0f + normal * 24.0f;
// trace from the bot's waist straight forward... // trace from the bot's waist straight forward...
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr); game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
@ -2499,8 +2504,8 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
} }
// trace from the left waist to the right forward waist pos // trace from the left waist to the right forward waist pos
src = pev->origin + kVec00N24 + right * 16.0f; src = pev->origin + kVec00N24 + m_rightRef * 16.0f;
forward = pev->origin + kVec00N24 - right * -16.0f + normal * 24.0f; forward = pev->origin + kVec00N24 - m_rightRef * -16.0f + normal * 24.0f;
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr); game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
@ -2580,7 +2585,7 @@ bool Bot::canJumpUp (const Vector &normal) {
if (!isOnFloor () && (isOnLadder () || !isInWater ())) { if (!isOnFloor () && (isOnLadder () || !isInWater ())) {
return false; return false;
} }
auto right = Vector (0.0f, pev->angles.y, 0.0f).right (); // convert current view angle to vectors for traceline math... updateRightRef ();
// check for normal jump height first... // check for normal jump height first...
auto src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 45.0f); auto src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 45.0f);
@ -2590,7 +2595,7 @@ bool Bot::canJumpUp (const Vector &normal) {
game.testLine (src, dest, TraceIgnore::Monsters, ent (), &tr); game.testLine (src, dest, TraceIgnore::Monsters, ent (), &tr);
if (tr.flFraction < 1.0f) { if (tr.flFraction < 1.0f) {
return doneCanJumpUp (normal, right); return doneCanJumpUp (normal, m_rightRef);
} }
else { else {
// now trace from jump height upward to check for obstructions... // now trace from jump height upward to check for obstructions...
@ -2605,7 +2610,7 @@ bool Bot::canJumpUp (const Vector &normal) {
} }
// now check same height to one side of the bot... // now check same height to one side of the bot...
src = pev->origin + right * 16.0f + Vector (0.0f, 0.0f, -36.0f + 45.0f); src = pev->origin + m_rightRef * 16.0f + Vector (0.0f, 0.0f, -36.0f + 45.0f);
dest = src + normal * 32.0f; dest = src + normal * 32.0f;
// trace a line forward at maximum jump height... // trace a line forward at maximum jump height...
@ -2613,7 +2618,7 @@ bool Bot::canJumpUp (const Vector &normal) {
// if trace hit something, return false // if trace hit something, return false
if (tr.flFraction < 1.0f) { if (tr.flFraction < 1.0f) {
return doneCanJumpUp (normal, right); return doneCanJumpUp (normal, m_rightRef);
} }
// now trace from jump height upward to check for obstructions... // now trace from jump height upward to check for obstructions...
@ -2628,7 +2633,7 @@ bool Bot::canJumpUp (const Vector &normal) {
} }
// now check same height on the other side of the bot... // now check same height on the other side of the bot...
src = pev->origin + (-right * 16.0f) + Vector (0.0f, 0.0f, -36.0f + 45.0f); src = pev->origin + (-m_rightRef * 16.0f) + Vector (0.0f, 0.0f, -36.0f + 45.0f);
dest = src + normal * 32.0f; dest = src + normal * 32.0f;
// trace a line forward at maximum jump height... // trace a line forward at maximum jump height...
@ -2636,7 +2641,7 @@ bool Bot::canJumpUp (const Vector &normal) {
// if trace hit something, return false // if trace hit something, return false
if (tr.flFraction < 1.0f) { if (tr.flFraction < 1.0f) {
return doneCanJumpUp (normal, right); return doneCanJumpUp (normal, m_rightRef);
} }
// now trace from jump height upward to check for obstructions... // now trace from jump height upward to check for obstructions...
@ -2744,12 +2749,10 @@ bool Bot::canDuckUnder (const Vector &normal) {
if (tr.flFraction < 1.0f) { if (tr.flFraction < 1.0f) {
return false; return false;
} }
updateRightRef ();
// convert current view angle to vectors for TraceLine math...
auto right = Vector (0.0f, pev->angles.y, 0.0f).right ();
// now check same height to one side of the bot... // now check same height to one side of the bot...
src = baseHeight + right * 16.0f; src = baseHeight + m_rightRef * 16.0f;
dest = src + normal * 32.0f; dest = src + normal * 32.0f;
// trace a line forward at duck height... // trace a line forward at duck height...
@ -2761,7 +2764,7 @@ bool Bot::canDuckUnder (const Vector &normal) {
} }
// now check same height on the other side of the bot... // now check same height on the other side of the bot...
src = baseHeight + (-right * 16.0f); src = baseHeight + (-m_rightRef * 16.0f);
dest = src + normal * 32.0f; dest = src + normal * 32.0f;
// trace a line forward at duck height... // trace a line forward at duck height...
@ -3057,11 +3060,11 @@ bool Bot::isOccupiedNode (int index, bool needZeroVelocity) {
return false; return false;
} }
edict_t *Bot::lookupButton (const char *target) { edict_t *Bot::lookupButton (StringRef target) {
// this function tries to find nearest to current bot button, and returns pointer to // this function tries to find nearest to current bot button, and returns pointer to
// it's entity, also here must be specified the target, that button must open. // it's entity, also here must be specified the target, that button must open.
if (strings.isEmpty (target)) { if (target.empty ()) {
return nullptr; return nullptr;
} }
float nearestDistanceSq = kInfiniteDistance; float nearestDistanceSq = kInfiniteDistance;

View file

@ -373,7 +373,7 @@ bool FloydWarshallAlgo::load () {
if (!m_length) { if (!m_length) {
return false; return false;
} }
bool dataLoaded = bstor.load <Matrix> (m_matrix); const bool dataLoaded = bstor.load <Matrix> (m_matrix);
// do not rebuild if loaded // do not rebuild if loaded
if (dataLoaded) { if (dataLoaded) {
@ -451,7 +451,7 @@ bool DijkstraAlgo::find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, i
for (const auto &link : graph[current].links) { for (const auto &link : graph[current].links) {
if (link.index != kInvalidNodeIndex) { if (link.index != kInvalidNodeIndex) {
auto dlink = m_distance[current] + link.distance; const auto dlink = m_distance[current] + link.distance;
if (dlink < m_distance[link.index]) { if (dlink < m_distance[link.index]) {
m_distance[link.index] = dlink; m_distance[link.index] = dlink;

View file

@ -169,7 +169,7 @@ void BotPractice::load () {
SmallArray <DangerSaveRestore> data; SmallArray <DangerSaveRestore> data;
m_data.clear (); m_data.clear ();
bool dataLoaded = bstor.load <DangerSaveRestore> (data); const bool dataLoaded = bstor.load <DangerSaveRestore> (data);
// copy back to hash table // copy back to hash table
if (dataLoaded) { if (dataLoaded) {

View file

@ -233,7 +233,7 @@ template <typename U> bool BotStorage::save (const SmallArray <U> &data, ExtenHe
SmallArray <uint8_t> compressed (rawLength + sizeof (uint8_t) * ULZ::Excess); SmallArray <uint8_t> compressed (rawLength + sizeof (uint8_t) * ULZ::Excess);
// try to compress // try to compress
auto compressedLength = static_cast <size_t> (ulz.compress (reinterpret_cast <uint8_t *> (data.data ()), static_cast <int32_t> (rawLength), reinterpret_cast <uint8_t *> (compressed.data ()))); const auto compressedLength = static_cast <size_t> (ulz.compress (reinterpret_cast <uint8_t *> (data.data ()), static_cast <int32_t> (rawLength), reinterpret_cast <uint8_t *> (compressed.data ())));
if (compressedLength > 0) { if (compressedLength > 0) {
StorageHeader hdr {}; StorageHeader hdr {};
@ -349,7 +349,7 @@ String BotStorage::buildPath (int32_t file, bool isMemoryLoad) {
} }
// finally use correct path separators for us // finally use correct path separators for us
return String::join (path, PATH_SEP); return String::join (path, kPathSeparator);
} }
int32_t BotStorage::storageToBotFile (int32_t options) { int32_t BotStorage::storageToBotFile (int32_t options) {

View file

@ -231,7 +231,7 @@ bool BotSupport::isDoorEntity (edict_t *ent) {
if (game.isNullEntity (ent)) { if (game.isNullEntity (ent)) {
return false; return false;
} }
return ent->v.classname.str ().startsWith ("func_door");; return ent->v.classname.str ().startsWith ("func_door");
} }
bool BotSupport::isHostageEntity (edict_t *ent) { bool BotSupport::isHostageEntity (edict_t *ent) {

View file

@ -1097,7 +1097,7 @@ void Bot::throwExplosive_ () {
else { else {
m_aimFlags |= AimFlags::Grenade; m_aimFlags |= AimFlags::Grenade;
auto grenade = setCorrectGrenadeVelocity ("hegrenade.mdl"); auto grenade = setCorrectGrenadeVelocity (kExplosiveModelName);
if (game.isNullEntity (grenade)) { if (game.isNullEntity (grenade)) {
if (m_currentWeapon != Weapon::Explosive && !m_grenadeRequested) { if (m_currentWeapon != Weapon::Explosive && !m_grenadeRequested) {
@ -1163,7 +1163,7 @@ void Bot::throwFlashbang_ () {
else { else {
m_aimFlags |= AimFlags::Grenade; m_aimFlags |= AimFlags::Grenade;
auto grenade = setCorrectGrenadeVelocity ("flashbang.mdl"); auto grenade = setCorrectGrenadeVelocity (kFlashbangModelName);
if (game.isNullEntity (grenade)) { if (game.isNullEntity (grenade)) {
if (m_currentWeapon != Weapon::Flashbang && !m_grenadeRequested) { if (m_currentWeapon != Weapon::Flashbang && !m_grenadeRequested) {