Merge branch 'master' into chatter-fixes-and-improvements
This commit is contained in:
commit
d76e0e1ba2
27 changed files with 588 additions and 581 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3596ac42ccc21d93d7fe2a937870d76e944f7f07
|
Subproject commit ea7a91bd042599132e60482f51087d9669dbe1c4
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit b99f0bac831b823a1e5a57ef3bd7c7dcaf8dee22
|
Subproject commit 3e2bd997a6048a0c2d9318e65a63b30a35c67dfa
|
||||||
|
|
@ -193,25 +193,25 @@ public:
|
||||||
m_printQueueFlushTimestamp = 0.0f;
|
m_printQueueFlushTimestamp = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
int intValue (size_t arg) const {
|
template <typename U> constexpr U arg (const size_t index) const {
|
||||||
if (!hasArg (arg)) {
|
if constexpr (cr::is_same <U, float>::value) {
|
||||||
return 0;
|
if (!hasArg (index)) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return m_args[index].as <float> ();
|
||||||
}
|
}
|
||||||
return m_args[arg].int_ ();
|
else if constexpr (cr::is_same <U, int>::value) {
|
||||||
}
|
if (!hasArg (index)) {
|
||||||
|
return 0;
|
||||||
float floatValue (size_t arg) const {
|
}
|
||||||
if (!hasArg (arg)) {
|
return m_args[index].as <int> ();
|
||||||
return 0.0f;
|
|
||||||
}
|
}
|
||||||
return m_args[arg].float_ ();
|
else if constexpr (cr::is_same <U, StringRef>::value) {
|
||||||
}
|
if (!hasArg (index)) {
|
||||||
|
return "";
|
||||||
StringRef strValue (size_t arg) {
|
}
|
||||||
if (!hasArg (arg)) {
|
return m_args[index];
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
return m_args[arg];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasArg (size_t arg) const {
|
bool hasArg (size_t arg) const {
|
||||||
|
|
|
||||||
40
inc/engine.h
40
inc/engine.h
|
|
@ -188,7 +188,7 @@ public:
|
||||||
void prepareBotArgs (edict_t *ent, String str);
|
void prepareBotArgs (edict_t *ent, String str);
|
||||||
|
|
||||||
// adds cvar to registration stack
|
// adds cvar to registration stack
|
||||||
void addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32_t varType, bool missingAction, const char *regval, class ConVar *self);
|
void pushConVar (StringRef name, StringRef value, StringRef info, bool bounded, float min, float max, int32_t varType, bool missingAction, StringRef regval, class ConVar *self);
|
||||||
|
|
||||||
// check the cvar bounds
|
// check the cvar bounds
|
||||||
void checkCvarsBounds ();
|
void checkCvarsBounds ();
|
||||||
|
|
@ -470,18 +470,18 @@ public:
|
||||||
~ConVar () = default;
|
~ConVar () = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConVar (const char *name, const char *initval, int32_t type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
|
ConVar (StringRef name, StringRef initval, int32_t type = Var::NoServer, bool regMissing = false, StringRef regVal = nullptr) : ptr (nullptr) {
|
||||||
setPrefix (name, type);
|
setPrefix (name, type);
|
||||||
Game::instance ().addNewCvar (name_.chars (), initval, "", false, 0.0f, 0.0f, type, regMissing, regVal, this);
|
Game::instance ().pushConVar (name_.chars (), initval, "", false, 0.0f, 0.0f, type, regMissing, regVal, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConVar (const char *name, const char *initval, const char *info, bool bounded = true, float min = 0.0f, float max = 1.0f, int32_t type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
|
ConVar (StringRef name, StringRef initval, StringRef info, bool bounded = true, float min = 0.0f, float max = 1.0f, int32_t type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
|
||||||
setPrefix (name, type);
|
setPrefix (name, type);
|
||||||
Game::instance ().addNewCvar (name_.chars (), initval, info, bounded, min, max, type, regMissing, regVal, this);
|
Game::instance ().pushConVar (name_.chars (), initval, info, bounded, min, max, type, regMissing, regVal, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename U> constexpr U get () const {
|
template <typename U> constexpr U as () const {
|
||||||
if constexpr (cr::is_same <U, float>::value) {
|
if constexpr (cr::is_same <U, float>::value) {
|
||||||
return ptr->value;
|
return ptr->value;
|
||||||
}
|
}
|
||||||
|
|
@ -498,34 +498,22 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
operator bool () const {
|
operator bool () const {
|
||||||
return bool_ ();
|
return as <bool> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
operator float () const {
|
operator float () const {
|
||||||
return float_ ();
|
return as <float> ();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator int () const {
|
||||||
|
return as <int> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
operator StringRef () {
|
operator StringRef () {
|
||||||
return str ();
|
return as <StringRef> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool bool_ () const {
|
|
||||||
return get <bool> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
int int_ () const {
|
|
||||||
return get <int> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
float float_ () const {
|
|
||||||
return get <float> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
StringRef str () const {
|
|
||||||
return get <StringRef> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
StringRef name () const {
|
StringRef name () const {
|
||||||
return ptr->name;
|
return ptr->name;
|
||||||
}
|
}
|
||||||
|
|
@ -546,7 +534,7 @@ public:
|
||||||
void revert ();
|
void revert ();
|
||||||
|
|
||||||
// set the cvar prefix if needed
|
// set the cvar prefix if needed
|
||||||
void setPrefix (const char *name, int32_t type);
|
void setPrefix (StringRef name, int32_t type);
|
||||||
};
|
};
|
||||||
|
|
||||||
class MessageWriter final {
|
class MessageWriter final {
|
||||||
|
|
|
||||||
|
|
@ -317,7 +317,7 @@ public:
|
||||||
|
|
||||||
// get the random node on map
|
// get the random node on map
|
||||||
int32_t random () const {
|
int32_t random () const {
|
||||||
return rg.get (0, length () - 1);
|
return rg (0, length () - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if has editor
|
// check if has editor
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,7 @@ private:
|
||||||
bool m_jumpSequence {}; // next path link will be jump link
|
bool m_jumpSequence {}; // next path link will be jump link
|
||||||
|
|
||||||
PathWalk m_pathWalk {}; // pointer to current node from path
|
PathWalk m_pathWalk {}; // pointer to current node from path
|
||||||
Dodge m_combatStrafeDir {}; // direction to strafe
|
Dodge m_dodgeStrafeDir {}; // direction to strafe
|
||||||
Fight m_fightStyle {}; // combat style to use
|
Fight m_fightStyle {}; // combat style to use
|
||||||
CollisionState m_collisionState {}; // collision State
|
CollisionState m_collisionState {}; // collision State
|
||||||
FindPath m_pathType {}; // which pathfinder to use
|
FindPath m_pathType {}; // which pathfinder to use
|
||||||
|
|
@ -354,6 +354,7 @@ private:
|
||||||
|
|
||||||
CountdownTimer m_forgetLastVictimTimer {}; // time to forget last victim position ?
|
CountdownTimer m_forgetLastVictimTimer {}; // time to forget last victim position ?
|
||||||
CountdownTimer m_approachingLadderTimer {}; // bot is approaching ladder
|
CountdownTimer m_approachingLadderTimer {}; // bot is approaching ladder
|
||||||
|
CountdownTimer m_lostReachableNodeTimer {}; // bot's issuing next node, probably he's lost
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int pickBestWeapon (Array <int> &vec, int moneySave);
|
int pickBestWeapon (Array <int> &vec, int moneySave);
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ ConVar cv_graph_analyze_mark_goals_on_finish ("graph_analyze_mark_goals_on_finis
|
||||||
|
|
||||||
void GraphAnalyze::start () {
|
void GraphAnalyze::start () {
|
||||||
// start analyzer in few seconds after level initialized
|
// start analyzer in few seconds after level initialized
|
||||||
if (cv_graph_analyze_auto_start.bool_ ()) {
|
if (cv_graph_analyze_auto_start) {
|
||||||
m_updateInterval = game.time () + 3.0f;
|
m_updateInterval = game.time () + 3.0f;
|
||||||
m_basicsCreated = false;
|
m_basicsCreated = false;
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@ void GraphAnalyze::update () {
|
||||||
setUpdateInterval ();
|
setUpdateInterval ();
|
||||||
|
|
||||||
auto pos = graph[i].origin;
|
auto pos = graph[i].origin;
|
||||||
const auto range = cv_graph_analyze_distance.float_ ();
|
const auto range = cv_graph_analyze_distance.as <float> ();
|
||||||
|
|
||||||
for (int dir = 1; dir < kMaxNodeLinks; ++dir) {
|
for (int dir = 1; dir < kMaxNodeLinks; ++dir) {
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
|
|
@ -149,7 +149,7 @@ void GraphAnalyze::finish () {
|
||||||
ctrl.msg ("Completed map analysis.");
|
ctrl.msg ("Completed map analysis.");
|
||||||
|
|
||||||
// auto save bots graph
|
// auto save bots graph
|
||||||
if (cv_graph_analyze_auto_save.bool_ ()) {
|
if (cv_graph_analyze_auto_save) {
|
||||||
if (!graph.saveGraphData ()) {
|
if (!graph.saveGraphData ()) {
|
||||||
ctrl.msg ("Can't save analyzed graph. Internal error.");
|
ctrl.msg ("Can't save analyzed graph. Internal error.");
|
||||||
return;
|
return;
|
||||||
|
|
@ -171,7 +171,7 @@ void GraphAnalyze::optimize () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cv_graph_analyze_optimize_nodes_on_finish.bool_ ()) {
|
if (!cv_graph_analyze_optimize_nodes_on_finish) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cleanup ();
|
cleanup ();
|
||||||
|
|
@ -220,7 +220,7 @@ void GraphAnalyze::optimize () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the useless connections
|
// clear the useless connections
|
||||||
if (cv_graph_analyze_clean_paths_on_finish.bool_ ()) {
|
if (cv_graph_analyze_clean_paths_on_finish) {
|
||||||
for (auto i = 0; i < graph.length (); ++i) {
|
for (auto i = 0; i < graph.length (); ++i) {
|
||||||
graph.clearConnections (i);
|
graph.clearConnections (i);
|
||||||
}
|
}
|
||||||
|
|
@ -352,13 +352,13 @@ void GraphAnalyze::flood (const Vector &pos, const Vector &next, float range) {
|
||||||
void GraphAnalyze::setUpdateInterval () {
|
void GraphAnalyze::setUpdateInterval () {
|
||||||
const auto frametime = globals->frametime;
|
const auto frametime = globals->frametime;
|
||||||
|
|
||||||
if ((cv_graph_analyze_fps.float_ () + frametime) <= 1.0f / frametime) {
|
if ((cv_graph_analyze_fps.as <float> () + frametime) <= 1.0f / frametime) {
|
||||||
m_updateInterval = game.time () + frametime * 0.06f;
|
m_updateInterval = game.time () + frametime * 0.06f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphAnalyze::markGoals () {
|
void GraphAnalyze::markGoals () {
|
||||||
if (!cv_graph_analyze_mark_goals_on_finish.bool_ ()) {
|
if (!cv_graph_analyze_mark_goals_on_finish) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
201
src/botlib.cpp
201
src/botlib.cpp
|
|
@ -106,7 +106,7 @@ void Bot::avoidGrenades () {
|
||||||
m_lookAt.y = cr::wrapAngle ((game.getEntityOrigin (pent) - getEyesPos ()).angles ().y + 180.0f);
|
m_lookAt.y = cr::wrapAngle ((game.getEntityOrigin (pent) - getEyesPos ()).angles ().y + 180.0f);
|
||||||
|
|
||||||
m_canChooseAimDirection = false;
|
m_canChooseAimDirection = false;
|
||||||
m_preventFlashing = game.time () + rg.get (1.0f, 2.0f);
|
m_preventFlashing = game.time () + rg (1.0f, 2.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (game.isNullEntity (m_avoidGrenade) && model == kExplosiveModelName) {
|
else if (game.isNullEntity (m_avoidGrenade) && model == kExplosiveModelName) {
|
||||||
|
|
@ -132,7 +132,7 @@ void Bot::avoidGrenades () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cv_smoke_grenade_checks.int_ () == 1 && (pent->v.flags & FL_ONGROUND) && model == kSmokeModelName) {
|
else if (cv_smoke_grenade_checks.as <int> () == 1 && (pent->v.flags & FL_ONGROUND) && model == kSmokeModelName) {
|
||||||
if (isInFOV (pent->v.origin - getEyesPos ()) < pev->fov / 3.0f) {
|
if (isInFOV (pent->v.origin - getEyesPos ()) < pev->fov / 3.0f) {
|
||||||
const auto &entOrigin = game.getEntityOrigin (pent);
|
const auto &entOrigin = game.getEntityOrigin (pent);
|
||||||
const auto &betweenUs = (entOrigin - pev->origin).normalize_apx ();
|
const auto &betweenUs = (entOrigin - pev->origin).normalize_apx ();
|
||||||
|
|
@ -175,7 +175,7 @@ void Bot::checkBreakable (edict_t *touch) {
|
||||||
|
|
||||||
void Bot::checkBreakablesAround () {
|
void Bot::checkBreakablesAround () {
|
||||||
if (!m_buyingFinished
|
if (!m_buyingFinished
|
||||||
|| !cv_destroy_breakables_around.bool_ ()
|
|| !cv_destroy_breakables_around
|
||||||
|| usesKnife ()
|
|| usesKnife ()
|
||||||
|| rg.chance (25)
|
|| rg.chance (25)
|
||||||
|| !game.hasBreakables ()
|
|| !game.hasBreakables ()
|
||||||
|
|
@ -185,7 +185,7 @@ void Bot::checkBreakablesAround () {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto radius = cv_object_destroy_radius.float_ ();
|
const auto radius = cv_object_destroy_radius.as <float> ();
|
||||||
|
|
||||||
// check if we're have some breakables in 400 units range
|
// check if we're have some breakables in 400 units range
|
||||||
for (const auto &breakable : game.getBreakables ()) {
|
for (const auto &breakable : game.getBreakables ()) {
|
||||||
|
|
@ -280,7 +280,7 @@ edict_t *Bot::lookupBreakable () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::setIdealReactionTimers (bool actual) {
|
void Bot::setIdealReactionTimers (bool actual) {
|
||||||
if (cv_whose_your_daddy.bool_ ()) {
|
if (cv_whose_your_daddy) {
|
||||||
m_idealReactionTime = 0.05f;
|
m_idealReactionTime = 0.05f;
|
||||||
m_actualReactionTime = 0.095f;
|
m_actualReactionTime = 0.095f;
|
||||||
|
|
||||||
|
|
@ -294,7 +294,7 @@ void Bot::setIdealReactionTimers (bool actual) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_idealReactionTime = rg.get (tweak->reaction[0], tweak->reaction[1]);
|
m_idealReactionTime = rg (tweak->reaction[0], tweak->reaction[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::updatePickups () {
|
void Bot::updatePickups () {
|
||||||
|
|
@ -323,7 +323,7 @@ void Bot::updatePickups () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// knife mode is in progress ?
|
// knife mode is in progress ?
|
||||||
else if (cv_jasonmode.bool_ ()) {
|
else if (cv_jasonmode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,7 +343,7 @@ void Bot::updatePickups () {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &interesting = bots.getInterestingEntities ();
|
const auto &interesting = bots.getInterestingEntities ();
|
||||||
const float radius = cr::sqrf (cv_object_pickup_radius.float_ ());
|
const float radius = cr::sqrf (cv_object_pickup_radius.as <float> ());
|
||||||
|
|
||||||
if (!game.isNullEntity (m_pickupItem)) {
|
if (!game.isNullEntity (m_pickupItem)) {
|
||||||
bool itemExists = false;
|
bool itemExists = false;
|
||||||
|
|
@ -426,7 +426,7 @@ void Bot::updatePickups () {
|
||||||
allowPickup = true;
|
allowPickup = true;
|
||||||
pickupType = Pickup::Weapon;
|
pickupType = Pickup::Weapon;
|
||||||
|
|
||||||
if (cv_pickup_ammo_and_kits.bool_ ()) {
|
if (cv_pickup_ammo_and_kits) {
|
||||||
const int primaryWeaponCarried = bestPrimaryCarried ();
|
const int primaryWeaponCarried = bestPrimaryCarried ();
|
||||||
const int secondaryWeaponCarried = bestSecondaryCarried ();
|
const int secondaryWeaponCarried = bestSecondaryCarried ();
|
||||||
|
|
||||||
|
|
@ -494,7 +494,7 @@ void Bot::updatePickups () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// weapon replacement is not allowed
|
// weapon replacement is not allowed
|
||||||
if (!cv_pickup_best.bool_ ()) {
|
if (!cv_pickup_best) {
|
||||||
allowPickup = false;
|
allowPickup = false;
|
||||||
pickupType = Pickup::None;
|
pickupType = Pickup::None;
|
||||||
}
|
}
|
||||||
|
|
@ -504,7 +504,7 @@ void Bot::updatePickups () {
|
||||||
pickupType = Pickup::Shield;
|
pickupType = Pickup::Shield;
|
||||||
|
|
||||||
// weapon replacement is not allowed
|
// weapon replacement is not allowed
|
||||||
if (!cv_pickup_best.bool_ ()) {
|
if (!cv_pickup_best) {
|
||||||
allowPickup = false;
|
allowPickup = false;
|
||||||
pickupType = Pickup::None;
|
pickupType = Pickup::None;
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +517,7 @@ void Bot::updatePickups () {
|
||||||
allowPickup = true;
|
allowPickup = true;
|
||||||
pickupType = Pickup::PlantedC4;
|
pickupType = Pickup::PlantedC4;
|
||||||
}
|
}
|
||||||
else if (cv_pickup_custom_items.bool_ () && util.isItem (ent) && !classname.startsWith ("item_thighpack")) {
|
else if (cv_pickup_custom_items && util.isItem (ent) && !classname.startsWith ("item_thighpack")) {
|
||||||
allowPickup = true;
|
allowPickup = true;
|
||||||
pickupType = Pickup::Items;
|
pickupType = Pickup::Items;
|
||||||
}
|
}
|
||||||
|
|
@ -577,8 +577,8 @@ void Bot::updatePickups () {
|
||||||
|
|
||||||
const int index = findDefendNode (origin);
|
const int index = findDefendNode (origin);
|
||||||
|
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (cv_camping_time_min.float_ (), cv_camping_time_max.float_ ()), true); // push camp task on to stack
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (cv_camping_time_min.as <float> (), cv_camping_time_max.as <float> ()), true); // push camp task on to stack
|
||||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (3.0f, 6.0f), true); // push move command
|
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (3.0f, 6.0f), true); // push move command
|
||||||
|
|
||||||
// decide to duck or not to duck
|
// decide to duck or not to duck
|
||||||
selectCampButtons (index);
|
selectCampButtons (index);
|
||||||
|
|
@ -597,7 +597,7 @@ void Bot::updatePickups () {
|
||||||
const int index = findDefendNode (origin);
|
const int index = findDefendNode (origin);
|
||||||
const Path &path = graph[index];
|
const Path &path = graph[index];
|
||||||
|
|
||||||
const float bombTimer = mp_c4timer.float_ ();
|
const float bombTimer = mp_c4timer.as <float> ();
|
||||||
const float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
|
const float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
|
||||||
|
|
||||||
if (timeMidBlowup > game.time ()) {
|
if (timeMidBlowup > game.time ()) {
|
||||||
|
|
@ -672,7 +672,7 @@ void Bot::updatePickups () {
|
||||||
const int index = findDefendNode (origin);
|
const int index = findDefendNode (origin);
|
||||||
const auto &path = graph[index];
|
const auto &path = graph[index];
|
||||||
|
|
||||||
const float timeToExplode = bots.getTimeBombPlanted () + mp_c4timer.float_ () - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
|
const float timeToExplode = bots.getTimeBombPlanted () + mp_c4timer.as <float> () - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
|
||||||
|
|
||||||
clearTask (Task::MoveToPosition); // remove any move tasks
|
clearTask (Task::MoveToPosition); // remove any move tasks
|
||||||
|
|
||||||
|
|
@ -700,8 +700,8 @@ void Bot::updatePickups () {
|
||||||
if (!m_defendedBomb && m_difficulty >= Difficulty::Normal && rg.chance (75) && m_healthValue < 60) {
|
if (!m_defendedBomb && m_difficulty >= Difficulty::Normal && rg.chance (75) && m_healthValue < 60) {
|
||||||
const int index = findDefendNode (origin);
|
const int index = findDefendNode (origin);
|
||||||
|
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (cv_camping_time_min.float_ (), cv_camping_time_max.float_ ()), true); // push camp task on to stack
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (cv_camping_time_min.as <float> (), cv_camping_time_max.as <float> ()), true); // push camp task on to stack
|
||||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (10.0f, 30.0f), true); // push move command
|
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (10.0f, 30.0f), true); // push move command
|
||||||
|
|
||||||
// decide to duck or not to duck
|
// decide to duck or not to duck
|
||||||
selectCampButtons (index);
|
selectCampButtons (index);
|
||||||
|
|
@ -839,7 +839,7 @@ Vector Bot::getCampDirection (const Vector &dest) {
|
||||||
void Bot::showChatterIcon (bool show, bool disconnect) {
|
void Bot::showChatterIcon (bool show, bool disconnect) {
|
||||||
// this function depending on show boolean, shows/remove chatter, icon, on the head of bot.
|
// this function depending on show boolean, shows/remove chatter, icon, on the head of bot.
|
||||||
|
|
||||||
if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.int_ () != 2) {
|
if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.as <int> () != 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -877,7 +877,7 @@ void Bot::showChatterIcon (bool show, bool disconnect) {
|
||||||
void Bot::instantChatter (int type) {
|
void Bot::instantChatter (int type) {
|
||||||
// this function sends instant chatter messages.
|
// this function sends instant chatter messages.
|
||||||
if (!game.is (GameFlags::HasBotVoice)
|
if (!game.is (GameFlags::HasBotVoice)
|
||||||
|| cv_radio_mode.int_ () != 2
|
|| cv_radio_mode.as <int> () != 2
|
||||||
|| !conf.hasChatterBank (type)
|
|| !conf.hasChatterBank (type)
|
||||||
|| !conf.hasChatterBank (Chatter::DiePain)) {
|
|| !conf.hasChatterBank (Chatter::DiePain)) {
|
||||||
|
|
||||||
|
|
@ -894,7 +894,7 @@ void Bot::instantChatter (int type) {
|
||||||
const int ownIndex = index ();
|
const int ownIndex = index ();
|
||||||
|
|
||||||
auto writeChatterSound = [&msg] (ChatterItem item) {
|
auto writeChatterSound = [&msg] (ChatterItem item) {
|
||||||
msg.writeString (strings.format ("%s%s%s.wav", cv_chatter_path.str (), kPathSeparator, item.name));
|
msg.writeString (strings.format ("%s%s%s.wav", cv_chatter_path.as <StringRef> (), kPathSeparator, item.name));
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto &client : util.getClients ()) {
|
for (auto &client : util.getClients ()) {
|
||||||
|
|
@ -920,12 +920,12 @@ void Bot::instantChatter (int type) {
|
||||||
void Bot::pushRadioMessage (int message) {
|
void Bot::pushRadioMessage (int message) {
|
||||||
// this function inserts the radio message into the message queue
|
// this function inserts the radio message into the message queue
|
||||||
|
|
||||||
if (cv_radio_mode.int_ () == 0 || m_numFriendsLeft == 0) {
|
if (cv_radio_mode.as <int> () == 0 || m_numFriendsLeft == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_forceRadio = !game.is (GameFlags::HasBotVoice)
|
m_forceRadio = !game.is (GameFlags::HasBotVoice)
|
||||||
|| !conf.hasChatterBank (message)
|
|| !conf.hasChatterBank (message)
|
||||||
|| cv_radio_mode.int_ () != 2; // use radio instead voice
|
|| cv_radio_mode.as <int> () != 2; // use radio instead voice
|
||||||
|
|
||||||
m_radioSelect = message;
|
m_radioSelect = message;
|
||||||
pushMsgQueue (BotMsg::Radio);
|
pushMsgQueue (BotMsg::Radio);
|
||||||
|
|
@ -934,7 +934,7 @@ void Bot::pushRadioMessage (int message) {
|
||||||
void Bot::pushChatterMessage (int message) {
|
void Bot::pushChatterMessage (int message) {
|
||||||
// this function inserts the voice message into the message queue (mostly same as above)
|
// this function inserts the voice message into the message queue (mostly same as above)
|
||||||
|
|
||||||
if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.int_ () != 2 || !conf.hasChatterBank (message) || m_numFriendsLeft == 0) {
|
if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.as <int> () != 2 || !conf.hasChatterBank (message) || m_numFriendsLeft == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool sendMessage = false;
|
bool sendMessage = false;
|
||||||
|
|
@ -991,21 +991,21 @@ void Bot::checkMsgQueue () {
|
||||||
}
|
}
|
||||||
|
|
||||||
m_buyPending = false;
|
m_buyPending = false;
|
||||||
m_nextBuyTime = game.time () + rg.get (0.5f, 1.3f);
|
m_nextBuyTime = game.time () + rg (0.5f, 1.3f);
|
||||||
|
|
||||||
// if freezetime is very low do not delay the buy process
|
// if freezetime is very low do not delay the buy process
|
||||||
if (mp_freezetime.float_ () <= 1.0f) {
|
if (mp_freezetime.as <float> () <= 1.0f) {
|
||||||
m_nextBuyTime = game.time ();
|
m_nextBuyTime = game.time ();
|
||||||
m_ignoreBuyDelay = true;
|
m_ignoreBuyDelay = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if bot buying is off then no need to buy
|
// if bot buying is off then no need to buy
|
||||||
if (!cv_botbuy.bool_ ()) {
|
if (!cv_botbuy) {
|
||||||
m_buyState = BuyState::Done;
|
m_buyState = BuyState::Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if fun-mode no need to buy
|
// if fun-mode no need to buy
|
||||||
if (cv_jasonmode.bool_ ()) {
|
if (cv_jasonmode) {
|
||||||
m_buyState = BuyState::Done;
|
m_buyState = BuyState::Done;
|
||||||
selectWeaponById (Weapon::Knife);
|
selectWeaponById (Weapon::Knife);
|
||||||
}
|
}
|
||||||
|
|
@ -1067,7 +1067,7 @@ void Bot::checkMsgQueue () {
|
||||||
|
|
||||||
if (m_radioSelect != -1) {
|
if (m_radioSelect != -1) {
|
||||||
if ((m_radioSelect != Radio::ReportingIn && m_forceRadio)
|
if ((m_radioSelect != Radio::ReportingIn && m_forceRadio)
|
||||||
|| cv_radio_mode.int_ () != 2
|
|| cv_radio_mode.as <int> () != 2
|
||||||
|| !conf.hasChatterBank (m_radioSelect)
|
|| !conf.hasChatterBank (m_radioSelect)
|
||||||
|| !game.is (GameFlags::HasBotVoice)) {
|
|| !game.is (GameFlags::HasBotVoice)) {
|
||||||
|
|
||||||
|
|
@ -1116,7 +1116,7 @@ void Bot::checkMsgQueue () {
|
||||||
bool Bot::isWeaponRestricted (int wid) {
|
bool Bot::isWeaponRestricted (int wid) {
|
||||||
// this function checks for weapon restrictions.
|
// this function checks for weapon restrictions.
|
||||||
|
|
||||||
auto val = cv_restricted_weapons.str ();
|
auto val = cv_restricted_weapons.as <StringRef> ();
|
||||||
|
|
||||||
if (val.empty ()) {
|
if (val.empty ()) {
|
||||||
return isWeaponRestrictedAMX (wid); // no banned weapons
|
return isWeaponRestrictedAMX (wid); // no banned weapons
|
||||||
|
|
@ -1213,7 +1213,7 @@ int Bot::pickBestWeapon (Array <int> &vec, int moneySave) {
|
||||||
// swap array values
|
// swap array values
|
||||||
vec.reverse ();
|
vec.reverse ();
|
||||||
|
|
||||||
return vec[static_cast <int> (static_cast <float> (vec.length <int32_t> () - 1) * cr::log10 (rg.get (1.0f, cr::powf (10.0f, buyFactor))) / buyFactor + 0.5f)];
|
return vec[static_cast <int> (static_cast <float> (vec.length <int32_t> () - 1) * cr::log10 (rg (1.0f, cr::powf (10.0f, buyFactor))) / buyFactor + 0.5f)];
|
||||||
}
|
}
|
||||||
int chance = 95;
|
int chance = 95;
|
||||||
|
|
||||||
|
|
@ -1232,7 +1232,7 @@ int Bot::pickBestWeapon (Array <int> &vec, int moneySave) {
|
||||||
const auto &weapon = tab[w];
|
const auto &weapon = tab[w];
|
||||||
|
|
||||||
// if we have enough money for weapon, buy it
|
// if we have enough money for weapon, buy it
|
||||||
if (weapon.price + moneySave < m_moneyAmount + rg.get (50, 200) && rg.chance (chance)) {
|
if (weapon.price + moneySave < m_moneyAmount + rg (50, 200) && rg.chance (chance)) {
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1246,7 +1246,7 @@ void Bot::buyStuff () {
|
||||||
m_nextBuyTime = game.time ();
|
m_nextBuyTime = game.time ();
|
||||||
|
|
||||||
if (!m_ignoreBuyDelay) {
|
if (!m_ignoreBuyDelay) {
|
||||||
m_nextBuyTime += rg.get (0.3f, 0.5f);
|
m_nextBuyTime += rg (0.3f, 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
@ -1263,7 +1263,7 @@ void Bot::buyStuff () {
|
||||||
const bool isOldGame = game.is (GameFlags::Legacy);
|
const bool isOldGame = game.is (GameFlags::Legacy);
|
||||||
|
|
||||||
const bool hasDefaultPistols = (pev->weapons & (cr::bit (Weapon::USP) | cr::bit (Weapon::Glock18)));
|
const bool hasDefaultPistols = (pev->weapons & (cr::bit (Weapon::USP) | cr::bit (Weapon::Glock18)));
|
||||||
const bool isFirstRound = m_moneyAmount == mp_startmoney.int_ ();
|
const bool isFirstRound = m_moneyAmount == mp_startmoney.as <int> ();
|
||||||
|
|
||||||
switch (m_buyState) {
|
switch (m_buyState) {
|
||||||
case BuyState::PrimaryWeapon: // if no primary weapon and bot has some money, buy a primary weapon
|
case BuyState::PrimaryWeapon: // if no primary weapon and bot has some money, buy a primary weapon
|
||||||
|
|
@ -1308,7 +1308,7 @@ void Bot::buyStuff () {
|
||||||
const int *limit = conf.getEconLimit ();
|
const int *limit = conf.getEconLimit ();
|
||||||
int prostock = 0;
|
int prostock = 0;
|
||||||
|
|
||||||
const int disrespectEconomicsPct = 100 - cv_economics_disrespect_percent.int_ ();
|
const int disrespectEconomicsPct = 100 - cv_economics_disrespect_percent.as <int> ();
|
||||||
|
|
||||||
// filter out weapons with bot economics
|
// filter out weapons with bot economics
|
||||||
switch (m_personality) {
|
switch (m_personality) {
|
||||||
|
|
@ -1389,12 +1389,12 @@ void Bot::buyStuff () {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ignoreWeapon && tab[25].teamStandard == 1 && cv_economics_rounds.bool_ ()) {
|
if (ignoreWeapon && tab[25].teamStandard == 1 && cv_economics_rounds) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save money for grenade for example?
|
// save money for grenade for example?
|
||||||
moneySave = rg.get (500, 1000);
|
moneySave = rg (500, 1000);
|
||||||
|
|
||||||
if (bots.getLastWinner () == m_team) {
|
if (bots.getLastWinner () == m_team) {
|
||||||
moneySave = 0;
|
moneySave = 0;
|
||||||
|
|
@ -1441,7 +1441,7 @@ void Bot::buyStuff () {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BuyState::ArmorVestHelm: // if armor is damaged and bot has some money, buy some armor
|
case BuyState::ArmorVestHelm: // if armor is damaged and bot has some money, buy some armor
|
||||||
if (pev->armorvalue < rg.get (50.0f, 80.0f)
|
if (pev->armorvalue < rg (50.0f, 80.0f)
|
||||||
&& teamHasGoodEconomics
|
&& teamHasGoodEconomics
|
||||||
&& (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) {
|
&& (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) {
|
||||||
|
|
||||||
|
|
@ -1458,8 +1458,8 @@ void Bot::buyStuff () {
|
||||||
case BuyState::SecondaryWeapon: // if bot has still some money, buy a better secondary weapon
|
case BuyState::SecondaryWeapon: // if bot has still some money, buy a better secondary weapon
|
||||||
if (isPistolMode
|
if (isPistolMode
|
||||||
|| (isFirstRound && hasDefaultPistols && rg.chance (60))
|
|| (isFirstRound && hasDefaultPistols && rg.chance (60))
|
||||||
|| (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg.get (2000, 3000))
|
|| (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg (2000, 3000))
|
||||||
|| (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg.get (7500, 9000))) {
|
|| (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg (7500, 9000))) {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
pref--;
|
pref--;
|
||||||
|
|
@ -1492,7 +1492,7 @@ void Bot::buyStuff () {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedWeapon->price <= (m_moneyAmount - rg.get (100, 200))) {
|
if (selectedWeapon->price <= (m_moneyAmount - rg (100, 200))) {
|
||||||
choices.emplace (*pref);
|
choices.emplace (*pref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1500,7 +1500,7 @@ void Bot::buyStuff () {
|
||||||
|
|
||||||
// found a desired weapon?
|
// found a desired weapon?
|
||||||
if (!choices.empty ()) {
|
if (!choices.empty ()) {
|
||||||
selectedWeapon = &tab[pickBestWeapon (choices, rg.get (100, 200))];
|
selectedWeapon = &tab[pickBestWeapon (choices, rg (100, 200))];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
selectedWeapon = nullptr;
|
selectedWeapon = nullptr;
|
||||||
|
|
@ -1527,7 +1527,7 @@ void Bot::buyStuff () {
|
||||||
|
|
||||||
case BuyState::Ammo: // buy enough primary & secondary ammo (do not check for money here)
|
case BuyState::Ammo: // buy enough primary & secondary ammo (do not check for money here)
|
||||||
for (int i = 0; i < 7; ++i) {
|
for (int i = 0; i < 7; ++i) {
|
||||||
issueCommand ("buyammo%d", rg.get (1, 2)); // simulate human
|
issueCommand ("buyammo%d", rg (1, 2)); // simulate human
|
||||||
}
|
}
|
||||||
|
|
||||||
// buy enough ammo
|
// buy enough ammo
|
||||||
|
|
@ -1654,7 +1654,7 @@ void Bot::overrideConditions () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// special handling, if we have a knife in our hands
|
// special handling, if we have a knife in our hands
|
||||||
if (isKnifeMode () && (util.isPlayer (m_enemy) || (cv_attack_monsters.bool_ () && util.isMonster (m_enemy)))) {
|
if (isKnifeMode () && (util.isPlayer (m_enemy) || (cv_attack_monsters && util.isMonster (m_enemy)))) {
|
||||||
const float length = pev->origin.distance2d (m_enemy->v.origin);
|
const float length = pev->origin.distance2d (m_enemy->v.origin);
|
||||||
|
|
||||||
// do nodes movement if enemy is not reachable with a knife
|
// do nodes movement if enemy is not reachable with a knife
|
||||||
|
|
@ -1802,7 +1802,7 @@ void Bot::setLastVictim (edict_t *ent) {
|
||||||
m_lastVictim = ent;
|
m_lastVictim = ent;
|
||||||
m_lastVictimOrigin = ent->v.origin;
|
m_lastVictimOrigin = ent->v.origin;
|
||||||
|
|
||||||
m_forgetLastVictimTimer.start (rg.get (1.0f, 2.0f));
|
m_forgetLastVictimTimer.start (rg (1.0f, 2.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::setConditions () {
|
void Bot::setConditions () {
|
||||||
|
|
@ -1897,7 +1897,7 @@ void Bot::setConditions () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't listen if seeing enemy, just checked for sounds or being blinded (because its inhuman)
|
// don't listen if seeing enemy, just checked for sounds or being blinded (because its inhuman)
|
||||||
if (!cv_ignore_enemies.bool_ ()
|
if (!cv_ignore_enemies
|
||||||
&& m_soundUpdateTime < game.time ()
|
&& m_soundUpdateTime < game.time ()
|
||||||
&& m_blindTime < game.time ()
|
&& m_blindTime < game.time ()
|
||||||
&& m_seeEnemyTime + 1.0f < game.time ()) {
|
&& m_seeEnemyTime + 1.0f < game.time ()) {
|
||||||
|
|
@ -1991,12 +1991,12 @@ void Bot::filterTasks () {
|
||||||
if (util.isPlayer (m_lastEnemy) && !m_lastEnemyOrigin.empty () && !m_hasC4) {
|
if (util.isPlayer (m_lastEnemy) && !m_lastEnemyOrigin.empty () && !m_hasC4) {
|
||||||
float retreatLevel = (100.0f - (m_healthValue > 70.0f ? 100.0f : m_healthValue)) * tempFear; // retreat level depends on bot health
|
float retreatLevel = (100.0f - (m_healthValue > 70.0f ? 100.0f : m_healthValue)) * tempFear; // retreat level depends on bot health
|
||||||
|
|
||||||
if (m_numEnemiesLeft > m_numFriendsLeft / 2 && m_retreatTime < game.time () && m_seeEnemyTime - rg.get (2.0f, 4.0f) < game.time ()) {
|
if (m_numEnemiesLeft > m_numFriendsLeft / 2 && m_retreatTime < game.time () && m_seeEnemyTime - rg (2.0f, 4.0f) < game.time ()) {
|
||||||
float timeSeen = m_seeEnemyTime - game.time ();
|
float timeSeen = m_seeEnemyTime - game.time ();
|
||||||
float timeHeard = m_heardSoundTime - game.time ();
|
float timeHeard = m_heardSoundTime - game.time ();
|
||||||
float ratio = 0.0f;
|
float ratio = 0.0f;
|
||||||
|
|
||||||
m_retreatTime = game.time () + rg.get (1.0f, 4.0f);
|
m_retreatTime = game.time () + rg (1.0f, 4.0f);
|
||||||
|
|
||||||
if (timeSeen > timeHeard) {
|
if (timeSeen > timeHeard) {
|
||||||
timeSeen += 10.0f;
|
timeSeen += 10.0f;
|
||||||
|
|
@ -2042,7 +2042,7 @@ void Bot::filterTasks () {
|
||||||
&& !m_isUsingGrenade
|
&& !m_isUsingGrenade
|
||||||
&& m_currentNodeIndex != graph.getNearest (m_lastEnemyOrigin)
|
&& m_currentNodeIndex != graph.getNearest (m_lastEnemyOrigin)
|
||||||
&& m_personality != Personality::Careful
|
&& m_personality != Personality::Careful
|
||||||
&& !cv_ignore_enemies.bool_ ()) {
|
&& !cv_ignore_enemies) {
|
||||||
|
|
||||||
float desireLevel = 4096.0f - ((1.0f - tempAgression) * m_lastEnemyOrigin.distance (pev->origin));
|
float desireLevel = 4096.0f - ((1.0f - tempAgression) * m_lastEnemyOrigin.distance (pev->origin));
|
||||||
|
|
||||||
|
|
@ -2166,7 +2166,7 @@ void Bot::startTask (Task id, float desire, int data, float time, bool resume) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is best place to handle some voice commands report team some info
|
// this is best place to handle some voice commands report team some info
|
||||||
if (cv_radio_mode.int_ () > 1) {
|
if (cv_radio_mode.as <int> () > 1) {
|
||||||
if (rg.chance (90)) {
|
if (rg.chance (90)) {
|
||||||
if (tid == Task::Blind) {
|
if (tid == Task::Blind) {
|
||||||
pushChatterMessage (Chatter::Blind);
|
pushChatterMessage (Chatter::Blind);
|
||||||
|
|
@ -2198,8 +2198,8 @@ void Bot::startTask (Task id, float desire, int data, float time, bool resume) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cv_debug_goal.int_ () != kInvalidNodeIndex) {
|
if (cv_debug_goal.as <int> () != kInvalidNodeIndex) {
|
||||||
m_chosenGoalIndex = cv_debug_goal.int_ ();
|
m_chosenGoalIndex = cv_debug_goal.as <int> ();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_chosenGoalIndex = getTask ()->data;
|
m_chosenGoalIndex = getTask ()->data;
|
||||||
|
|
@ -2354,7 +2354,7 @@ void Bot::checkRadioQueue () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int allowedFollowers = cv_user_max_followers.int_ ();
|
int allowedFollowers = cv_user_max_followers.as <int> ();
|
||||||
|
|
||||||
if (m_radioEntity->v.weapons & cr::bit (Weapon::C4)) {
|
if (m_radioEntity->v.weapons & cr::bit (Weapon::C4)) {
|
||||||
allowedFollowers = 1;
|
allowedFollowers = 1;
|
||||||
|
|
@ -2403,7 +2403,7 @@ void Bot::checkRadioQueue () {
|
||||||
pushRadioMessage (Radio::RogerThat);
|
pushRadioMessage (Radio::RogerThat);
|
||||||
|
|
||||||
m_campButtons = 0;
|
m_campButtons = 0;
|
||||||
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), false);
|
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg (30.0f, 60.0f), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -2422,10 +2422,10 @@ void Bot::checkRadioQueue () {
|
||||||
m_fearLevel = 0.0f;
|
m_fearLevel = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rg.chance (45) && cv_radio_mode.int_ () == 2) {
|
if (rg.chance (45) && cv_radio_mode.as <int> () == 2) {
|
||||||
pushChatterMessage (Chatter::OnMyWay);
|
pushChatterMessage (Chatter::OnMyWay);
|
||||||
}
|
}
|
||||||
else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.int_ () != 2) {
|
else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as <int> () != 2) {
|
||||||
pushRadioMessage (Radio::RogerThat);
|
pushRadioMessage (Radio::RogerThat);
|
||||||
}
|
}
|
||||||
tryHeadTowardRadioMessage ();
|
tryHeadTowardRadioMessage ();
|
||||||
|
|
@ -2456,10 +2456,10 @@ void Bot::checkRadioQueue () {
|
||||||
m_fearLevel = 0.0f;
|
m_fearLevel = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rg.chance (45) && cv_radio_mode.int_ () == 2) {
|
if (rg.chance (45) && cv_radio_mode.as <int> () == 2) {
|
||||||
pushChatterMessage (Chatter::OnMyWay);
|
pushChatterMessage (Chatter::OnMyWay);
|
||||||
}
|
}
|
||||||
else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.int_ () != 2 && rg.chance (50)) {
|
else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as <int> () != 2 && rg.chance (50)) {
|
||||||
pushRadioMessage (Radio::RogerThat);
|
pushRadioMessage (Radio::RogerThat);
|
||||||
}
|
}
|
||||||
tryHeadTowardRadioMessage ();
|
tryHeadTowardRadioMessage ();
|
||||||
|
|
@ -2471,10 +2471,10 @@ void Bot::checkRadioQueue () {
|
||||||
|
|
||||||
case Radio::GoGoGo:
|
case Radio::GoGoGo:
|
||||||
if (m_radioEntity == m_targetEntity) {
|
if (m_radioEntity == m_targetEntity) {
|
||||||
if (rg.chance (45) && cv_radio_mode.int_ () == 2) {
|
if (rg.chance (45) && cv_radio_mode.as <int> () == 2) {
|
||||||
pushRadioMessage (Radio::RogerThat);
|
pushRadioMessage (Radio::RogerThat);
|
||||||
}
|
}
|
||||||
else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.int_ () != 2) {
|
else if (m_radioOrder == Radio::NeedBackup && cv_radio_mode.as <int> () != 2) {
|
||||||
pushRadioMessage (Radio::RogerThat);
|
pushRadioMessage (Radio::RogerThat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2500,7 +2500,7 @@ void Bot::checkRadioQueue () {
|
||||||
getTask ()->time = game.time ();
|
getTask ()->time = game.time ();
|
||||||
|
|
||||||
m_targetEntity = nullptr;
|
m_targetEntity = nullptr;
|
||||||
m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg.get (1024.0f, 2048.0f);
|
m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg (1024.0f, 2048.0f);
|
||||||
|
|
||||||
clearSearchNodes ();
|
clearSearchNodes ();
|
||||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true);
|
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true);
|
||||||
|
|
@ -2554,7 +2554,7 @@ void Bot::checkRadioQueue () {
|
||||||
getTask ()->time = game.time ();
|
getTask ()->time = game.time ();
|
||||||
}
|
}
|
||||||
m_targetEntity = nullptr;
|
m_targetEntity = nullptr;
|
||||||
m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg.get (1024.0f, 2048.0f);
|
m_position = m_radioEntity->v.origin + m_radioEntity->v.v_angle.forward () * rg (1024.0f, 2048.0f);
|
||||||
|
|
||||||
clearSearchNodes ();
|
clearSearchNodes ();
|
||||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true);
|
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, kInvalidNodeIndex, 0.0f, true);
|
||||||
|
|
@ -2585,7 +2585,7 @@ void Bot::checkRadioQueue () {
|
||||||
m_agressionLevel = 0.0f;
|
m_agressionLevel = 0.0f;
|
||||||
}
|
}
|
||||||
if (getCurrentTaskId () == Task::Camp) {
|
if (getCurrentTaskId () == Task::Camp) {
|
||||||
getTask ()->time += rg.get (10.0f, 15.0f);
|
getTask ()->time += rg (10.0f, 15.0f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// don't pause/camp anymore
|
// don't pause/camp anymore
|
||||||
|
|
@ -2746,7 +2746,7 @@ void Bot::checkRadioQueue () {
|
||||||
pushRadioMessage (Radio::RogerThat);
|
pushRadioMessage (Radio::RogerThat);
|
||||||
|
|
||||||
if (getCurrentTaskId () == Task::Camp) {
|
if (getCurrentTaskId () == Task::Camp) {
|
||||||
getTask ()->time = game.time () + rg.get (30.0f, 60.0f);
|
getTask ()->time = game.time () + rg (30.0f, 60.0f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// don't pause anymore
|
// don't pause anymore
|
||||||
|
|
@ -2785,10 +2785,10 @@ void Bot::checkRadioQueue () {
|
||||||
const int index = findDefendNode (m_radioEntity->v.origin);
|
const int index = findDefendNode (m_radioEntity->v.origin);
|
||||||
|
|
||||||
// push camp task on to stack
|
// push camp task on to stack
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true);
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (30.0f, 60.0f), true);
|
||||||
|
|
||||||
// push move command
|
// push move command
|
||||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (30.0f, 60.0f), true);
|
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (30.0f, 60.0f), true);
|
||||||
|
|
||||||
// decide to duck or not to duck
|
// decide to duck or not to duck
|
||||||
selectCampButtons (index);
|
selectCampButtons (index);
|
||||||
|
|
@ -2885,7 +2885,7 @@ void Bot::frame () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// kick the bot if stay time is over, the quota maintain will add new bot for us later
|
// kick the bot if stay time is over, the quota maintain will add new bot for us later
|
||||||
if (cv_rotate_bots.bool_ () && m_stayTime < game.time ()) {
|
if (cv_rotate_bots && m_stayTime < game.time ()) {
|
||||||
m_kickedByRotation = true; // kicked by rotation, so not save bot name if save bot names is active
|
m_kickedByRotation = true; // kicked by rotation, so not save bot name if save bot names is active
|
||||||
|
|
||||||
kick ();
|
kick ();
|
||||||
|
|
@ -2905,7 +2905,7 @@ void Bot::update () {
|
||||||
if (m_team == Team::Terrorist && game.mapIs (MapFlags::Demolition)) {
|
if (m_team == Team::Terrorist && game.mapIs (MapFlags::Demolition)) {
|
||||||
m_hasC4 = !!(pev->weapons & cr::bit (Weapon::C4));
|
m_hasC4 = !!(pev->weapons & cr::bit (Weapon::C4));
|
||||||
|
|
||||||
if (m_hasC4 && (cv_ignore_objectives.bool_ () || cv_jasonmode.bool_ ())) {
|
if (m_hasC4 && (cv_ignore_objectives || cv_jasonmode)) {
|
||||||
m_hasC4 = false;
|
m_hasC4 = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2931,12 +2931,12 @@ void Bot::update () {
|
||||||
}
|
}
|
||||||
else if (!m_isAlive) {
|
else if (!m_isAlive) {
|
||||||
// we got a teamkiller? vote him away...
|
// we got a teamkiller? vote him away...
|
||||||
if (m_voteKickIndex != m_lastVoteKick && cv_tkpunish.bool_ ()) {
|
if (m_voteKickIndex != m_lastVoteKick && cv_tkpunish) {
|
||||||
issueCommand ("vote %d", m_voteKickIndex);
|
issueCommand ("vote %d", m_voteKickIndex);
|
||||||
m_lastVoteKick = m_voteKickIndex;
|
m_lastVoteKick = m_voteKickIndex;
|
||||||
|
|
||||||
// if bot tk punishment is enabled slay the tk
|
// if bot tk punishment is enabled slay the tk
|
||||||
if (cv_tkpunish.int_ () != 2 || util.isFakeClient (game.entityOfIndex (m_voteKickIndex))) {
|
if (cv_tkpunish.as <int> () != 2 || util.isFakeClient (game.entityOfIndex (m_voteKickIndex))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto killer = game.entityOfIndex (m_lastVoteKick);
|
auto killer = game.entityOfIndex (m_lastVoteKick);
|
||||||
|
|
@ -2953,7 +2953,7 @@ void Bot::update () {
|
||||||
}
|
}
|
||||||
else if (m_buyingFinished
|
else if (m_buyingFinished
|
||||||
&& !(pev->maxspeed < 10.0f && tid != Task::PlantBomb && tid != Task::DefuseBomb)
|
&& !(pev->maxspeed < 10.0f && tid != Task::PlantBomb && tid != Task::DefuseBomb)
|
||||||
&& !cv_freeze_bots.bool_ ()
|
&& !cv_freeze_bots
|
||||||
&& !graph.hasChanged ()) {
|
&& !graph.hasChanged ()) {
|
||||||
|
|
||||||
botMovement = true;
|
botMovement = true;
|
||||||
|
|
@ -2972,17 +2972,13 @@ void Bot::update () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::logicDuringFreezetime () {
|
void Bot::logicDuringFreezetime () {
|
||||||
|
pev->button = 0;
|
||||||
|
|
||||||
if (m_changeViewTime > game.time ()) {
|
if (m_changeViewTime > game.time ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// simply skip randomly
|
if (rg.chance (15) && m_jumpTime + rg (1.0f, 2.0f) < game.time ()) {
|
||||||
if (rg.chance (10)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pev->button &= ~IN_DUCK;
|
|
||||||
|
|
||||||
if (rg.chance (15) && m_jumpTime + rg.get (1.0, 2.0f) < game.time ()) {
|
|
||||||
pev->button |= IN_JUMP;
|
pev->button |= IN_JUMP;
|
||||||
m_jumpTime = game.time ();
|
m_jumpTime = game.time ();
|
||||||
}
|
}
|
||||||
|
|
@ -2990,7 +2986,7 @@ void Bot::logicDuringFreezetime () {
|
||||||
teammates.clear ();
|
teammates.clear ();
|
||||||
|
|
||||||
for (const auto &bot : bots) {
|
for (const auto &bot : bots) {
|
||||||
if (bot->m_isAlive && bot->m_team == m_team && seesEntity (bot->pev->origin) && bot.get () != this) {
|
if (bot->m_isAlive && bot->m_team == m_team && bot.get () != this && seesEntity (bot->pev->origin)) {
|
||||||
teammates.push (bot.get ());
|
teammates.push (bot.get ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3008,7 +3004,7 @@ void Bot::logicDuringFreezetime () {
|
||||||
m_needToSendWelcomeChat = false;
|
m_needToSendWelcomeChat = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_changeViewTime = game.time () + rg.get (1.25f, 2.0f);
|
m_changeViewTime = game.time () + rg (1.25f, 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::executeTasks () {
|
void Bot::executeTasks () {
|
||||||
|
|
@ -3024,8 +3020,8 @@ void Bot::checkSpawnConditions () {
|
||||||
// this function is called instead of ai when buying finished, but freezetime is not yet left.
|
// this function is called instead of ai when buying finished, but freezetime is not yet left.
|
||||||
|
|
||||||
// switch to knife if time to do this
|
// switch to knife if time to do this
|
||||||
if (m_checkKnifeSwitch && m_buyingFinished && m_spawnTime + rg.get (5.0f, 7.5f) < game.time ()) {
|
if (m_checkKnifeSwitch && m_buyingFinished && m_spawnTime + rg (5.0f, 7.5f) < game.time ()) {
|
||||||
if (rg.get (1, 100) < 2 && cv_spraypaints.bool_ ()) {
|
if (rg (1, 100) < 2 && cv_spraypaints) {
|
||||||
startTask (Task::Spraypaint, TaskPri::Spraypaint, kInvalidNodeIndex, game.time () + 1.0f, false);
|
startTask (Task::Spraypaint, TaskPri::Spraypaint, kInvalidNodeIndex, game.time () + 1.0f, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3043,13 +3039,13 @@ void Bot::checkSpawnConditions () {
|
||||||
}
|
}
|
||||||
m_checkKnifeSwitch = false;
|
m_checkKnifeSwitch = false;
|
||||||
|
|
||||||
if (rg.chance (cv_user_follow_percent.int_ ()) && game.isNullEntity (m_targetEntity) && !m_isLeader && !m_hasC4 && rg.chance (50)) {
|
if (rg.chance (cv_user_follow_percent.as <int> ()) && game.isNullEntity (m_targetEntity) && !m_isLeader && !m_hasC4 && rg.chance (50)) {
|
||||||
decideFollowUser ();
|
decideFollowUser ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we already switched weapon mode
|
// check if we already switched weapon mode
|
||||||
if (m_checkWeaponSwitch && m_buyingFinished && m_spawnTime + rg.get (3.0f, 4.5f) < game.time ()) {
|
if (m_checkWeaponSwitch && m_buyingFinished && m_spawnTime + rg (3.0f, 4.5f) < game.time ()) {
|
||||||
if (hasShield () && isShieldDrawn ()) {
|
if (hasShield () && isShieldDrawn ()) {
|
||||||
pev->button |= IN_ATTACK2;
|
pev->button |= IN_ATTACK2;
|
||||||
}
|
}
|
||||||
|
|
@ -3129,7 +3125,7 @@ void Bot::logic () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// some stuff required by by chatter engine
|
// some stuff required by by chatter engine
|
||||||
if (cv_radio_mode.int_ () == 2) {
|
if (cv_radio_mode.as <int> () == 2) {
|
||||||
if ((m_states & Sense::SeeingEnemy) && !game.isNullEntity (m_enemy)) {
|
if ((m_states & Sense::SeeingEnemy) && !game.isNullEntity (m_enemy)) {
|
||||||
int hasFriendNearby = numFriendsNear (pev->origin, 512.0f);
|
int hasFriendNearby = numFriendsNear (pev->origin, 512.0f);
|
||||||
|
|
||||||
|
|
@ -3171,7 +3167,7 @@ void Bot::logic () {
|
||||||
m_wantsToFire = false;
|
m_wantsToFire = false;
|
||||||
|
|
||||||
// avoid flyings grenades, if needed
|
// avoid flyings grenades, if needed
|
||||||
if (cv_avoid_grenades.bool_ () && !m_isCreature) {
|
if (cv_avoid_grenades && !m_isCreature) {
|
||||||
avoidGrenades ();
|
avoidGrenades ();
|
||||||
}
|
}
|
||||||
m_isUsingGrenade = false;
|
m_isUsingGrenade = false;
|
||||||
|
|
@ -3219,7 +3215,7 @@ void Bot::logic () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the darkness
|
// check the darkness
|
||||||
if (cv_check_darkness.bool_ ()) {
|
if (cv_check_darkness) {
|
||||||
checkDarkness ();
|
checkDarkness ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3237,7 +3233,7 @@ void Bot::logic () {
|
||||||
checkParachute ();
|
checkParachute ();
|
||||||
|
|
||||||
// display some debugging thingy to host entity
|
// display some debugging thingy to host entity
|
||||||
if (cv_debug.int_ () >= 1) {
|
if (cv_debug.as <int> () >= 1) {
|
||||||
showDebugOverlay ();
|
showDebugOverlay ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3266,7 +3262,7 @@ void Bot::showDebugOverlay () {
|
||||||
displayDebugOverlay = true;
|
displayDebugOverlay = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!displayDebugOverlay && cv_debug.int_ () >= 2) {
|
if (!displayDebugOverlay && cv_debug.as <int> () >= 2) {
|
||||||
Bot *nearest = nullptr;
|
Bot *nearest = nullptr;
|
||||||
|
|
||||||
if (util.findNearestPlayer (reinterpret_cast <void **> (&nearest), overlayEntity, 128.0f, false, true, true, true) && nearest == this) {
|
if (util.findNearestPlayer (reinterpret_cast <void **> (&nearest), overlayEntity, 128.0f, false, true, true, true) && nearest == this) {
|
||||||
|
|
@ -3405,7 +3401,7 @@ void Bot::showDebugOverlay () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::hasHostage () {
|
bool Bot::hasHostage () {
|
||||||
if (cv_ignore_objectives.bool_ () || game.mapIs (MapFlags::Demolition)) {
|
if (cv_ignore_objectives || game.mapIs (MapFlags::Demolition)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3433,10 +3429,10 @@ void Bot::takeDamage (edict_t *inflictor, int damage, int armor, int bits) {
|
||||||
updatePracticeValue (damage);
|
updatePracticeValue (damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (util.isPlayer (inflictor) || (cv_attack_monsters.bool_ () && util.isMonster (inflictor))) {
|
if (util.isPlayer (inflictor) || (cv_attack_monsters && util.isMonster (inflictor))) {
|
||||||
const auto inflictorTeam = game.getTeam (inflictor);
|
const auto inflictorTeam = game.getTeam (inflictor);
|
||||||
|
|
||||||
if (!util.isMonster (inflictor) && cv_tkpunish.bool_ () && inflictorTeam == m_team && !util.isFakeClient (inflictor)) {
|
if (!util.isMonster (inflictor) && cv_tkpunish && inflictorTeam == m_team && !util.isFakeClient (inflictor)) {
|
||||||
// alright, die you team killer!!!
|
// alright, die you team killer!!!
|
||||||
m_actualReactionTime = 0.0f;
|
m_actualReactionTime = 0.0f;
|
||||||
m_seeEnemyTime = game.time ();
|
m_seeEnemyTime = game.time ();
|
||||||
|
|
@ -3494,7 +3490,7 @@ void Bot::takeBlind (int alpha) {
|
||||||
// this function gets called by network message handler, when screenfade message get's send
|
// this function gets called by network message handler, when screenfade message get's send
|
||||||
// it's used to make bot blind from the grenade.
|
// it's used to make bot blind from the grenade.
|
||||||
|
|
||||||
m_viewDistance = rg.get (10.0f, 20.0f);
|
m_viewDistance = rg (10.0f, 20.0f);
|
||||||
|
|
||||||
// do not take in effect some unique map effects on round start
|
// do not take in effect some unique map effects on round start
|
||||||
if (bots.getRoundStartTime () + 5.0f < game.time ()) {
|
if (bots.getRoundStartTime () + 5.0f < game.time ()) {
|
||||||
|
|
@ -3606,7 +3602,7 @@ void Bot::updatePracticeDamage (edict_t *attacker, int damage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::pushChatMessage (int type, bool isTeamSay) {
|
void Bot::pushChatMessage (int type, bool isTeamSay) {
|
||||||
if (!conf.hasChatBank (type) || !cv_chat.bool_ ()) {
|
if (!conf.hasChatBank (type) || !cv_chat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3679,7 +3675,7 @@ void Bot::debugMsgInternal (StringRef str) {
|
||||||
if (game.isDedicated ()) {
|
if (game.isDedicated ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const int level = cv_debug.int_ ();
|
const int level = cv_debug.as <int> ();
|
||||||
|
|
||||||
if (level <= 2) {
|
if (level <= 2) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -3718,7 +3714,7 @@ Vector Bot::isBombAudible () {
|
||||||
}
|
}
|
||||||
const Vector &bombOrigin = graph.getBombOrigin ();
|
const Vector &bombOrigin = graph.getBombOrigin ();
|
||||||
|
|
||||||
const float timeElapsed = ((game.time () - bots.getTimeBombPlanted ()) / mp_c4timer.float_ ()) * 100.0f;
|
const float timeElapsed = ((game.time () - bots.getTimeBombPlanted ()) / mp_c4timer.as <float> ()) * 100.0f;
|
||||||
float desiredRadius = 768.0f;
|
float desiredRadius = 768.0f;
|
||||||
|
|
||||||
// start the manual calculations
|
// start the manual calculations
|
||||||
|
|
@ -3803,7 +3799,7 @@ float Bot::getBombTimeleft () const {
|
||||||
if (!bots.isBombPlanted ()) {
|
if (!bots.isBombPlanted ()) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
return cr::max (bots.getTimeBombPlanted () + mp_c4timer.float_ () - game.time (), 0.0f);
|
return cr::max (bots.getTimeBombPlanted () + mp_c4timer.as <float> () - game.time (), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::isOutOfBombTimer () {
|
bool Bot::isOutOfBombTimer () {
|
||||||
|
|
@ -3915,8 +3911,8 @@ void Bot::updateHearing () {
|
||||||
auto error = kSprayDistance * cr::powf (nearestDistanceSq, 0.5f) / 2048.0f;
|
auto error = kSprayDistance * cr::powf (nearestDistanceSq, 0.5f) / 2048.0f;
|
||||||
auto origin = hearedEnemy->v.origin;
|
auto origin = hearedEnemy->v.origin;
|
||||||
|
|
||||||
origin.x = origin.x + rg.get (-error, error);
|
origin.x = origin.x + rg (-error, error);
|
||||||
origin.y = origin.y + rg.get (-error, error);
|
origin.y = origin.y + rg (-error, error);
|
||||||
|
|
||||||
return origin;
|
return origin;
|
||||||
};
|
};
|
||||||
|
|
@ -3962,7 +3958,7 @@ void Bot::updateHearing () {
|
||||||
|
|
||||||
// check if heard enemy can be shoot through some obstacle
|
// check if heard enemy can be shoot through some obstacle
|
||||||
else {
|
else {
|
||||||
if (cv_shoots_thru_walls.bool_ ()
|
if (cv_shoots_thru_walls
|
||||||
&& m_lastEnemy == hearedEnemy
|
&& m_lastEnemy == hearedEnemy
|
||||||
&& rg.chance (conf.getDifficultyTweaks (m_difficulty)->hearThruPct)
|
&& rg.chance (conf.getDifficultyTweaks (m_difficulty)->hearThruPct)
|
||||||
&& m_seeEnemyTime + 3.0f > game.time ()
|
&& m_seeEnemyTime + 3.0f > game.time ()
|
||||||
|
|
@ -3992,7 +3988,7 @@ void Bot::enteredBuyZone (int buyState) {
|
||||||
if (m_seeEnemyTime + 12.0f < game.time ()
|
if (m_seeEnemyTime + 12.0f < game.time ()
|
||||||
&& m_lastEquipTime + 15.0f < game.time ()
|
&& m_lastEquipTime + 15.0f < game.time ()
|
||||||
&& m_inBuyZone
|
&& m_inBuyZone
|
||||||
&& (bots.getRoundStartTime () + rg.get (10.0f, 20.0f) + mp_buytime.float_ () < game.time ())
|
&& (bots.getRoundStartTime () + rg (10.0f, 20.0f) + mp_buytime.as <float> () < game.time ())
|
||||||
&& !bots.isBombPlanted ()
|
&& !bots.isBombPlanted ()
|
||||||
&& m_moneyAmount > econLimit[EcoLimit::PrimaryGreater]) {
|
&& m_moneyAmount > econLimit[EcoLimit::PrimaryGreater]) {
|
||||||
|
|
||||||
|
|
@ -4085,7 +4081,8 @@ float Bot::getShiftSpeed () {
|
||||||
|| isInWater ()
|
|| isInWater ()
|
||||||
|| isKnifeMode ()
|
|| isKnifeMode ()
|
||||||
|| m_isStuck
|
|| m_isStuck
|
||||||
|| m_numEnemiesLeft <= 0) {
|
|| m_numEnemiesLeft <= 0
|
||||||
|
|| !m_lostReachableNodeTimer.elapsed ()) {
|
||||||
|
|
||||||
return pev->maxspeed;
|
return pev->maxspeed;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,14 @@ void BotChatManager::humanizePlayerName (String &playerName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sometimes switch name to lower characters, only valid for the english languge
|
// sometimes switch name to lower characters, only valid for the english languge
|
||||||
if (rg.chance (8) && cv_language.str () == "en") {
|
if (rg.chance (8) && cv_language.as <StringRef> () == "en") {
|
||||||
playerName.lowercase ();
|
playerName.lowercase ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotChatManager::addChatErrors (String &line) {
|
void BotChatManager::addChatErrors (String &line) {
|
||||||
// sometimes switch name to lower characters, only valid for the english languge
|
// sometimes switch name to lower characters, only valid for the english languge
|
||||||
if (rg.chance (8) && cv_language.str () == "en") {
|
if (rg.chance (8) && cv_language.as <StringRef> () == "en") {
|
||||||
line.lowercase ();
|
line.lowercase ();
|
||||||
}
|
}
|
||||||
const auto length = static_cast <int32_t> (line.length ());
|
const auto length = static_cast <int32_t> (line.length ());
|
||||||
|
|
@ -72,12 +72,13 @@ void BotChatManager::addChatErrors (String &line) {
|
||||||
|
|
||||||
// "length / 2" percent of time drop a character
|
// "length / 2" percent of time drop a character
|
||||||
if (rg.chance (percentile)) {
|
if (rg.chance (percentile)) {
|
||||||
line.erase (static_cast <size_t> (rg.get (length / 8, length - length / 8), 1));
|
auto pos = rg (length / 8, length - length / 8);
|
||||||
|
line.erase (static_cast <size_t> (pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
// "length" / 4 precent of time swap character
|
// "length" / 4 precent of time swap character
|
||||||
if (rg.chance (percentile / 2)) {
|
if (rg.chance (percentile / 2)) {
|
||||||
size_t pos = static_cast <size_t> (rg.get (length / 8, 3 * length / 8)); // choose random position in string
|
auto pos = static_cast <size_t> (rg (length / 8, 3 * length / 8)); // choose random position in string
|
||||||
cr::swap (line[pos], line[pos + 1]);
|
cr::swap (line[pos], line[pos + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +87,7 @@ void BotChatManager::addChatErrors (String &line) {
|
||||||
bool BotChatManager::checkKeywords (StringRef line, String &reply) {
|
bool BotChatManager::checkKeywords (StringRef line, String &reply) {
|
||||||
// this function checks is string contain keyword, and generates reply to it
|
// this function checks is string contain keyword, and generates reply to it
|
||||||
|
|
||||||
if (!cv_chat.bool_ () || line.empty ()) {
|
if (!cv_chat || line.empty ()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,7 +136,7 @@ bool BotChatManager::checkKeywords (StringRef line, String &reply) {
|
||||||
void Bot::prepareChatMessage (StringRef message) {
|
void Bot::prepareChatMessage (StringRef message) {
|
||||||
// this function parses messages from the botchat, replaces keywords and converts names into a more human style
|
// this function parses messages from the botchat, replaces keywords and converts names into a more human style
|
||||||
|
|
||||||
if (!cv_chat.bool_ () || message.empty ()) {
|
if (!cv_chat || message.empty ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_chatBuffer = message;
|
m_chatBuffer = message;
|
||||||
|
|
@ -306,10 +307,10 @@ bool Bot::isReplyingToChat () {
|
||||||
|
|
||||||
if (m_sayTextBuffer.entityIndex != -1 && !m_sayTextBuffer.sayText.empty ()) {
|
if (m_sayTextBuffer.entityIndex != -1 && !m_sayTextBuffer.sayText.empty ()) {
|
||||||
// check is time to chat is good
|
// check is time to chat is good
|
||||||
if (m_sayTextBuffer.timeNextChat < game.time () + rg.get (m_sayTextBuffer.chatDelay / 2, m_sayTextBuffer.chatDelay)) {
|
if (m_sayTextBuffer.timeNextChat < game.time () + rg (m_sayTextBuffer.chatDelay / 2, m_sayTextBuffer.chatDelay)) {
|
||||||
String replyText;
|
String replyText;
|
||||||
|
|
||||||
if (rg.chance (m_sayTextBuffer.chatProbability + rg.get (40, 70)) && checkChatKeywords (replyText)) {
|
if (rg.chance (m_sayTextBuffer.chatProbability + rg (40, 70)) && checkChatKeywords (replyText)) {
|
||||||
prepareChatMessage (replyText);
|
prepareChatMessage (replyText);
|
||||||
pushMsgQueue (BotMsg::Say);
|
pushMsgQueue (BotMsg::Say);
|
||||||
|
|
||||||
|
|
@ -329,14 +330,14 @@ bool Bot::isReplyingToChat () {
|
||||||
void Bot::checkForChat () {
|
void Bot::checkForChat () {
|
||||||
// say a text every now and then
|
// say a text every now and then
|
||||||
|
|
||||||
if (m_isAlive || !cv_chat.bool_ () || game.is (GameFlags::CSDM)) {
|
if (m_isAlive || !cv_chat || game.is (GameFlags::CSDM)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bot chatting turned on?
|
// bot chatting turned on?
|
||||||
if (rg.chance (cv_chat_percent.int_ ())
|
if (rg.chance (cv_chat_percent.as <int> ())
|
||||||
&& m_lastChatTime + rg.get (6.0f, 10.0f) < game.time ()
|
&& m_lastChatTime + rg (6.0f, 10.0f) < game.time ()
|
||||||
&& bots.getLastChatTimestamp () + rg.get (2.5f, 5.0f) < game.time ()
|
&& bots.getLastChatTimestamp () + rg (2.5f, 5.0f) < game.time ()
|
||||||
&& !isReplyingToChat ()) {
|
&& !isReplyingToChat ()) {
|
||||||
|
|
||||||
if (conf.hasChatBank (Chat::Dead)) {
|
if (conf.hasChatBank (Chat::Dead)) {
|
||||||
|
|
@ -364,7 +365,7 @@ void Bot::checkForChat () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the used line buffer every now and then
|
// clear the used line buffer every now and then
|
||||||
if (static_cast <int> (m_sayTextBuffer.lastUsedSentences.length ()) > rg.get (4, 6)) {
|
if (static_cast <int> (m_sayTextBuffer.lastUsedSentences.length ()) > rg (4, 6)) {
|
||||||
m_sayTextBuffer.lastUsedSentences.clear ();
|
m_sayTextBuffer.lastUsedSentences.clear ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -373,7 +374,7 @@ void Bot::checkForChat () {
|
||||||
void Bot::sendToChat (StringRef message, bool teamOnly) {
|
void Bot::sendToChat (StringRef message, bool teamOnly) {
|
||||||
// this function prints saytext message to all players
|
// this function prints saytext message to all players
|
||||||
|
|
||||||
if (message.empty () || !cv_chat.bool_ ()) {
|
if (message.empty () || !cv_chat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
issueCommand ("%s \"%s\"", teamOnly ? "say_team" : "say", message);
|
issueCommand ("%s \"%s\"", teamOnly ? "say_team" : "say", message);
|
||||||
|
|
|
||||||
112
src/combat.cpp
112
src/combat.cpp
|
|
@ -58,7 +58,7 @@ int Bot::numEnemiesNear (const Vector &origin, const float radius) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::isEnemyHidden (edict_t *enemy) {
|
bool Bot::isEnemyHidden (edict_t *enemy) {
|
||||||
if (!cv_check_enemy_rendering.bool_ () || game.isNullEntity (enemy)) {
|
if (!cv_check_enemy_rendering || game.isNullEntity (enemy)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto &v = enemy->v;
|
const auto &v = enemy->v;
|
||||||
|
|
@ -100,7 +100,7 @@ bool Bot::isEnemyHidden (edict_t *enemy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::isEnemyInvincible (edict_t *enemy) {
|
bool Bot::isEnemyInvincible (edict_t *enemy) {
|
||||||
if (!cv_check_enemy_invincibility.bool_ () || game.isNullEntity (enemy)) {
|
if (!cv_check_enemy_invincibility || game.isNullEntity (enemy)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto &v = enemy->v;
|
const auto &v = enemy->v;
|
||||||
|
|
@ -217,7 +217,7 @@ bool Bot::checkBodyParts (edict_t *target) {
|
||||||
|
|
||||||
bool Bot::seesEnemy (edict_t *player) {
|
bool Bot::seesEnemy (edict_t *player) {
|
||||||
auto isBehindSmokeClouds = [&] (const Vector &pos) {
|
auto isBehindSmokeClouds = [&] (const Vector &pos) {
|
||||||
if (cv_smoke_grenade_checks.int_ () == 2) {
|
if (cv_smoke_grenade_checks.as <int> () == 2) {
|
||||||
return bots.isLineBlockedBySmoke (getEyesPos (), pos);
|
return bots.isLineBlockedBySmoke (getEyesPos (), pos);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -228,7 +228,7 @@ bool Bot::seesEnemy (edict_t *player) {
|
||||||
}
|
}
|
||||||
bool ignoreFieldOfView = false;
|
bool ignoreFieldOfView = false;
|
||||||
|
|
||||||
if (cv_whose_your_daddy.bool_ () && util.isPlayer (pev->dmg_inflictor) && game.getTeam (pev->dmg_inflictor) != m_team) {
|
if (cv_whose_your_daddy && util.isPlayer (pev->dmg_inflictor) && game.getTeam (pev->dmg_inflictor) != m_team) {
|
||||||
ignoreFieldOfView = true;
|
ignoreFieldOfView = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,7 +257,7 @@ bool Bot::lookupEnemies () {
|
||||||
// this function tries to find the best suitable enemy for the bot
|
// this function tries to find the best suitable enemy for the bot
|
||||||
|
|
||||||
// do not search for enemies while we're blinded, or shooting disabled by user
|
// do not search for enemies while we're blinded, or shooting disabled by user
|
||||||
if (m_enemyIgnoreTimer > game.time () || m_blindTime > game.time () || cv_ignore_enemies.bool_ ()) {
|
if (m_enemyIgnoreTimer > game.time () || m_blindTime > game.time () || cv_ignore_enemies) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
edict_t *player, *newEnemy = nullptr;
|
edict_t *player, *newEnemy = nullptr;
|
||||||
|
|
@ -270,10 +270,12 @@ bool Bot::lookupEnemies () {
|
||||||
else if (game.isNullEntity (m_enemy) && m_seeEnemyTime + 4.0f > game.time () && util.isAlive (m_lastEnemy)) {
|
else if (game.isNullEntity (m_enemy) && m_seeEnemyTime + 4.0f > game.time () && util.isAlive (m_lastEnemy)) {
|
||||||
m_states |= Sense::SuspectEnemy;
|
m_states |= Sense::SuspectEnemy;
|
||||||
|
|
||||||
// check if last enemy can be penetrated
|
const bool denyLastEnemy = pev->velocity.lengthSq2d () > 0.0f
|
||||||
const auto penetratePower = conf.findWeaponById (m_currentWeapon).penetratePower * 4;
|
&& pev->origin.distanceSq2d (m_lastEnemyOrigin) < cr::sqrf (256.0f)
|
||||||
|
&& m_shootTime + 1.5f > game.time ();
|
||||||
|
|
||||||
if (isPenetrableObstacle1 (m_lastEnemyOrigin, penetratePower)) {
|
if (!(m_aimFlags & (AimFlags::Enemy | AimFlags::PredictPath | AimFlags::Danger))
|
||||||
|
&& !denyLastEnemy && seesEntity (m_lastEnemyOrigin, true)) {
|
||||||
m_aimFlags |= AimFlags::LastEnemy;
|
m_aimFlags |= AimFlags::LastEnemy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -298,14 +300,14 @@ bool Bot::lookupEnemies () {
|
||||||
auto set = nullptr;
|
auto set = nullptr;
|
||||||
|
|
||||||
// setup potential visibility set from engine
|
// setup potential visibility set from engine
|
||||||
if (cv_use_engine_pvs_check.bool_ ()) {
|
if (cv_use_engine_pvs_check) {
|
||||||
game.getVisibilitySet (this, true);
|
game.getVisibilitySet (this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore shielded enemies, while we have real one
|
// ignore shielded enemies, while we have real one
|
||||||
edict_t *shieldEnemy = nullptr;
|
edict_t *shieldEnemy = nullptr;
|
||||||
|
|
||||||
if (cv_attack_monsters.bool_ ()) {
|
if (cv_attack_monsters) {
|
||||||
// search the world for monsters...
|
// search the world for monsters...
|
||||||
for (const auto &interesting : bots.getInterestingEntities ()) {
|
for (const auto &interesting : bots.getInterestingEntities ()) {
|
||||||
if (!util.isMonster (interesting)) {
|
if (!util.isMonster (interesting)) {
|
||||||
|
|
@ -313,7 +315,7 @@ bool Bot::lookupEnemies () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the engine PVS
|
// check the engine PVS
|
||||||
if (cv_use_engine_pvs_check.bool_ () && !game.checkVisibility (interesting, set)) {
|
if (cv_use_engine_pvs_check && !game.checkVisibility (interesting, set)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,12 +345,12 @@ bool Bot::lookupEnemies () {
|
||||||
player = client.ent;
|
player = client.ent;
|
||||||
|
|
||||||
// check the engine PVS
|
// check the engine PVS
|
||||||
if (cv_use_engine_pvs_check.bool_ () && !game.checkVisibility (player, set)) {
|
if (cv_use_engine_pvs_check && !game.checkVisibility (player, set)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// extra skill player can see through smoke... if being attacked
|
// extra skill player can see through smoke... if being attacked
|
||||||
if (cv_whose_your_daddy.bool_ () && (player->v.button & (IN_ATTACK | IN_ATTACK2)) && m_viewDistance < m_maxViewDistance) {
|
if (cv_whose_your_daddy && (player->v.button & (IN_ATTACK | IN_ATTACK2)) && m_viewDistance < m_maxViewDistance) {
|
||||||
nearestDistanceSq = cr::sqrf (m_maxViewDistance);
|
nearestDistanceSq = cr::sqrf (m_maxViewDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,7 +380,7 @@ bool Bot::lookupEnemies () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newEnemy != nullptr && (util.isPlayer (newEnemy) || (cv_attack_monsters.bool_ () && util.isMonster (newEnemy)))) {
|
if (newEnemy != nullptr && (util.isPlayer (newEnemy) || (cv_attack_monsters && util.isMonster (newEnemy)))) {
|
||||||
bots.setCanPause (true);
|
bots.setCanPause (true);
|
||||||
|
|
||||||
m_aimFlags |= AimFlags::Enemy;
|
m_aimFlags |= AimFlags::Enemy;
|
||||||
|
|
@ -401,7 +403,7 @@ bool Bot::lookupEnemies () {
|
||||||
}
|
}
|
||||||
m_targetEntity = nullptr; // stop following when we see an enemy...
|
m_targetEntity = nullptr; // stop following when we see an enemy...
|
||||||
|
|
||||||
if (cv_whose_your_daddy.bool_ ()) {
|
if (cv_whose_your_daddy) {
|
||||||
m_enemySurpriseTime = m_actualReactionTime * 0.5f;
|
m_enemySurpriseTime = m_actualReactionTime * 0.5f;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -475,7 +477,7 @@ bool Bot::lookupEnemies () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no enemy visible check if last one shoot able through wall
|
// if no enemy visible check if last one shoot able through wall
|
||||||
if (cv_shoots_thru_walls.bool_ ()
|
if (cv_shoots_thru_walls
|
||||||
&& rg.chance (conf.getDifficultyTweaks (m_difficulty)->seenThruPct)
|
&& rg.chance (conf.getDifficultyTweaks (m_difficulty)->seenThruPct)
|
||||||
&& isPenetrableObstacle (newEnemy->v.origin)) {
|
&& isPenetrableObstacle (newEnemy->v.origin)) {
|
||||||
|
|
||||||
|
|
@ -528,12 +530,12 @@ Vector Bot::getBodyOffsetError (float distance) {
|
||||||
const float hitError = distance / (cr::clamp (static_cast <float> (m_difficulty), 1.0f, 4.0f) * 1280.0f);
|
const float hitError = distance / (cr::clamp (static_cast <float> (m_difficulty), 1.0f, 4.0f) * 1280.0f);
|
||||||
const auto &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins;
|
const auto &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins;
|
||||||
|
|
||||||
m_aimLastError = Vector (rg.get (mins.x * hitError, maxs.x * hitError), rg.get (mins.y * hitError, maxs.y * hitError), rg.get (mins.z * hitError * 0.5f, maxs.z * hitError * 0.5f));
|
m_aimLastError = Vector (rg (mins.x * hitError, maxs.x * hitError), rg (mins.y * hitError, maxs.y * hitError), rg (mins.z * hitError * 0.5f, maxs.z * hitError * 0.5f));
|
||||||
|
|
||||||
const auto &aimError = conf.getDifficultyTweaks (m_difficulty) ->aimError;
|
const auto &aimError = conf.getDifficultyTweaks (m_difficulty) ->aimError;
|
||||||
m_aimLastError += Vector (rg.get (-aimError.x, aimError.x), rg.get (-aimError.y, aimError.y), rg.get (-aimError.z, aimError.z));
|
m_aimLastError += Vector (rg (-aimError.x, aimError.x), rg (-aimError.y, aimError.y), rg (-aimError.z, aimError.z));
|
||||||
|
|
||||||
m_aimErrorTime = game.time () + rg.get (0.4f, 0.8f);
|
m_aimErrorTime = game.time () + rg (0.4f, 0.8f);
|
||||||
}
|
}
|
||||||
return m_aimLastError;
|
return m_aimLastError;
|
||||||
}
|
}
|
||||||
|
|
@ -582,6 +584,9 @@ Vector Bot::getEnemyBodyOffset () {
|
||||||
if (distance > kSprayDistance && (isRecoilHigh () || usesShotgun ())) {
|
if (distance > kSprayDistance && (isRecoilHigh () || usesShotgun ())) {
|
||||||
headshotPct = 0;
|
headshotPct = 0;
|
||||||
}
|
}
|
||||||
|
else if (distance <= kSprayDistance && isRecoilHigh ()) {
|
||||||
|
headshotPct = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// now check is our skill match to aim at head, else aim at enemy body
|
// now check is our skill match to aim at head, else aim at enemy body
|
||||||
if (m_enemyBodyPartSet == m_enemy || rg.chance (headshotPct)) {
|
if (m_enemyBodyPartSet == m_enemy || rg.chance (headshotPct)) {
|
||||||
|
|
@ -665,7 +670,7 @@ Vector Bot::getCustomHeight (float distance) {
|
||||||
|
|
||||||
bool Bot::isFriendInLineOfFire (float distance) {
|
bool Bot::isFriendInLineOfFire (float distance) {
|
||||||
// bot can't hurt teammates, if friendly fire is not enabled...
|
// bot can't hurt teammates, if friendly fire is not enabled...
|
||||||
if (!mp_friendlyfire.bool_ () || game.is (GameFlags::CSDM)) {
|
if (!mp_friendlyfire || game.is (GameFlags::CSDM)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -710,7 +715,7 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
|
||||||
if (penetratePower == 0) {
|
if (penetratePower == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto method = cv_shoots_thru_walls.int_ ();
|
const auto method = cv_shoots_thru_walls.as <int> ();
|
||||||
|
|
||||||
// switch methods
|
// switch methods
|
||||||
switch (method) {
|
switch (method) {
|
||||||
|
|
@ -858,13 +863,13 @@ bool Bot::needToPauseFiring (float distance) {
|
||||||
const float yPunch = cr::sqrf (cr::deg2rad (pev->punchangle.y));
|
const float yPunch = cr::sqrf (cr::deg2rad (pev->punchangle.y));
|
||||||
|
|
||||||
const float tolerance = (100.0f - static_cast <float> (m_difficulty) * 25.0f) / 99.0f;
|
const float tolerance = (100.0f - static_cast <float> (m_difficulty) * 25.0f) / 99.0f;
|
||||||
const float baseTime = distance > kSprayDistance ? 0.65f : 0.48f;
|
const float baseTime = distance > kSprayDistance ? 0.55f : 0.38f;
|
||||||
const float maxRecoil = static_cast <float> (conf.getDifficultyTweaks (m_difficulty)->maxRecoil);
|
const float maxRecoil = static_cast <float> (conf.getDifficultyTweaks (m_difficulty)->maxRecoil);
|
||||||
|
|
||||||
// check if we need to compensate recoil
|
// check if we need to compensate recoil
|
||||||
if (cr::tanf (cr::sqrtf (cr::abs (xPunch) + cr::abs (yPunch))) * distance > offset + maxRecoil + tolerance) {
|
if (cr::tanf (cr::sqrtf (cr::abs (xPunch) + cr::abs (yPunch))) * distance > offset + maxRecoil + tolerance) {
|
||||||
if (m_firePause < game.time ()) {
|
if (m_firePause < game.time ()) {
|
||||||
m_firePause = game.time () + rg.get (baseTime, baseTime + maxRecoil * 0.01f * tolerance) - m_frameInterval;
|
m_firePause = game.time () + rg (baseTime, baseTime + maxRecoil * 0.01f * tolerance) - m_frameInterval;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1024,7 +1029,7 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
|
||||||
|
|
||||||
const int offset = cr::abs <int> (m_difficulty * 25 / 20 - 5);
|
const int offset = cr::abs <int> (m_difficulty * 25 / 20 - 5);
|
||||||
|
|
||||||
m_shootTime = game.time () + 0.1f + rg.get (kMinFireDelay[offset], kMaxFireDelay[offset]);
|
m_shootTime = game.time () + 0.1f + rg (kMinFireDelay[offset], kMaxFireDelay[offset]);
|
||||||
m_zoomCheckTime = game.time ();
|
m_zoomCheckTime = game.time ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1059,7 +1064,7 @@ void Bot::fireWeapons () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// use knife if near and good difficulty (l33t dude!)
|
// use knife if near and good difficulty (l33t dude!)
|
||||||
if (cv_stab_close_enemies.bool_ () && m_difficulty >= Difficulty::Normal
|
if (cv_stab_close_enemies && m_difficulty >= Difficulty::Normal
|
||||||
&& m_healthValue > 80.0f
|
&& m_healthValue > 80.0f
|
||||||
&& !game.isNullEntity (m_enemy)
|
&& !game.isNullEntity (m_enemy)
|
||||||
&& m_healthValue >= m_enemy->v.health
|
&& m_healthValue >= m_enemy->v.health
|
||||||
|
|
@ -1255,13 +1260,14 @@ void Bot::attackMovement () {
|
||||||
m_moveSpeed = pev->maxspeed;
|
m_moveSpeed = pev->maxspeed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const bool isFullView = !!(m_enemyParts & (Visibility::Head | Visibility::Body));
|
||||||
|
|
||||||
if (m_lastFightStyleCheck + 3.0f < game.time ()) {
|
if (m_lastFightStyleCheck + 3.0f < game.time ()) {
|
||||||
if (usesSniper ()) {
|
if (usesSniper ()) {
|
||||||
m_fightStyle = Fight::Stay;
|
m_fightStyle = Fight::Stay;
|
||||||
}
|
}
|
||||||
else if (usesRifle () || usesSubmachine () || usesHeavy ()) {
|
else if (usesRifle () || usesSubmachine () || usesHeavy ()) {
|
||||||
const int rand = rg.get (1, 100);
|
const int rand = rg (1, 100);
|
||||||
|
|
||||||
if (distance < 768.0f) {
|
if (distance < 768.0f) {
|
||||||
m_fightStyle = Fight::Strafe;
|
m_fightStyle = Fight::Strafe;
|
||||||
|
|
@ -1297,7 +1303,7 @@ void Bot::attackMovement () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not try to strafe while ducking
|
// do not try to strafe while ducking
|
||||||
if (isDucking () || isInNarrowPlace ()) {
|
if (isDucking () || isInNarrowPlace () || !isFullView) {
|
||||||
m_fightStyle = Fight::Stay;
|
m_fightStyle = Fight::Stay;
|
||||||
}
|
}
|
||||||
const auto pistolStrafeDistance = game.is (GameFlags::CSDM) ? kSprayDistanceX2 * 3.0f : kSprayDistanceX2;
|
const auto pistolStrafeDistance = game.is (GameFlags::CSDM) ? kSprayDistanceX2 * 3.0f : kSprayDistanceX2;
|
||||||
|
|
@ -1320,12 +1326,12 @@ void Bot::attackMovement () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_fightStyle == Fight::Strafe) {
|
if (m_fightStyle == Fight::Strafe) {
|
||||||
auto swapStrafeCombatDir = [&] () {
|
auto swapDodgeDirection = [&] () {
|
||||||
m_combatStrafeDir = (m_combatStrafeDir == Dodge::Left ? Dodge::Right : Dodge::Left);
|
m_dodgeStrafeDir = (m_dodgeStrafeDir == Dodge::Left ? Dodge::Right : Dodge::Left);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto strafeUpdateTime = [] () {
|
auto strafeUpdateTime = [] () {
|
||||||
return game.time () + rg.get (0.3f, 1.0f);
|
return game.time () + rg (0.3f, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
// to start strafing, we have to first figure out if the target is on the left side or right side
|
// to start strafing, we have to first figure out if the target is on the left side or right side
|
||||||
|
|
@ -1334,14 +1340,14 @@ void Bot::attackMovement () {
|
||||||
const auto &rightSide = m_enemy->v.v_angle.right ().normalize2d_apx ();
|
const auto &rightSide = m_enemy->v.v_angle.right ().normalize2d_apx ();
|
||||||
|
|
||||||
if ((dirToPoint | rightSide) < 0.0f) {
|
if ((dirToPoint | rightSide) < 0.0f) {
|
||||||
m_combatStrafeDir = Dodge::Right;
|
m_dodgeStrafeDir = Dodge::Right;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_combatStrafeDir = Dodge::Left;
|
m_dodgeStrafeDir = Dodge::Left;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rg.chance (30)) {
|
if (rg.chance (30)) {
|
||||||
swapStrafeCombatDir ();
|
swapDodgeDirection ();
|
||||||
}
|
}
|
||||||
m_strafeSetTime = strafeUpdateTime ();
|
m_strafeSetTime = strafeUpdateTime ();
|
||||||
}
|
}
|
||||||
|
|
@ -1349,12 +1355,12 @@ void Bot::attackMovement () {
|
||||||
const bool wallOnRight = checkWallOnRight ();
|
const bool wallOnRight = checkWallOnRight ();
|
||||||
const bool wallOnLeft = checkWallOnLeft ();
|
const bool wallOnLeft = checkWallOnLeft ();
|
||||||
|
|
||||||
if (m_combatStrafeDir == Dodge::Left) {
|
if (m_dodgeStrafeDir == Dodge::Left) {
|
||||||
if (!wallOnLeft) {
|
if (!wallOnLeft) {
|
||||||
m_strafeSpeed = -pev->maxspeed;
|
m_strafeSpeed = -pev->maxspeed;
|
||||||
}
|
}
|
||||||
else if (!wallOnRight) {
|
else if (!wallOnRight) {
|
||||||
swapStrafeCombatDir ();
|
swapDodgeDirection ();
|
||||||
|
|
||||||
m_strafeSetTime = strafeUpdateTime ();
|
m_strafeSetTime = strafeUpdateTime ();
|
||||||
m_strafeSpeed = pev->maxspeed;
|
m_strafeSpeed = pev->maxspeed;
|
||||||
|
|
@ -1369,7 +1375,7 @@ void Bot::attackMovement () {
|
||||||
m_strafeSpeed = pev->maxspeed;
|
m_strafeSpeed = pev->maxspeed;
|
||||||
}
|
}
|
||||||
else if (!wallOnLeft) {
|
else if (!wallOnLeft) {
|
||||||
swapStrafeCombatDir ();
|
swapDodgeDirection ();
|
||||||
|
|
||||||
m_strafeSetTime = strafeUpdateTime ();
|
m_strafeSetTime = strafeUpdateTime ();
|
||||||
m_strafeSpeed = -pev->maxspeed;
|
m_strafeSpeed = -pev->maxspeed;
|
||||||
|
|
@ -1388,7 +1394,7 @@ void Bot::attackMovement () {
|
||||||
if (m_difficulty >= Difficulty::Normal
|
if (m_difficulty >= Difficulty::Normal
|
||||||
&& (m_jumpTime + 5.0f < game.time ()
|
&& (m_jumpTime + 5.0f < game.time ()
|
||||||
&& isOnFloor ()
|
&& isOnFloor ()
|
||||||
&& rg.get (0, 1000) < (m_isReloading ? 8 : 2)
|
&& rg (0, 1000) < (m_isReloading ? 8 : 2)
|
||||||
&& pev->velocity.length2d () > 150.0f) && !usesSniper ()) {
|
&& pev->velocity.length2d () > 150.0f) && !usesSniper ()) {
|
||||||
|
|
||||||
pev->button |= IN_JUMP;
|
pev->button |= IN_JUMP;
|
||||||
|
|
@ -1401,7 +1407,7 @@ void Bot::attackMovement () {
|
||||||
m_duckTime = game.time () + m_frameInterval * 3.0f;
|
m_duckTime = game.time () + m_frameInterval * 3.0f;
|
||||||
}
|
}
|
||||||
else if ((distance > kSprayDistanceX2 && hasPrimaryWeapon ())
|
else if ((distance > kSprayDistanceX2 && hasPrimaryWeapon ())
|
||||||
&& (m_enemyParts & (Visibility::Head | Visibility::Body))
|
&& isFullView
|
||||||
&& getCurrentTaskId () != Task::SeekCover
|
&& getCurrentTaskId () != Task::SeekCover
|
||||||
&& getCurrentTaskId () != Task::Hunt) {
|
&& getCurrentTaskId () != Task::Hunt) {
|
||||||
|
|
||||||
|
|
@ -1418,7 +1424,7 @@ void Bot::attackMovement () {
|
||||||
|
|
||||||
if (m_difficulty >= Difficulty::Normal && isOnFloor () && m_duckTime < game.time ()) {
|
if (m_difficulty >= Difficulty::Normal && isOnFloor () && m_duckTime < game.time ()) {
|
||||||
if (distance < kSprayDistanceX2) {
|
if (distance < kSprayDistanceX2) {
|
||||||
if (rg.get (0, 1000) < rg.get (5, 10) && pev->velocity.length2d () > 150.0f && isInViewCone (m_enemy->v.origin)) {
|
if (rg (0, 1000) < rg (5, 10) && pev->velocity.length2d () > 150.0f && isInViewCone (m_enemy->v.origin)) {
|
||||||
pev->button |= IN_JUMP;
|
pev->button |= IN_JUMP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1585,7 +1591,7 @@ bool Bot::hasAnyWeapons () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::isKnifeMode () {
|
bool Bot::isKnifeMode () {
|
||||||
return cv_jasonmode.bool_ () || (usesKnife () && !hasAnyWeapons ()) || m_isCreature;
|
return cv_jasonmode || (usesKnife () && !hasAnyWeapons ()) || m_isCreature;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::isGrenadeWar () {
|
bool Bot::isGrenadeWar () {
|
||||||
|
|
@ -1597,7 +1603,7 @@ bool Bot::isGrenadeWar () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we're forced to via cvar
|
// if we're forced to via cvar
|
||||||
if (cv_grenadier_mode.bool_ ()) {
|
if (cv_grenadier_mode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return game.mapIs (MapFlags::GrenadeWar); // in case map was flagged
|
return game.mapIs (MapFlags::GrenadeWar); // in case map was flagged
|
||||||
|
|
@ -1717,7 +1723,7 @@ void Bot::decideFollowUser () {
|
||||||
|
|
||||||
void Bot::updateTeamCommands () {
|
void Bot::updateTeamCommands () {
|
||||||
// prevent spamming
|
// prevent spamming
|
||||||
if (m_timeTeamOrder > game.time () + 2.0f || game.is (GameFlags::FreeForAll) || !cv_radio_mode.int_ ()) {
|
if (m_timeTeamOrder > game.time () + 2.0f || game.is (GameFlags::FreeForAll) || !cv_radio_mode.as <int> ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1739,20 +1745,20 @@ void Bot::updateTeamCommands () {
|
||||||
|
|
||||||
// has teammates?
|
// has teammates?
|
||||||
if (memberNear) {
|
if (memberNear) {
|
||||||
if (m_personality == Personality::Rusher && cv_radio_mode.int_ () == 2) {
|
if (m_personality == Personality::Rusher && cv_radio_mode.as <int> () == 2) {
|
||||||
pushRadioMessage (Radio::StormTheFront);
|
pushRadioMessage (Radio::StormTheFront);
|
||||||
}
|
}
|
||||||
else if (m_personality != Personality::Rusher && cv_radio_mode.int_ () == 2) {
|
else if (m_personality != Personality::Rusher && cv_radio_mode.as <int> () == 2) {
|
||||||
pushRadioMessage (Radio::TeamFallback);
|
pushRadioMessage (Radio::TeamFallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (memberExists && cv_radio_mode.int_ () == 1) {
|
else if (memberExists && cv_radio_mode.as <int> () == 1) {
|
||||||
pushRadioMessage (Radio::TakingFireNeedAssistance);
|
pushRadioMessage (Radio::TakingFireNeedAssistance);
|
||||||
}
|
}
|
||||||
else if (memberExists && cv_radio_mode.int_ () == 2) {
|
else if (memberExists && cv_radio_mode.as <int> () == 2) {
|
||||||
pushChatterMessage (Chatter::ScaredEmotion);
|
pushChatterMessage (Chatter::ScaredEmotion);
|
||||||
}
|
}
|
||||||
m_timeTeamOrder = game.time () + rg.get (15.0f, 30.0f);
|
m_timeTeamOrder = game.time () + rg (15.0f, 30.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::isGroupOfEnemies (const Vector &location, int numEnemies, float radius) {
|
bool Bot::isGroupOfEnemies (const Vector &location, int numEnemies, float radius) {
|
||||||
|
|
@ -1871,7 +1877,7 @@ Vector Bot::calcToss (const Vector &start, const Vector &stop) {
|
||||||
// returns null vector if toss is not feasible.
|
// returns null vector if toss is not feasible.
|
||||||
|
|
||||||
TraceResult tr {};
|
TraceResult tr {};
|
||||||
const float gravity = sv_gravity.float_ () * 0.55f;
|
const float gravity = sv_gravity.as <float> () * 0.55f;
|
||||||
|
|
||||||
// prevent div by zero in some strange situations
|
// prevent div by zero in some strange situations
|
||||||
if (cr::fzero (gravity)) {
|
if (cr::fzero (gravity)) {
|
||||||
|
|
@ -1931,7 +1937,7 @@ Vector Bot::calcThrow (const Vector &start, const Vector &stop) {
|
||||||
Vector velocity = stop - start;
|
Vector velocity = stop - start;
|
||||||
TraceResult tr {};
|
TraceResult tr {};
|
||||||
|
|
||||||
const float gravity = sv_gravity.float_ () * 0.55f;
|
const float gravity = sv_gravity.as <float> () * 0.55f;
|
||||||
|
|
||||||
// prevent div by zero in some strange situations
|
// prevent div by zero in some strange situations
|
||||||
if (cr::fzero (gravity)) {
|
if (cr::fzero (gravity)) {
|
||||||
|
|
@ -2010,7 +2016,7 @@ void Bot::checkGrenadesThrow () {
|
||||||
? m_lastEnemyOrigin.empty ()
|
? m_lastEnemyOrigin.empty ()
|
||||||
: (preventibleTasks
|
: (preventibleTasks
|
||||||
|| isInNarrowPlace ()
|
|| isInNarrowPlace ()
|
||||||
|| cv_ignore_enemies.bool_ ()
|
|| cv_ignore_enemies
|
||||||
|| m_isUsingGrenade
|
|| m_isUsingGrenade
|
||||||
|| m_isReloading
|
|| m_isReloading
|
||||||
|| (isKnifeMode () && !bots.isBombPlanted ())
|
|| (isKnifeMode () && !bots.isBombPlanted ())
|
||||||
|
|
@ -2094,7 +2100,7 @@ void Bot::checkGrenadesThrow () {
|
||||||
// care about different grenades
|
// care about different grenades
|
||||||
switch (grenadeToThrow) {
|
switch (grenadeToThrow) {
|
||||||
case Weapon::Explosive:
|
case Weapon::Explosive:
|
||||||
if (mp_friendlyfire.bool_ () && numFriendsNear (m_lastEnemy->v.origin, 256.0f) > 0) {
|
if (mp_friendlyfire && numFriendsNear (m_lastEnemy->v.origin, 256.0f) > 0) {
|
||||||
allowThrowing = false;
|
allowThrowing = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -2245,7 +2251,7 @@ bool Bot::isEnemyNoticeable (float range) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_enemyParts & Visibility::Other) {
|
if (m_enemyParts & Visibility::Other) {
|
||||||
coverRatio += rg.get (10.0f, 25.0f);
|
coverRatio += rg (10.0f, 25.0f);
|
||||||
}
|
}
|
||||||
constexpr float kCloseRange = 300.0f;
|
constexpr float kCloseRange = 300.0f;
|
||||||
constexpr float kFarRange = 1000.0f;
|
constexpr float kFarRange = 1000.0f;
|
||||||
|
|
@ -2311,7 +2317,7 @@ bool Bot::isEnemyNoticeable (float range) {
|
||||||
}
|
}
|
||||||
noticeChance = cr::max (0.1f, noticeChance * cr::abs (m_agressionLevel - m_fearLevel));
|
noticeChance = cr::max (0.1f, noticeChance * cr::abs (m_agressionLevel - m_fearLevel));
|
||||||
|
|
||||||
return rg.get (0.0f, 100.0f) < noticeChance;
|
return rg (0.0f, 100.0f) < noticeChance;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Bot::getAmmo () {
|
int Bot::getAmmo () {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ void BotConfig::loadMainConfig (bool isFirstLoad) {
|
||||||
auto keyval = line.split (" ");
|
auto keyval = line.split (" ");
|
||||||
|
|
||||||
if (keyval.length () > 1) {
|
if (keyval.length () > 1) {
|
||||||
auto ignore = String (cv_ignore_cvars_on_changelevel.str ()).split (",");
|
auto ignore = String (cv_ignore_cvars_on_changelevel.as <StringRef> ()).split (",");
|
||||||
|
|
||||||
auto key = keyval[0].trim ().chars ();
|
auto key = keyval[0].trim ().chars ();
|
||||||
auto cvar = engfuncs.pfnCVarGetPointer (key);
|
auto cvar = engfuncs.pfnCVarGetPointer (key);
|
||||||
|
|
@ -76,7 +76,7 @@ void BotConfig::loadMainConfig (bool isFirstLoad) {
|
||||||
if (needsToIgnoreVar (ignore, key) && !strings.matches (value, cvar->string)) {
|
if (needsToIgnoreVar (ignore, key) && !strings.matches (value, cvar->string)) {
|
||||||
|
|
||||||
// preserve quota number if it's zero
|
// preserve quota number if it's zero
|
||||||
if (cv_quota.name () == cvar->name && cv_quota.int_ () <= 0) {
|
if (cv_quota.name () == cvar->name && cv_quota.as <int> () <= 0) {
|
||||||
engfuncs.pfnCvar_DirectSet (cvar, value);
|
engfuncs.pfnCvar_DirectSet (cvar, value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -101,13 +101,13 @@ void BotConfig::loadMainConfig (bool isFirstLoad) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// android is a bit hard to play, lower the difficulty by default
|
// android is a bit hard to play, lower the difficulty by default
|
||||||
if (plat.android && cv_difficulty.int_ () > 3) {
|
if (plat.android && cv_difficulty.as <int> () > 3) {
|
||||||
cv_difficulty.set (3);
|
cv_difficulty.set (3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind the correct menu key for bot menu...
|
// bind the correct menu key for bot menu...
|
||||||
if (!game.isDedicated ()) {
|
if (!game.isDedicated ()) {
|
||||||
auto val = cv_bind_menu_key.str ();
|
auto val = cv_bind_menu_key.as <StringRef> ();
|
||||||
|
|
||||||
if (!val.empty ()) {
|
if (!val.empty ()) {
|
||||||
game.serverCommand ("bind \"%s\" \"yb menu\"", val);
|
game.serverCommand ("bind \"%s\" \"yb menu\"", val);
|
||||||
|
|
@ -115,7 +115,7 @@ void BotConfig::loadMainConfig (bool isFirstLoad) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable logger if requested
|
// disable logger if requested
|
||||||
logger.disableLogWrite (cv_logger_disable_logfile.bool_ ());
|
logger.disableLogWrite (cv_logger_disable_logfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotConfig::loadNamesConfig () {
|
void BotConfig::loadNamesConfig () {
|
||||||
|
|
@ -161,10 +161,10 @@ void BotConfig::loadWeaponsConfig () {
|
||||||
|
|
||||||
for (size_t i = 0; i < data.length (); ++i) {
|
for (size_t i = 0; i < data.length (); ++i) {
|
||||||
if (as) {
|
if (as) {
|
||||||
weapons[i].teamAS = data[i].int_ ();
|
weapons[i].teamAS = data[i].as <int> ();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
weapons[i].teamStandard = data[i].int_ ();
|
weapons[i].teamStandard = data[i].as <int> ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -176,7 +176,7 @@ void BotConfig::loadWeaponsConfig () {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < to.length (); ++i) {
|
for (size_t i = 0; i < to.length (); ++i) {
|
||||||
to[i] = data[i].int_ ();
|
to[i] = data[i].as <int> ();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
String line;
|
String line;
|
||||||
|
|
@ -235,7 +235,7 @@ void BotConfig::loadChatterConfig () {
|
||||||
MemFile file;
|
MemFile file;
|
||||||
|
|
||||||
// chatter initialization
|
// chatter initialization
|
||||||
if (game.is (GameFlags::HasBotVoice) && cv_radio_mode.int_ () == 2 && openConfig ("chatter", "Couldn't open chatter system configuration", &file)) {
|
if (game.is (GameFlags::HasBotVoice) && cv_radio_mode.as <int> () == 2 && openConfig ("chatter", "Couldn't open chatter system configuration", &file)) {
|
||||||
m_chatter.clear ();
|
m_chatter.clear ();
|
||||||
|
|
||||||
struct EventMap {
|
struct EventMap {
|
||||||
|
|
@ -521,7 +521,7 @@ void BotConfig::loadLanguageConfig () {
|
||||||
}
|
}
|
||||||
file.close ();
|
file.close ();
|
||||||
}
|
}
|
||||||
else if (cv_language.str () != "en") {
|
else if (cv_language.as <StringRef> () != "en") {
|
||||||
logger.error ("Couldn't load language configuration");
|
logger.error ("Couldn't load language configuration");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -592,15 +592,15 @@ void BotConfig::loadDifficultyConfig () {
|
||||||
}
|
}
|
||||||
auto diff = &m_difficulty[level];
|
auto diff = &m_difficulty[level];
|
||||||
|
|
||||||
diff->reaction[0] = values[0].float_ ();
|
diff->reaction[0] = values[0].as <float> ();
|
||||||
diff->reaction[1] = values[1].float_ ();
|
diff->reaction[1] = values[1].as <float> ();
|
||||||
diff->headshotPct = values[2].int_ ();
|
diff->headshotPct = values[2].as <int> ();
|
||||||
diff->seenThruPct = values[3].int_ ();
|
diff->seenThruPct = values[3].as <int> ();
|
||||||
diff->hearThruPct = values[4].int_ ();
|
diff->hearThruPct = values[4].as <int> ();
|
||||||
diff->maxRecoil = values[5].int_ ();
|
diff->maxRecoil = values[5].as <int> ();
|
||||||
diff->aimError.x = values[6].float_ ();
|
diff->aimError.x = values[6].as <float> ();
|
||||||
diff->aimError.y = values[7].float_ ();
|
diff->aimError.y = values[7].as <float> ();
|
||||||
diff->aimError.z = values[8].float_ ();
|
diff->aimError.z = values[8].as <float> ();
|
||||||
};
|
};
|
||||||
|
|
||||||
// difficulty initialization
|
// difficulty initialization
|
||||||
|
|
@ -882,10 +882,10 @@ bool BotConfig::openConfig (StringRef fileName, StringRef errorIfNotExists, MemF
|
||||||
auto configDir = strings.joinPath (bstor.getRunningPathVFS (), folders.config);
|
auto configDir = strings.joinPath (bstor.getRunningPathVFS (), folders.config);
|
||||||
|
|
||||||
if (languageDependant) {
|
if (languageDependant) {
|
||||||
if (fileName.startsWith ("lang") && cv_language.str () == "en") {
|
if (fileName.startsWith ("lang") && cv_language.as <StringRef> () == "en") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto langConfig = strings.joinPath (configDir, folders.lang, strings.format ("%s_%s.%s", cv_language.str (), fileName, kConfigExtension));
|
auto langConfig = strings.joinPath (configDir, folders.lang, strings.format ("%s_%s.%s", cv_language.as <StringRef> (), fileName, kConfigExtension));
|
||||||
|
|
||||||
// check is file is exists for this language
|
// check is file is exists for this language
|
||||||
if (!outFile->open (langConfig)) {
|
if (!outFile->open (langConfig)) {
|
||||||
|
|
|
||||||
157
src/control.cpp
157
src/control.cpp
|
|
@ -25,19 +25,19 @@ int BotControl::cmdAddBot () {
|
||||||
m_args.resize (max);
|
m_args.resize (max);
|
||||||
|
|
||||||
// if team is specified, modify args to set team
|
// if team is specified, modify args to set team
|
||||||
if (strValue (alias).endsWith ("_ct")) {
|
if (arg <StringRef> (alias).endsWith ("_ct")) {
|
||||||
m_args.set (team, "2");
|
m_args.set (team, "2");
|
||||||
}
|
}
|
||||||
else if (strValue (alias).endsWith ("_t")) {
|
else if (arg <StringRef> (alias).endsWith ("_t")) {
|
||||||
m_args.set (team, "1");
|
m_args.set (team, "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
// if high-skilled bot is requested set personality to rusher and max-out difficulty
|
// if high-skilled bot is requested set personality to rusher and max-out difficulty
|
||||||
if (strValue (alias).contains ("addhs")) {
|
if (arg <StringRef> (alias).contains ("addhs")) {
|
||||||
m_args.set (difficulty, "4");
|
m_args.set (difficulty, "4");
|
||||||
m_args.set (personality, "1");
|
m_args.set (personality, "1");
|
||||||
}
|
}
|
||||||
bots.addbot (strValue (name), strValue (difficulty), strValue (personality), strValue (team), strValue (model), true);
|
bots.addbot (arg <StringRef> (name), arg <StringRef> (difficulty), arg <StringRef> (personality), arg <StringRef> (team), arg <StringRef> (model), true);
|
||||||
|
|
||||||
return BotCommandResult::Handled;
|
return BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
@ -46,10 +46,10 @@ int BotControl::cmdKickBot () {
|
||||||
enum args { alias = 1, team };
|
enum args { alias = 1, team };
|
||||||
|
|
||||||
// if team is specified, kick from specified tram
|
// if team is specified, kick from specified tram
|
||||||
if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") {
|
if (arg <StringRef> (alias).endsWith ("_ct") || arg <int> (team) == 2 || arg <StringRef> (team) == "ct") {
|
||||||
bots.kickFromTeam (Team::CT);
|
bots.kickFromTeam (Team::CT);
|
||||||
}
|
}
|
||||||
else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") {
|
else if (arg <StringRef> (alias).endsWith ("_t") || arg <int> (team) == 1 || arg <StringRef> (team) == "t") {
|
||||||
bots.kickFromTeam (Team::Terrorist);
|
bots.kickFromTeam (Team::Terrorist);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -62,13 +62,13 @@ int BotControl::cmdKickBots () {
|
||||||
enum args { alias = 1, instant, team };
|
enum args { alias = 1, instant, team };
|
||||||
|
|
||||||
// check if we're need to remove bots instantly
|
// check if we're need to remove bots instantly
|
||||||
const auto kickInstant = strValue (instant) == "instant";
|
const auto kickInstant = arg <StringRef> (instant) == "instant";
|
||||||
|
|
||||||
// if team is specified, kick from specified tram
|
// if team is specified, kick from specified tram
|
||||||
if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") {
|
if (arg <StringRef> (alias).endsWith ("_ct") || arg <int> (team) == 2 || arg <StringRef> (team) == "ct") {
|
||||||
bots.kickFromTeam (Team::CT, true);
|
bots.kickFromTeam (Team::CT, true);
|
||||||
}
|
}
|
||||||
else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") {
|
else if (arg <StringRef> (alias).endsWith ("_t") || arg <int> (team) == 1 || arg <StringRef> (team) == "t") {
|
||||||
bots.kickFromTeam (Team::Terrorist, true);
|
bots.kickFromTeam (Team::Terrorist, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -81,13 +81,13 @@ int BotControl::cmdKillBots () {
|
||||||
enum args { alias = 1, team, silent, max };
|
enum args { alias = 1, team, silent, max };
|
||||||
|
|
||||||
// do not issue any messages
|
// do not issue any messages
|
||||||
bool silentKill = hasArg (silent) && strValue (silent).startsWith ("si");
|
bool silentKill = hasArg (silent) && arg <StringRef> (silent).startsWith ("si");
|
||||||
|
|
||||||
// if team is specified, kick from specified tram
|
// if team is specified, kick from specified tram
|
||||||
if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") {
|
if (arg <StringRef> (alias).endsWith ("_ct") || arg <int> (team) == 2 || arg <StringRef> (team) == "ct") {
|
||||||
bots.killAllBots (Team::CT, silentKill);
|
bots.killAllBots (Team::CT, silentKill);
|
||||||
}
|
}
|
||||||
else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") {
|
else if (arg <StringRef> (alias).endsWith ("_t") || arg <int> (team) == 1 || arg <StringRef> (team) == "t") {
|
||||||
bots.killAllBots (Team::Terrorist, silentKill);
|
bots.killAllBots (Team::Terrorist, silentKill);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -102,7 +102,10 @@ int BotControl::cmdFill () {
|
||||||
if (!hasArg (team)) {
|
if (!hasArg (team)) {
|
||||||
return BotCommandResult::BadFormat;
|
return BotCommandResult::BadFormat;
|
||||||
}
|
}
|
||||||
bots.serverFill (intValue (team), hasArg (personality) ? intValue (personality) : -1, hasArg (difficulty) ? intValue (difficulty) : -1, hasArg (count) ? intValue (count) - 1 : -1);
|
bots.serverFill (arg <int> (team),
|
||||||
|
hasArg (personality) ? arg <int> (personality) : -1,
|
||||||
|
hasArg (difficulty) ? arg <int> (difficulty) : -1,
|
||||||
|
hasArg (count) ? arg <int> (count) - 1 : -1);
|
||||||
|
|
||||||
return BotCommandResult::Handled;
|
return BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +116,7 @@ int BotControl::cmdVote () {
|
||||||
if (!hasArg (mapid)) {
|
if (!hasArg (mapid)) {
|
||||||
return BotCommandResult::BadFormat;
|
return BotCommandResult::BadFormat;
|
||||||
}
|
}
|
||||||
const int mapID = intValue (mapid);
|
const int mapID = arg <int> (mapid);
|
||||||
|
|
||||||
// loop through all players
|
// loop through all players
|
||||||
for (const auto &bot : bots) {
|
for (const auto &bot : bots) {
|
||||||
|
|
@ -139,7 +142,7 @@ int BotControl::cmdWeaponMode () {
|
||||||
{ "sniper", 6 },
|
{ "sniper", 6 },
|
||||||
{ "standard", 7 }
|
{ "standard", 7 }
|
||||||
};
|
};
|
||||||
auto mode = strValue (type);
|
auto mode = arg <StringRef> (type);
|
||||||
|
|
||||||
// check if selected mode exists
|
// check if selected mode exists
|
||||||
if (!modes.exists (mode)) {
|
if (!modes.exists (mode)) {
|
||||||
|
|
@ -180,7 +183,7 @@ int BotControl::cmdMenu () {
|
||||||
// reset the current menu
|
// reset the current menu
|
||||||
closeMenu ();
|
closeMenu ();
|
||||||
|
|
||||||
if (strValue (cmd) == "cmd" && util.isAlive (m_ent)) {
|
if (arg <StringRef> (cmd) == "cmd" && util.isAlive (m_ent)) {
|
||||||
showMenu (Menu::Commands);
|
showMenu (Menu::Commands);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -199,7 +202,7 @@ int BotControl::cmdList () {
|
||||||
int BotControl::cmdCvars () {
|
int BotControl::cmdCvars () {
|
||||||
enum args { alias = 1, pattern };
|
enum args { alias = 1, pattern };
|
||||||
|
|
||||||
auto match = strValue (pattern);
|
auto match = arg <StringRef> (pattern);
|
||||||
|
|
||||||
// revert all the cvars to their default values
|
// revert all the cvars to their default values
|
||||||
if (match == "defaults") {
|
if (match == "defaults") {
|
||||||
|
|
@ -257,7 +260,7 @@ int BotControl::cmdCvars () {
|
||||||
if (isSave && !cfg) {
|
if (isSave && !cfg) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto val = cvar.self->str ();
|
auto val = cvar.self->as <StringRef> ();
|
||||||
|
|
||||||
// float value ?
|
// float value ?
|
||||||
bool isFloat = !val.empty () && val.find (".") != StringRef::InvalidIndex;
|
bool isFloat = !val.empty () && val.find (".") != StringRef::InvalidIndex;
|
||||||
|
|
@ -276,20 +279,20 @@ int BotControl::cmdCvars () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cfg.puts ("// Default: \"%s\"\n", cvar.self->str ());
|
cfg.puts ("// Default: \"%s\"\n", cvar.self->as <StringRef> ());
|
||||||
}
|
}
|
||||||
cfg.puts ("// \n");
|
cfg.puts ("// \n");
|
||||||
|
|
||||||
if (cvar.bounded) {
|
if (cvar.bounded) {
|
||||||
if (isFloat) {
|
if (isFloat) {
|
||||||
cfg.puts ("%s \"%.1f\"\n", cvar.reg.name, cvar.self->float_ ());
|
cfg.puts ("%s \"%.1f\"\n", cvar.reg.name, cvar.self->as <float> ());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cfg.puts ("%s \"%i\"\n", cvar.reg.name, cvar.self->int_ ());
|
cfg.puts ("%s \"%i\"\n", cvar.reg.name, cvar.self->as <int> ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cfg.puts ("%s \"%s\"\n", cvar.reg.name, cvar.self->str ());
|
cfg.puts ("%s \"%s\"\n", cvar.reg.name, cvar.self->as <StringRef> ());
|
||||||
}
|
}
|
||||||
cfg.puts ("\n");
|
cfg.puts ("\n");
|
||||||
}
|
}
|
||||||
|
|
@ -327,7 +330,7 @@ int BotControl::cmdExec () {
|
||||||
if (!hasArg (target) || !hasArg (command)) {
|
if (!hasArg (target) || !hasArg (command)) {
|
||||||
return BotCommandResult::BadFormat;
|
return BotCommandResult::BadFormat;
|
||||||
}
|
}
|
||||||
const auto userId = intValue (target);
|
const auto userId = arg <int> (target);
|
||||||
|
|
||||||
// find our little target
|
// find our little target
|
||||||
auto bot = bots.findBotByIndex (userId);
|
auto bot = bots.findBotByIndex (userId);
|
||||||
|
|
@ -337,7 +340,7 @@ int BotControl::cmdExec () {
|
||||||
msg ("Bot with #%d not found or not a bot.", userId);
|
msg ("Bot with #%d not found or not a bot.", userId);
|
||||||
return BotCommandResult::Handled;
|
return BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
bot->issueCommand (strValue (command).chars ());
|
bot->issueCommand (arg <StringRef> (command).chars ());
|
||||||
|
|
||||||
return BotCommandResult::Handled;
|
return BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
@ -366,7 +369,7 @@ int BotControl::cmdNode () {
|
||||||
};
|
};
|
||||||
|
|
||||||
// graph editor supported only with editor
|
// graph editor supported only with editor
|
||||||
if (game.isDedicated () && !graph.hasEditor () && !isAllowedOnDedicatedServer (strValue (cmd))) {
|
if (game.isDedicated () && !graph.hasEditor () && !isAllowedOnDedicatedServer (arg <StringRef> (cmd))) {
|
||||||
msg ("Unable to use graph edit commands without setting graph editor player. Please use \"graph acquire_editor\" to acquire rights for graph editing.");
|
msg ("Unable to use graph edit commands without setting graph editor player. Please use \"graph acquire_editor\" to acquire rights for graph editing.");
|
||||||
return BotCommandResult::Handled;
|
return BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
@ -426,8 +429,8 @@ int BotControl::cmdNode () {
|
||||||
addGraphCmd ("release_editor", "release_editor [noarguments]", "Releases graph editing rights.", &BotControl::cmdNodeReleaseEditor);
|
addGraphCmd ("release_editor", "release_editor [noarguments]", "Releases graph editing rights.", &BotControl::cmdNodeReleaseEditor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (commands.exists (strValue (cmd))) {
|
if (commands.exists (arg <StringRef> (cmd))) {
|
||||||
const auto &item = commands[strValue (cmd)];
|
const auto &item = commands[arg <StringRef> (cmd)];
|
||||||
|
|
||||||
// graph have only bad format return status
|
// graph have only bad format return status
|
||||||
int status = (this->*item.handler) ();
|
int status = (this->*item.handler) ();
|
||||||
|
|
@ -439,8 +442,8 @@ int BotControl::cmdNode () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (strValue (cmd) == "help" && hasArg (cmd2) && commands.exists (strValue (cmd2))) {
|
if (arg <StringRef> (cmd) == "help" && hasArg (cmd2) && commands.exists (arg <StringRef> (cmd2))) {
|
||||||
auto &item = commands[strValue (cmd2)];
|
auto &item = commands[arg <StringRef> (cmd2)];
|
||||||
|
|
||||||
msg ("Command: \"%s %s %s\"", m_args[root], m_args[alias], item.name);
|
msg ("Command: \"%s %s %s\"", m_args[root], m_args[alias], item.name);
|
||||||
msg ("Format: %s", item.format);
|
msg ("Format: %s", item.format);
|
||||||
|
|
@ -461,13 +464,13 @@ int BotControl::cmdNodeOn () {
|
||||||
enum args { alias = 1, cmd, option };
|
enum args { alias = 1, cmd, option };
|
||||||
|
|
||||||
// enable various features of editor
|
// enable various features of editor
|
||||||
if (strValue (option).empty () || strValue (option) == "display" || strValue (option) == "models") {
|
if (arg <StringRef> (option).empty () || arg <StringRef> (option) == "display" || arg <StringRef> (option) == "models") {
|
||||||
graph.setEditFlag (GraphEdit::On);
|
graph.setEditFlag (GraphEdit::On);
|
||||||
enableDrawModels (true);
|
enableDrawModels (true);
|
||||||
|
|
||||||
msg ("Graph editor has been enabled.");
|
msg ("Graph editor has been enabled.");
|
||||||
}
|
}
|
||||||
else if (strValue (option) == "noclip") {
|
else if (arg <StringRef> (option) == "noclip") {
|
||||||
m_ent->v.movetype = MOVETYPE_NOCLIP;
|
m_ent->v.movetype = MOVETYPE_NOCLIP;
|
||||||
|
|
||||||
if (graph.hasEditFlag (GraphEdit::On)) {
|
if (graph.hasEditFlag (GraphEdit::On)) {
|
||||||
|
|
@ -482,7 +485,7 @@ int BotControl::cmdNodeOn () {
|
||||||
msg ("Graph editor has been enabled with noclip mode.");
|
msg ("Graph editor has been enabled with noclip mode.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strValue (option) == "auto") {
|
else if (arg <StringRef> (option) == "auto") {
|
||||||
if (graph.hasEditFlag (GraphEdit::On)) {
|
if (graph.hasEditFlag (GraphEdit::On)) {
|
||||||
graph.setEditFlag (GraphEdit::Auto);
|
graph.setEditFlag (GraphEdit::Auto);
|
||||||
|
|
||||||
|
|
@ -497,9 +500,9 @@ int BotControl::cmdNodeOn () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (graph.hasEditFlag (GraphEdit::On)) {
|
if (graph.hasEditFlag (GraphEdit::On)) {
|
||||||
m_graphSaveVarValues.roundtime = mp_roundtime.float_ ();
|
m_graphSaveVarValues.roundtime = mp_roundtime.as <float> ();
|
||||||
m_graphSaveVarValues.freezetime = mp_freezetime.float_ ();
|
m_graphSaveVarValues.freezetime = mp_freezetime.as <float> ();
|
||||||
m_graphSaveVarValues.timelimit = mp_timelimit.float_ ();
|
m_graphSaveVarValues.timelimit = mp_timelimit.as <float> ();
|
||||||
|
|
||||||
mp_roundtime.set (9);
|
mp_roundtime.set (9);
|
||||||
mp_freezetime.set (0);
|
mp_freezetime.set (0);
|
||||||
|
|
@ -512,7 +515,7 @@ int BotControl::cmdNodeOff () {
|
||||||
enum args { graph_cmd = 1, cmd, option };
|
enum args { graph_cmd = 1, cmd, option };
|
||||||
|
|
||||||
// enable various features of editor
|
// enable various features of editor
|
||||||
if (strValue (option).empty () || strValue (option) == "display") {
|
if (arg <StringRef> (option).empty () || arg <StringRef> (option) == "display") {
|
||||||
graph.clearEditFlag (GraphEdit::On | GraphEdit::Auto | GraphEdit::Noclip);
|
graph.clearEditFlag (GraphEdit::On | GraphEdit::Auto | GraphEdit::Noclip);
|
||||||
enableDrawModels (false);
|
enableDrawModels (false);
|
||||||
|
|
||||||
|
|
@ -523,18 +526,18 @@ int BotControl::cmdNodeOff () {
|
||||||
|
|
||||||
msg ("Graph editor has been disabled.");
|
msg ("Graph editor has been disabled.");
|
||||||
}
|
}
|
||||||
else if (strValue (option) == "models") {
|
else if (arg <StringRef> (option) == "models") {
|
||||||
enableDrawModels (false);
|
enableDrawModels (false);
|
||||||
|
|
||||||
msg ("Graph editor has disabled spawn points highlighting.");
|
msg ("Graph editor has disabled spawn points highlighting.");
|
||||||
}
|
}
|
||||||
else if (strValue (option) == "noclip") {
|
else if (arg <StringRef> (option) == "noclip") {
|
||||||
m_ent->v.movetype = MOVETYPE_WALK;
|
m_ent->v.movetype = MOVETYPE_WALK;
|
||||||
graph.clearEditFlag (GraphEdit::Noclip);
|
graph.clearEditFlag (GraphEdit::Noclip);
|
||||||
|
|
||||||
msg ("Graph editor has disabled noclip mode.");
|
msg ("Graph editor has disabled noclip mode.");
|
||||||
}
|
}
|
||||||
else if (strValue (option) == "auto") {
|
else if (arg <StringRef> (option) == "auto") {
|
||||||
graph.clearEditFlag (GraphEdit::Auto);
|
graph.clearEditFlag (GraphEdit::Auto);
|
||||||
msg ("Graph editor has disabled auto add node mode.");
|
msg ("Graph editor has disabled auto add node mode.");
|
||||||
}
|
}
|
||||||
|
|
@ -567,12 +570,12 @@ int BotControl::cmdNodeSave () {
|
||||||
enum args { graph_cmd = 1, cmd, option };
|
enum args { graph_cmd = 1, cmd, option };
|
||||||
|
|
||||||
// if no check is set save anyway
|
// if no check is set save anyway
|
||||||
if (strValue (option) == "nocheck") {
|
if (arg <StringRef> (option) == "nocheck") {
|
||||||
graph.saveGraphData ();
|
graph.saveGraphData ();
|
||||||
|
|
||||||
msg ("All nodes has been saved and written to disk (IGNORING QUALITY CONTROL).");
|
msg ("All nodes has been saved and written to disk (IGNORING QUALITY CONTROL).");
|
||||||
}
|
}
|
||||||
else if (strValue (option) == "old" || strValue (option) == "oldformat") {
|
else if (arg <StringRef> (option) == "old" || arg <StringRef> (option) == "oldformat") {
|
||||||
if (graph.length () >= 1024) {
|
if (graph.length () >= 1024) {
|
||||||
msg ("Unable to save POD-Bot Format waypoint file. Number of nodes exceeds 1024.");
|
msg ("Unable to save POD-Bot Format waypoint file. Number of nodes exceeds 1024.");
|
||||||
|
|
||||||
|
|
@ -611,7 +614,7 @@ int BotControl::cmdNodeErase () {
|
||||||
enum args { graph_cmd = 1, cmd, iamsure };
|
enum args { graph_cmd = 1, cmd, iamsure };
|
||||||
|
|
||||||
// prevent accidents when graph are deleted unintentionally
|
// prevent accidents when graph are deleted unintentionally
|
||||||
if (strValue (iamsure) == "iamsure") {
|
if (arg <StringRef> (iamsure) == "iamsure") {
|
||||||
bstor.unlinkFromDisk ();
|
bstor.unlinkFromDisk ();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -627,11 +630,11 @@ int BotControl::cmdNodeDelete () {
|
||||||
graph.setEditFlag (GraphEdit::On);
|
graph.setEditFlag (GraphEdit::On);
|
||||||
|
|
||||||
// if "nearest" or nothing passed delete nearest, else delete by index
|
// if "nearest" or nothing passed delete nearest, else delete by index
|
||||||
if (strValue (nearest).empty () || strValue (nearest) == "nearest") {
|
if (arg <StringRef> (nearest).empty () || arg <StringRef> (nearest) == "nearest") {
|
||||||
graph.erase (kInvalidNodeIndex);
|
graph.erase (kInvalidNodeIndex);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int index = intValue (nearest);
|
const auto index = arg <int> (nearest);
|
||||||
|
|
||||||
// check for existence
|
// check for existence
|
||||||
if (graph.exists (index)) {
|
if (graph.exists (index)) {
|
||||||
|
|
@ -662,11 +665,11 @@ int BotControl::cmdNodeCache () {
|
||||||
graph.setEditFlag (GraphEdit::On);
|
graph.setEditFlag (GraphEdit::On);
|
||||||
|
|
||||||
// if "nearest" or nothing passed delete nearest, else delete by index
|
// if "nearest" or nothing passed delete nearest, else delete by index
|
||||||
if (strValue (nearest).empty () || strValue (nearest) == "nearest") {
|
if (arg <StringRef> (nearest).empty () || arg <StringRef> (nearest) == "nearest") {
|
||||||
graph.cachePoint (kInvalidNodeIndex);
|
graph.cachePoint (kInvalidNodeIndex);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const int index = intValue (nearest);
|
const int index = arg <int> (nearest);
|
||||||
|
|
||||||
// check for existence
|
// check for existence
|
||||||
if (graph.exists (index)) {
|
if (graph.exists (index)) {
|
||||||
|
|
@ -683,7 +686,7 @@ int BotControl::cmdNodeClean () {
|
||||||
graph.setEditFlag (GraphEdit::On);
|
graph.setEditFlag (GraphEdit::On);
|
||||||
|
|
||||||
// if "all" passed clean up all the paths
|
// if "all" passed clean up all the paths
|
||||||
if (strValue (option) == "all") {
|
if (arg <StringRef> (option) == "all") {
|
||||||
int removed = 0;
|
int removed = 0;
|
||||||
|
|
||||||
for (auto i = 0; i < graph.length (); ++i) {
|
for (auto i = 0; i < graph.length (); ++i) {
|
||||||
|
|
@ -691,13 +694,13 @@ int BotControl::cmdNodeClean () {
|
||||||
}
|
}
|
||||||
msg ("Done. Processed %d nodes. %d useless paths was cleared.", graph.length (), removed);
|
msg ("Done. Processed %d nodes. %d useless paths was cleared.", graph.length (), removed);
|
||||||
}
|
}
|
||||||
else if (strValue (option).empty () || strValue (option) == "nearest") {
|
else if (arg <StringRef> (option).empty () || arg <StringRef> (option) == "nearest") {
|
||||||
int removed = graph.clearConnections (graph.getEditorNearest ());
|
int removed = graph.clearConnections (graph.getEditorNearest ());
|
||||||
|
|
||||||
msg ("Done. Processed node %d. %d useless paths was cleared.", graph.getEditorNearest (), removed);
|
msg ("Done. Processed node %d. %d useless paths was cleared.", graph.getEditorNearest (), removed);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const int index = intValue (option);
|
const int index = arg <int> (option);
|
||||||
|
|
||||||
// check for existence
|
// check for existence
|
||||||
if (graph.exists (index)) {
|
if (graph.exists (index)) {
|
||||||
|
|
@ -721,13 +724,13 @@ int BotControl::cmdNodeSetRadius () {
|
||||||
}
|
}
|
||||||
int radiusIndex = kInvalidNodeIndex;
|
int radiusIndex = kInvalidNodeIndex;
|
||||||
|
|
||||||
if (strValue (index).empty () || strValue (index) == "nearest") {
|
if (arg <StringRef> (index).empty () || arg <StringRef> (index) == "nearest") {
|
||||||
radiusIndex = graph.getEditorNearest ();
|
radiusIndex = graph.getEditorNearest ();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
radiusIndex = intValue (index);
|
radiusIndex = arg <int> (index);
|
||||||
}
|
}
|
||||||
graph.setRadius (radiusIndex, strValue (radius).float_ ());
|
graph.setRadius (radiusIndex, arg <StringRef> (radius).as <float> ());
|
||||||
|
|
||||||
return BotCommandResult::Handled;
|
return BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
@ -749,7 +752,7 @@ int BotControl::cmdNodeTeleport () {
|
||||||
if (!hasArg (teleport_index)) {
|
if (!hasArg (teleport_index)) {
|
||||||
return BotCommandResult::BadFormat;
|
return BotCommandResult::BadFormat;
|
||||||
}
|
}
|
||||||
int index = intValue (teleport_index);
|
int index = arg <int> (teleport_index);
|
||||||
|
|
||||||
// check for existence
|
// check for existence
|
||||||
if (graph.exists (index)) {
|
if (graph.exists (index)) {
|
||||||
|
|
@ -773,16 +776,16 @@ int BotControl::cmdNodePathCreate () {
|
||||||
graph.setEditFlag (GraphEdit::On);
|
graph.setEditFlag (GraphEdit::On);
|
||||||
|
|
||||||
// choose the direction for path creation
|
// choose the direction for path creation
|
||||||
if (strValue (cmd).endsWith ("_jump")) {
|
if (arg <StringRef> (cmd).endsWith ("_jump")) {
|
||||||
graph.pathCreate (PathConnection::Jumping);
|
graph.pathCreate (PathConnection::Jumping);
|
||||||
}
|
}
|
||||||
else if (strValue (cmd).endsWith ("_both")) {
|
else if (arg <StringRef> (cmd).endsWith ("_both")) {
|
||||||
graph.pathCreate (PathConnection::Bidirectional);
|
graph.pathCreate (PathConnection::Bidirectional);
|
||||||
}
|
}
|
||||||
else if (strValue (cmd).endsWith ("_in")) {
|
else if (arg <StringRef> (cmd).endsWith ("_in")) {
|
||||||
graph.pathCreate (PathConnection::Incoming);
|
graph.pathCreate (PathConnection::Incoming);
|
||||||
}
|
}
|
||||||
else if (strValue (cmd).endsWith ("_out")) {
|
else if (arg <StringRef> (cmd).endsWith ("_out")) {
|
||||||
graph.pathCreate (PathConnection::Outgoing);
|
graph.pathCreate (PathConnection::Outgoing);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -819,7 +822,7 @@ int BotControl::cmdNodePathCleanAll () {
|
||||||
auto requestedNode = kInvalidNodeIndex;
|
auto requestedNode = kInvalidNodeIndex;
|
||||||
|
|
||||||
if (hasArg (index)) {
|
if (hasArg (index)) {
|
||||||
requestedNode = intValue (index);
|
requestedNode = arg <int> (index);
|
||||||
}
|
}
|
||||||
graph.resetPath (requestedNode);
|
graph.resetPath (requestedNode);
|
||||||
|
|
||||||
|
|
@ -871,7 +874,7 @@ int BotControl::cmdNodeUpload () {
|
||||||
msg ("Sorry, unable to upload graph file that contains errors. Please type \"graph check\" to verify graph consistency.");
|
msg ("Sorry, unable to upload graph file that contains errors. Please type \"graph check\" to verify graph consistency.");
|
||||||
return BotCommandResult::Handled;
|
return BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
String uploadUrlAddress = cv_graph_url_upload.str ();
|
String uploadUrlAddress = cv_graph_url_upload.as <StringRef> ();
|
||||||
|
|
||||||
// only allow to upload to non-https endpoint
|
// only allow to upload to non-https endpoint
|
||||||
if (uploadUrlAddress.startsWith ("https")) {
|
if (uploadUrlAddress.startsWith ("https")) {
|
||||||
|
|
@ -930,7 +933,7 @@ int BotControl::cmdNodeIterateCamp () {
|
||||||
graph.setEditFlag (GraphEdit::On);
|
graph.setEditFlag (GraphEdit::On);
|
||||||
|
|
||||||
// get the option describing operation
|
// get the option describing operation
|
||||||
auto op = strValue (option);
|
auto op = arg <StringRef> (option);
|
||||||
|
|
||||||
if (op != "begin" && op != "end" && op != "next") {
|
if (op != "begin" && op != "end" && op != "next") {
|
||||||
return BotCommandResult::BadFormat;
|
return BotCommandResult::BadFormat;
|
||||||
|
|
@ -998,7 +1001,7 @@ int BotControl::cmdNodeAdjustHeight () {
|
||||||
if (!hasArg (offset)) {
|
if (!hasArg (offset)) {
|
||||||
return BotCommandResult::BadFormat;
|
return BotCommandResult::BadFormat;
|
||||||
}
|
}
|
||||||
auto heightOffset = floatValue (offset);
|
auto heightOffset = arg <float> (offset);
|
||||||
|
|
||||||
// adjust the height for all the nodes (negative values possible)
|
// adjust the height for all the nodes (negative values possible)
|
||||||
for (auto &path : graph) {
|
for (auto &path : graph) {
|
||||||
|
|
@ -1026,7 +1029,7 @@ int BotControl::menuMain (int item) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
if (game.is (GameFlags::ReGameDLL) && !cv_bots_kill_on_endround.bool_ ()) {
|
if (game.is (GameFlags::ReGameDLL) && !cv_bots_kill_on_endround) {
|
||||||
game.serverCommand ("endround");
|
game.serverCommand ("endround");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -1069,7 +1072,7 @@ int BotControl::menuFeatures (int item) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
cv_debug.set (cv_debug.int_ () ^ 1);
|
cv_debug.set (cv_debug.as <int> () ^ 1);
|
||||||
|
|
||||||
showMenu (Menu::Features);
|
showMenu (Menu::Features);
|
||||||
break;
|
break;
|
||||||
|
|
@ -1549,8 +1552,8 @@ int BotControl::menuGraphDebug (int item) {
|
||||||
switch (item) {
|
switch (item) {
|
||||||
case 1:
|
case 1:
|
||||||
cv_debug_goal.set (graph.getEditorNearest ());
|
cv_debug_goal.set (graph.getEditorNearest ());
|
||||||
if (cv_debug_goal.int_ () != kInvalidNodeIndex) {
|
if (cv_debug_goal.as <int> () != kInvalidNodeIndex) {
|
||||||
msg ("Debug goal is set to node %d.", cv_debug_goal.int_ ());
|
msg ("Debug goal is set to node %d.", cv_debug_goal.as <int> ());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
msg ("Cannot find the node. Debug goal is disabled.");
|
msg ("Cannot find the node. Debug goal is disabled.");
|
||||||
|
|
@ -1560,8 +1563,8 @@ int BotControl::menuGraphDebug (int item) {
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
cv_debug_goal.set (graph.getFacingIndex ());
|
cv_debug_goal.set (graph.getFacingIndex ());
|
||||||
if (cv_debug_goal.int_ () != kInvalidNodeIndex) {
|
if (cv_debug_goal.as <int> () != kInvalidNodeIndex) {
|
||||||
msg ("Debug goal is set to node %d.", cv_debug_goal.int_ ());
|
msg ("Debug goal is set to node %d.", cv_debug_goal.as <int> ());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
msg ("Cannot find the node. Debug goal is disabled.");
|
msg ("Cannot find the node. Debug goal is disabled.");
|
||||||
|
|
@ -1871,7 +1874,7 @@ bool BotControl::executeCommands () {
|
||||||
String cmd;
|
String cmd;
|
||||||
|
|
||||||
// give some help
|
// give some help
|
||||||
if (hasArg (1) && strValue (1) == "help") {
|
if (hasArg (1) && arg <StringRef> (1) == "help") {
|
||||||
const auto hasSecondArg = hasArg (2);
|
const auto hasSecondArg = hasArg (2);
|
||||||
|
|
||||||
for (auto &item : m_cmds) {
|
for (auto &item : m_cmds) {
|
||||||
|
|
@ -1879,7 +1882,7 @@ bool BotControl::executeCommands () {
|
||||||
cmd = item.name.split ("/").first ();
|
cmd = item.name.split ("/").first ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasSecondArg || aliasMatch (item.name, strValue (2), cmd)) {
|
if (!hasSecondArg || aliasMatch (item.name, arg <StringRef> (2), cmd)) {
|
||||||
msg ("Command: \"%s %s\"", prefix, cmd);
|
msg ("Command: \"%s %s\"", prefix, cmd);
|
||||||
msg ("Format: %s", item.format);
|
msg ("Format: %s", item.format);
|
||||||
msg ("Help: %s", conf.translate (item.help));
|
msg ("Help: %s", conf.translate (item.help));
|
||||||
|
|
@ -1903,7 +1906,7 @@ bool BotControl::executeCommands () {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
msg ("No help found for \"%s\"", strValue (2));
|
msg ("No help found for \"%s\"", arg <StringRef> (2));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1961,14 +1964,14 @@ bool BotControl::executeMenus () {
|
||||||
const auto &issuer = util.getClient (game.indexOfPlayer (m_ent));
|
const auto &issuer = util.getClient (game.indexOfPlayer (m_ent));
|
||||||
|
|
||||||
// check if it's menu select, and some key pressed
|
// check if it's menu select, and some key pressed
|
||||||
if (strValue (0) != "menuselect" || strValue (1).empty () || issuer.menu == Menu::None) {
|
if (arg <StringRef> (0) != "menuselect" || arg <StringRef> (1).empty () || issuer.menu == Menu::None) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// let's get handle
|
// let's get handle
|
||||||
for (auto &menu : m_menus) {
|
for (auto &menu : m_menus) {
|
||||||
if (menu.ident == issuer.menu) {
|
if (menu.ident == issuer.menu) {
|
||||||
return (this->*menu.handler) (strValue (1).int_ ()) == BotCommandResult::Handled;
|
return (this->*menu.handler) (arg <StringRef> (1).as <int> ()) == BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -2013,7 +2016,7 @@ void BotControl::showMenu (int id) {
|
||||||
|
|
||||||
for (const auto &display : m_menus) {
|
for (const auto &display : m_menus) {
|
||||||
if (display.ident == id) {
|
if (display.ident == id) {
|
||||||
String text = (game.is (GameFlags::Xash3D | GameFlags::Mobility) && !cv_display_menu_text.bool_ ()) ? " " : display.text.chars ();
|
String text = (game.is (GameFlags::Xash3D | GameFlags::Mobility) && !cv_display_menu_text) ? " " : display.text.chars ();
|
||||||
|
|
||||||
// split if needed
|
// split if needed
|
||||||
if (text.length () > maxMenuSentLength) {
|
if (text.length () > maxMenuSentLength) {
|
||||||
|
|
@ -2106,8 +2109,8 @@ void BotControl::assignAdminRights (edict_t *ent, char *infobuffer) {
|
||||||
if (!game.isDedicated () || util.isFakeClient (ent)) {
|
if (!game.isDedicated () || util.isFakeClient (ent)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StringRef key = cv_password_key.str ();
|
StringRef key = cv_password_key.as <StringRef> ();
|
||||||
StringRef password = cv_password.str ();
|
StringRef password = cv_password.as <StringRef> ();
|
||||||
|
|
||||||
if (!key.empty () && !password.empty ()) {
|
if (!key.empty () && !password.empty ()) {
|
||||||
auto &client = util.getClient (game.indexOfPlayer (ent));
|
auto &client = util.getClient (game.indexOfPlayer (ent));
|
||||||
|
|
@ -2126,8 +2129,8 @@ void BotControl::maintainAdminRights () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef key = cv_password_key.str ();
|
StringRef key = cv_password_key.as <StringRef> ();
|
||||||
StringRef password = cv_password.str ();
|
StringRef password = cv_password.as <StringRef> ();
|
||||||
|
|
||||||
for (auto &client : util.getClients ()) {
|
for (auto &client : util.getClients ()) {
|
||||||
if (!(client.flags & ClientFlags::Used) || util.isFakeClient (client.ent)) {
|
if (!(client.flags & ClientFlags::Used) || util.isFakeClient (client.ent)) {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ ConVar cv_csdm_mode ("csdm_mode", "0", "Enables or disables CSDM / FFA mode for
|
||||||
ConVar cv_ignore_map_prefix_game_mode ("ignore_map_prefix_game_mode", "0", "If enabled, bots will not apply game modes based on map name prefix (fy_ and ka_ specifically).");
|
ConVar cv_ignore_map_prefix_game_mode ("ignore_map_prefix_game_mode", "0", "If enabled, bots will not apply game modes based on map name prefix (fy_ and ka_ specifically).");
|
||||||
ConVar cv_threadpool_workers ("threadpool_workers", "-1", "Maximum number of threads bot will run to process some tasks. -1 means half of CPU cores used.", true, -1.0f, static_cast <float> (plat.hardwareConcurrency ()));
|
ConVar cv_threadpool_workers ("threadpool_workers", "-1", "Maximum number of threads bot will run to process some tasks. -1 means half of CPU cores used.", true, -1.0f, static_cast <float> (plat.hardwareConcurrency ()));
|
||||||
ConVar cv_grenadier_mode ("grenadier_mode", "0", "If enabled, bots will not apply throwing condition on grenades.");
|
ConVar cv_grenadier_mode ("grenadier_mode", "0", "If enabled, bots will not apply throwing condition on grenades.");
|
||||||
ConVar cv_ignore_enemies_after_spawn_time ("ignore_enemies_after_spawn_time", "0", "Make bots ignore enemies for a specified here time in seconds on new round. Useful for Zombie Plague mods.", true, 0.0f, 540.0f);
|
ConVar cv_ignore_enemies_after_spawn_time ("ignore_enemies_after_spawn_time", "0", "Make bots ignore enemies for a specified here time in seconds on new round. Useful for Zombie Plague mods.", false);
|
||||||
|
|
||||||
ConVar sv_skycolor_r ("sv_skycolor_r", nullptr, Var::GameRef);
|
ConVar sv_skycolor_r ("sv_skycolor_r", nullptr, Var::GameRef);
|
||||||
ConVar sv_skycolor_g ("sv_skycolor_g", nullptr, Var::GameRef);
|
ConVar sv_skycolor_g ("sv_skycolor_g", nullptr, Var::GameRef);
|
||||||
|
|
@ -55,7 +55,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
|
||||||
bots.destroy ();
|
bots.destroy ();
|
||||||
|
|
||||||
// startup threaded worker
|
// startup threaded worker
|
||||||
worker.startup (cv_threadpool_workers.int_ ());
|
worker.startup (cv_threadpool_workers.as <int> ());
|
||||||
|
|
||||||
m_spawnCount[Team::CT] = 0;
|
m_spawnCount[Team::CT] = 0;
|
||||||
m_spawnCount[Team::Terrorist] = 0;
|
m_spawnCount[Team::Terrorist] = 0;
|
||||||
|
|
@ -154,7 +154,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// next maps doesn't have map-specific entities, so determine it by name
|
// next maps doesn't have map-specific entities, so determine it by name
|
||||||
if (!cv_ignore_map_prefix_game_mode.bool_ ()) {
|
if (!cv_ignore_map_prefix_game_mode) {
|
||||||
StringRef prefix = getMapName ();
|
StringRef prefix = getMapName ();
|
||||||
|
|
||||||
if (prefix.startsWith ("fy_")) {
|
if (prefix.startsWith ("fy_")) {
|
||||||
|
|
@ -590,27 +590,27 @@ bool Game::is25thAnniversaryUpdate () {
|
||||||
return sv_use_steam_networking.exists ();
|
return sv_use_steam_networking.exists ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32_t varType, bool missingAction, const char *regval, ConVar *self) {
|
void Game::pushConVar (StringRef name, StringRef value, StringRef info, bool bounded, float min, float max, int32_t varType, bool missingAction, StringRef regval, ConVar *self) {
|
||||||
// this function adds globally defined variable to registration stack
|
// this function adds globally defined variable to registration stack
|
||||||
|
|
||||||
ConVarReg reg {};
|
ConVarReg reg {};
|
||||||
|
|
||||||
reg.reg.name = const_cast <char *> (name);
|
reg.reg.name = name.chars ();
|
||||||
reg.reg.string = const_cast <char *> (value);
|
reg.reg.string = value.chars ();
|
||||||
reg.name = name;
|
reg.name = name;
|
||||||
reg.missing = missingAction;
|
reg.missing = missingAction;
|
||||||
reg.init = value;
|
reg.init = value;
|
||||||
reg.info = info;
|
reg.info = info;
|
||||||
reg.bounded = bounded;
|
reg.bounded = bounded;
|
||||||
|
|
||||||
if (regval) {
|
if (!regval.empty ()) {
|
||||||
reg.regval = regval;
|
reg.regval = regval;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bounded) {
|
if (bounded) {
|
||||||
reg.min = min;
|
reg.min = min;
|
||||||
reg.max = max;
|
reg.max = max;
|
||||||
reg.initial = static_cast <float> (atof (value));
|
reg.initial = value.as <float> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
int eflags = FCVAR_EXTDLL;
|
int eflags = FCVAR_EXTDLL;
|
||||||
|
|
@ -646,7 +646,7 @@ void ConVar::revert () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConVar::setPrefix (const char *name, int32_t type) {
|
void ConVar::setPrefix (StringRef name, int32_t type) {
|
||||||
if (type == Var::GameRef) {
|
if (type == Var::GameRef) {
|
||||||
name_ = name;
|
name_ = name;
|
||||||
return;
|
return;
|
||||||
|
|
@ -662,7 +662,7 @@ void Game::checkCvarsBounds () {
|
||||||
|
|
||||||
// read only cvar is not changeable
|
// read only cvar is not changeable
|
||||||
if (var.type == Var::ReadOnly && !var.init.empty ()) {
|
if (var.type == Var::ReadOnly && !var.init.empty ()) {
|
||||||
if (var.init != var.self->str ()) {
|
if (var.init != var.self->as <StringRef> ()) {
|
||||||
var.self->set (var.init.chars ());
|
var.self->set (var.init.chars ());
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -671,8 +671,8 @@ void Game::checkCvarsBounds () {
|
||||||
if (!var.bounded || !var.self) {
|
if (!var.bounded || !var.self) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto value = var.self->float_ ();
|
auto value = var.self->as <float> ();
|
||||||
auto str = String (var.self->str ());
|
auto str = String (var.self->as <StringRef> ());
|
||||||
|
|
||||||
// check the bounds and set default if out of bounds
|
// check the bounds and set default if out of bounds
|
||||||
if (value > var.max || value < var.min || (!str.empty () && isalpha (str[0]))) {
|
if (value > var.max || value < var.min || (!str.empty () && isalpha (str[0]))) {
|
||||||
|
|
@ -685,7 +685,7 @@ void Game::checkCvarsBounds () {
|
||||||
|
|
||||||
// special case for xash3d, by default engine is not calling startframe if no players on server, but our quota management and bot adding
|
// special case for xash3d, by default engine is not calling startframe if no players on server, but our quota management and bot adding
|
||||||
// mechanism assumes that starframe is called even if no players on server, so, set the xash3d's sv_forcesimulating cvar to 1 in case it's not
|
// mechanism assumes that starframe is called even if no players on server, so, set the xash3d's sv_forcesimulating cvar to 1 in case it's not
|
||||||
if (is (GameFlags::Xash3D)) {
|
if (is (GameFlags::Xash3DLegacy)) {
|
||||||
static ConVarRef sv_forcesimulating ("sv_forcesimulating");
|
static ConVarRef sv_forcesimulating ("sv_forcesimulating");
|
||||||
|
|
||||||
if (sv_forcesimulating.exists () && !cr::fequal (sv_forcesimulating.value (), 1.0f)) {
|
if (sv_forcesimulating.exists () && !cr::fequal (sv_forcesimulating.value (), 1.0f)) {
|
||||||
|
|
@ -929,7 +929,7 @@ void Game::applyGameModes () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle cvar cases
|
// handle cvar cases
|
||||||
switch (cv_csdm_mode.int_ ()) {
|
switch (cv_csdm_mode.as <int> ()) {
|
||||||
default:
|
default:
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
|
|
@ -1312,5 +1312,5 @@ float LightMeasure::getLightLevel (const Vector &point) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float LightMeasure::getSkyColor () {
|
float LightMeasure::getSkyColor () {
|
||||||
return static_cast <float> (Color (sv_skycolor_r.int_ (), sv_skycolor_g.int_ (), sv_skycolor_b.int_ ()).avg ());
|
return static_cast <float> (Color (sv_skycolor_r.as <int> (), sv_skycolor_g.as <int> (), sv_skycolor_b.as <int> ()).avg ());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -729,7 +729,7 @@ void BotGraph::add (int type, const Vector &pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// autosave nodes here and there
|
// autosave nodes here and there
|
||||||
if (!analyzer.isAnalyzing () && cv_graph_auto_save_count.bool_ () && ++m_autoSaveCount >= cv_graph_auto_save_count.int_ ()) {
|
if (!analyzer.isAnalyzing () && cv_graph_auto_save_count && ++m_autoSaveCount >= cv_graph_auto_save_count.as <int> ()) {
|
||||||
if (saveGraphData ()) {
|
if (saveGraphData ()) {
|
||||||
msg ("Nodes has been autosaved...");
|
msg ("Nodes has been autosaved...");
|
||||||
}
|
}
|
||||||
|
|
@ -1324,7 +1324,7 @@ void BotGraph::syncCollectOnline () {
|
||||||
if (localGraphs.empty ()) {
|
if (localGraphs.empty ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String uploadUrlAddress = cv_graph_url_upload.str ();
|
String uploadUrlAddress = cv_graph_url_upload.as <StringRef> ();
|
||||||
|
|
||||||
// only allow to upload to non-https endpoint
|
// only allow to upload to non-https endpoint
|
||||||
if (uploadUrlAddress.startsWith ("https")) {
|
if (uploadUrlAddress.startsWith ("https")) {
|
||||||
|
|
@ -1416,7 +1416,7 @@ void BotGraph::syncCollectOnline () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotGraph::collectOnline () {
|
void BotGraph::collectOnline () {
|
||||||
if (m_isOnlineCollected || !cv_graph_auto_collect_db.bool_ ()) {
|
if (m_isOnlineCollected || !cv_graph_auto_collect_db) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1818,7 +1818,7 @@ bool BotGraph::loadGraphData () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotGraph::canDownload () {
|
bool BotGraph::canDownload () {
|
||||||
return !cv_graph_url.str ().empty ();
|
return !cv_graph_url.as <StringRef> ().empty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotGraph::saveGraphData () {
|
bool BotGraph::saveGraphData () {
|
||||||
|
|
@ -2019,7 +2019,7 @@ bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotGraph::isNodeReacheableWithJump (const Vector &src, const Vector &destination) {
|
bool BotGraph::isNodeReacheableWithJump (const Vector &src, const Vector &destination) {
|
||||||
return isNodeReacheableEx (src, destination, cv_graph_analyze_max_jump_height.float_ ());
|
return isNodeReacheableEx (src, destination, cv_graph_analyze_max_jump_height.as <float> ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotGraph::frame () {
|
void BotGraph::frame () {
|
||||||
|
|
@ -2092,7 +2092,7 @@ void BotGraph::frame () {
|
||||||
const float distanceSq = path.origin.distanceSq (m_editor->v.origin);
|
const float distanceSq = path.origin.distanceSq (m_editor->v.origin);
|
||||||
|
|
||||||
// check if node is within a distance, and is visible
|
// check if node is within a distance, and is visible
|
||||||
if (distanceSq < cr::sqrf (cv_graph_draw_distance.float_ ())
|
if (distanceSq < cr::sqrf (cv_graph_draw_distance.as <float> ())
|
||||||
&& ((util.isVisible (path.origin, m_editor)
|
&& ((util.isVisible (path.origin, m_editor)
|
||||||
&& util.isInViewCone (path.origin, m_editor)) || !util.isAlive (m_editor) || distanceSq < cr::sqrf (64.0f))) {
|
&& util.isInViewCone (path.origin, m_editor)) || !util.isAlive (m_editor) || distanceSq < cr::sqrf (64.0f))) {
|
||||||
|
|
||||||
|
|
@ -2844,7 +2844,7 @@ void BotGraph::convertFromPOD (Path &path, const PODPath &pod) {
|
||||||
path.start = Vector (pod.csx, pod.csy, 0.0f);
|
path.start = Vector (pod.csx, pod.csy, 0.0f);
|
||||||
path.end = Vector (pod.cex, pod.cey, 0.0f);
|
path.end = Vector (pod.cex, pod.cey, 0.0f);
|
||||||
|
|
||||||
if (cv_graph_fixcamp.bool_ ()) {
|
if (cv_graph_fixcamp) {
|
||||||
convertCampDirection (path);
|
convertCampDirection (path);
|
||||||
}
|
}
|
||||||
path.radius = pod.radius;
|
path.radius = pod.radius;
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ int32_t ServerQueryHook::sendTo (int socket, const void *message, size_t length,
|
||||||
|
|
||||||
void ServerQueryHook::init () {
|
void ServerQueryHook::init () {
|
||||||
// if previously requested to disable?
|
// if previously requested to disable?
|
||||||
if (!cv_enable_query_hook.bool_ ()) {
|
if (!cv_enable_query_hook) {
|
||||||
if (m_sendToDetour.detoured ()) {
|
if (m_sendToDetour.detoured ()) {
|
||||||
disable ();
|
disable ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -394,7 +394,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
auto ent = const_cast <edict_t *> (player);
|
auto ent = const_cast <edict_t *> (player);
|
||||||
|
|
||||||
// if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false, and SV_EmitPings will not overwrite our results
|
// if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false, and SV_EmitPings will not overwrite our results
|
||||||
if (cv_show_latency.int_ () == 2) {
|
if (cv_show_latency.as <int> () == 2) {
|
||||||
if (!util.isFakeClient (ent) && (ent->v.oldbuttons | ent->v.button | cmd->buttons) & IN_SCORE) {
|
if (!util.isFakeClient (ent) && (ent->v.oldbuttons | ent->v.button | cmd->buttons) & IN_SCORE) {
|
||||||
cmd->buttons &= ~IN_SCORE;
|
cmd->buttons &= ~IN_SCORE;
|
||||||
util.emitPings (ent);
|
util.emitPings (ent);
|
||||||
|
|
@ -863,10 +863,10 @@ CR_EXPORT int Meta_Query (char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_t
|
||||||
|
|
||||||
gpMetaUtilFuncs->pfnLogError (PLID, "%s: meta-interface version mismatch (metamod: %s, %s: %s)", Plugin_info.name, ifvers, Plugin_info.name, Plugin_info.ifvers);
|
gpMetaUtilFuncs->pfnLogError (PLID, "%s: meta-interface version mismatch (metamod: %s, %s: %s)", Plugin_info.name, ifvers, Plugin_info.name, Plugin_info.ifvers);
|
||||||
|
|
||||||
const auto mmajor = mdll[0].int_ () ;
|
const auto mmajor = mdll[0].as <int> ();
|
||||||
const auto mminor = mdll[1].int_ ();
|
const auto mminor = mdll[1].as <int> ();
|
||||||
const auto pmajor = pdll[0].int_ ();
|
const auto pmajor = pdll[0].as <int> ();
|
||||||
const auto pminor = pdll[1].int_ ();
|
const auto pminor = pdll[1].as <int> ();
|
||||||
|
|
||||||
if (pmajor > mmajor || (pmajor == mmajor && pminor > mminor)) {
|
if (pmajor > mmajor || (pmajor == mmajor && pminor > mminor)) {
|
||||||
gpMetaUtilFuncs->pfnLogError (PLID, "metamod version is too old for this plugin; update metamod");
|
gpMetaUtilFuncs->pfnLogError (PLID, "metamod version is too old for this plugin; update metamod");
|
||||||
|
|
|
||||||
186
src/manager.cpp
186
src/manager.cpp
|
|
@ -192,10 +192,10 @@ BotCreateResult BotManager::create (StringRef name, int difficulty, int personal
|
||||||
return BotCreateResult::TeamStacked;
|
return BotCreateResult::TeamStacked;
|
||||||
}
|
}
|
||||||
if (difficulty < Difficulty::Noob || difficulty > Difficulty::Expert) {
|
if (difficulty < Difficulty::Noob || difficulty > Difficulty::Expert) {
|
||||||
difficulty = cv_difficulty.int_ ();
|
difficulty = cv_difficulty.as <int> ();
|
||||||
|
|
||||||
if (difficulty < Difficulty::Noob || difficulty > Difficulty::Expert) {
|
if (difficulty < Difficulty::Noob || difficulty > Difficulty::Expert) {
|
||||||
difficulty = rg.get (3, 4);
|
difficulty = rg (3, 4);
|
||||||
cv_difficulty.set (difficulty);
|
cv_difficulty.set (difficulty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -211,8 +211,8 @@ BotCreateResult BotManager::create (StringRef name, int difficulty, int personal
|
||||||
if (personality < Personality::Normal || personality > Personality::Careful) {
|
if (personality < Personality::Normal || personality > Personality::Careful) {
|
||||||
|
|
||||||
// assign preferred if we're forced with cvar
|
// assign preferred if we're forced with cvar
|
||||||
if (personalityMap.exists (cv_preferred_personality.str ())) {
|
if (personalityMap.exists (cv_preferred_personality.as <StringRef> ())) {
|
||||||
personality = personalityMap[cv_preferred_personality.str ()];
|
personality = personalityMap[cv_preferred_personality.as <StringRef> ()];
|
||||||
}
|
}
|
||||||
|
|
||||||
// do a holy random
|
// do a holy random
|
||||||
|
|
@ -240,22 +240,22 @@ BotCreateResult BotManager::create (StringRef name, int difficulty, int personal
|
||||||
resultName = botName->name;
|
resultName = botName->name;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
resultName.assignf ("%s_%d.%d", product.nameLower, rg.get (100, 10000), rg.get (100, 10000)); // just pick ugly random name
|
resultName.assignf ("%s_%d.%d", product.nameLower, rg (100, 10000), rg (100, 10000)); // just pick ugly random name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
resultName = name;
|
resultName = name;
|
||||||
}
|
}
|
||||||
const bool hasNamePrefix = !cv_name_prefix.str ().empty ();
|
const bool hasNamePrefix = !cv_name_prefix.as <StringRef> ().empty ();
|
||||||
|
|
||||||
// disable save bots names if prefix is enabled
|
// disable save bots names if prefix is enabled
|
||||||
if (hasNamePrefix && cv_save_bots_names.bool_ ()) {
|
if (hasNamePrefix && cv_save_bots_names) {
|
||||||
cv_save_bots_names.set (0);
|
cv_save_bots_names.set (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasNamePrefix) {
|
if (hasNamePrefix) {
|
||||||
String prefixed; // temp buffer for storing modified name
|
String prefixed; // temp buffer for storing modified name
|
||||||
prefixed.assignf ("%s %s", cv_name_prefix.str (), resultName);
|
prefixed.assignf ("%s %s", cv_name_prefix.as <StringRef> (), resultName);
|
||||||
|
|
||||||
// buffer has been modified, copy to real name
|
// buffer has been modified, copy to real name
|
||||||
resultName = cr::move (prefixed);
|
resultName = cr::move (prefixed);
|
||||||
|
|
@ -336,7 +336,7 @@ void BotManager::addbot (StringRef name, int difficulty, int personality, int te
|
||||||
request.manual = manual;
|
request.manual = manual;
|
||||||
|
|
||||||
// restore the bot name
|
// restore the bot name
|
||||||
if (cv_save_bots_names.bool_ () && name.empty () && !m_saveBotNames.empty ()) {
|
if (cv_save_bots_names && name.empty () && !m_saveBotNames.empty ()) {
|
||||||
request.name = m_saveBotNames.popFront ();
|
request.name = m_saveBotNames.popFront ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -351,10 +351,10 @@ void BotManager::addbot (StringRef name, StringRef difficulty, StringRef persona
|
||||||
static StringRef any = "*";
|
static StringRef any = "*";
|
||||||
|
|
||||||
request.name = (name.empty () || name == any) ? StringRef ("\0") : name;
|
request.name = (name.empty () || name == any) ? StringRef ("\0") : name;
|
||||||
request.difficulty = (difficulty.empty () || difficulty == any) ? -1 : difficulty.int_ ();
|
request.difficulty = (difficulty.empty () || difficulty == any) ? -1 : difficulty.as <int> ();
|
||||||
request.team = (team.empty () || team == any) ? -1 : team.int_ ();
|
request.team = (team.empty () || team == any) ? -1 : team.as <int> ();
|
||||||
request.skin = (skin.empty () || skin == any) ? -1 : skin.int_ ();
|
request.skin = (skin.empty () || skin == any) ? -1 : skin.as <int> ();
|
||||||
request.personality = (personality.empty () || personality == any) ? -1 : personality.int_ ();
|
request.personality = (personality.empty () || personality == any) ? -1 : personality.as <int> ();
|
||||||
request.manual = manual;
|
request.manual = manual;
|
||||||
|
|
||||||
addbot (request.name, request.difficulty, request.personality, request.team, request.skin, request.manual);
|
addbot (request.name, request.difficulty, request.personality, request.team, request.skin, request.manual);
|
||||||
|
|
@ -365,7 +365,7 @@ void BotManager::maintainQuota () {
|
||||||
// while creation process in process.
|
// while creation process in process.
|
||||||
|
|
||||||
if (graph.length () < 1 || graph.hasChanged ()) {
|
if (graph.length () < 1 || graph.hasChanged ()) {
|
||||||
if (cv_quota.int_ () > 0) {
|
if (cv_quota.as <int> () > 0) {
|
||||||
ctrl.msg ("There is no graph found. Cannot create bot.");
|
ctrl.msg ("There is no graph found. Cannot create bot.");
|
||||||
}
|
}
|
||||||
cv_quota.set (0);
|
cv_quota.set (0);
|
||||||
|
|
@ -383,7 +383,7 @@ void BotManager::maintainQuota () {
|
||||||
const BotCreateResult createResult = create (request.name, request.difficulty, request.personality, request.team, request.skin);
|
const BotCreateResult createResult = create (request.name, request.difficulty, request.personality, request.team, request.skin);
|
||||||
|
|
||||||
if (request.manual) {
|
if (request.manual) {
|
||||||
cv_quota.set (cr::min (cv_quota.int_ () + 1, game.maxClients ()));
|
cv_quota.set (cr::min (cv_quota.as <int> () + 1, game.maxClients ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the result of creation
|
// check the result of creation
|
||||||
|
|
@ -403,14 +403,14 @@ void BotManager::maintainQuota () {
|
||||||
m_addRequests.clear ();
|
m_addRequests.clear ();
|
||||||
cv_quota.set (getBotCount ());
|
cv_quota.set (getBotCount ());
|
||||||
}
|
}
|
||||||
m_maintainTime = game.time () + cv_quota_adding_interval.float_ ();
|
m_maintainTime = game.time () + cv_quota_adding_interval.as <float> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// now keep bot number up to date
|
// now keep bot number up to date
|
||||||
if (m_quotaMaintainTime > game.time ()) {
|
if (m_quotaMaintainTime > game.time ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cv_quota.set (cr::clamp <int> (cv_quota.int_ (), 0, game.maxClients ()));
|
cv_quota.set (cr::clamp <int> (cv_quota.as <int> (), 0, game.maxClients ()));
|
||||||
|
|
||||||
const int totalHumansInGame = getHumansCount ();
|
const int totalHumansInGame = getHumansCount ();
|
||||||
const int humanPlayersInGame = getHumansCount (true);
|
const int humanPlayersInGame = getHumansCount (true);
|
||||||
|
|
@ -419,29 +419,29 @@ void BotManager::maintainQuota () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int desiredBotCount = cv_quota.int_ ();
|
int desiredBotCount = cv_quota.as <int> ();
|
||||||
int botsInGame = getBotCount ();
|
int botsInGame = getBotCount ();
|
||||||
|
|
||||||
if (cv_quota_mode.str () == "fill") {
|
if (cv_quota_mode.as <StringRef> () == "fill") {
|
||||||
botsInGame += humanPlayersInGame;
|
botsInGame += humanPlayersInGame;
|
||||||
}
|
}
|
||||||
else if (cv_quota_mode.str () == "match") {
|
else if (cv_quota_mode.as <StringRef> () == "match") {
|
||||||
int detectQuotaMatch = cv_quota_match.int_ () == 0 ? cv_quota.int_ () : cv_quota_match.int_ ();
|
int detectQuotaMatch = cv_quota_match.as <int> () == 0 ? cv_quota.as <int> () : cv_quota_match.as <int> ();
|
||||||
|
|
||||||
desiredBotCount = cr::max <int> (0, detectQuotaMatch * humanPlayersInGame);
|
desiredBotCount = cr::max <int> (0, detectQuotaMatch * humanPlayersInGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cv_join_after_player.bool_ () && humanPlayersInGame == 0) {
|
if (cv_join_after_player && humanPlayersInGame == 0) {
|
||||||
desiredBotCount = 0;
|
desiredBotCount = 0;
|
||||||
}
|
}
|
||||||
int maxClients = game.maxClients ();
|
int maxClients = game.maxClients ();
|
||||||
|
|
||||||
if (cv_autovacate.bool_ ()) {
|
if (cv_autovacate) {
|
||||||
if (cv_kick_after_player_connect.bool_ ()) {
|
if (cv_kick_after_player_connect) {
|
||||||
desiredBotCount = cr::min <int> (desiredBotCount, maxClients - (totalHumansInGame + cv_autovacate_keep_slots.int_ ()));
|
desiredBotCount = cr::min <int> (desiredBotCount, maxClients - (totalHumansInGame + cv_autovacate_keep_slots.as <int> ()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
desiredBotCount = cr::min <int> (desiredBotCount, maxClients - (humanPlayersInGame + cv_autovacate_keep_slots.int_ ()));
|
desiredBotCount = cr::min <int> (desiredBotCount, maxClients - (humanPlayersInGame + cv_autovacate_keep_slots.as <int> ()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -482,11 +482,11 @@ void BotManager::maintainQuota () {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// clear the saved names when quota balancing ended
|
// clear the saved names when quota balancing ended
|
||||||
if (cv_save_bots_names.bool_ () && !m_saveBotNames.empty ()) {
|
if (cv_save_bots_names && !m_saveBotNames.empty ()) {
|
||||||
m_saveBotNames.clear ();
|
m_saveBotNames.clear ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_quotaMaintainTime = game.time () + cv_quota_maintain_interval.float_ ();
|
m_quotaMaintainTime = game.time () + cv_quota_maintain_interval.as <float> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotManager::maintainLeaders () {
|
void BotManager::maintainLeaders () {
|
||||||
|
|
@ -503,7 +503,7 @@ void BotManager::maintainLeaders () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotManager::maintainAutoKill () {
|
void BotManager::maintainAutoKill () {
|
||||||
const float killDelay = cv_autokill_delay.float_ ();
|
const float killDelay = cv_autokill_delay.as <float> ();
|
||||||
|
|
||||||
if (killDelay < 1.0f || m_roundOver) {
|
if (killDelay < 1.0f || m_roundOver) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -594,15 +594,15 @@ void BotManager::resetFilters () {
|
||||||
|
|
||||||
void BotManager::decrementQuota (int by) {
|
void BotManager::decrementQuota (int by) {
|
||||||
if (by != 0) {
|
if (by != 0) {
|
||||||
cv_quota.set (cr::clamp <int> (cv_quota.int_ () - by, 0, cv_quota.int_ ()));
|
cv_quota.set (cr::clamp <int> (cv_quota.as <int> () - by, 0, cv_quota.as <int> ()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cv_quota.set (0);
|
cv_quota.set (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotManager::initQuota () {
|
void BotManager::initQuota () {
|
||||||
m_maintainTime = game.time () + cv_join_delay.float_ ();
|
m_maintainTime = game.time () + cv_join_delay.as <float> ();
|
||||||
m_quotaMaintainTime = game.time () + cv_join_delay.float_ ();
|
m_quotaMaintainTime = game.time () + cv_join_delay.as <float> ();
|
||||||
|
|
||||||
m_addRequests.clear ();
|
m_addRequests.clear ();
|
||||||
}
|
}
|
||||||
|
|
@ -611,8 +611,8 @@ void BotManager::serverFill (int selection, int personality, int difficulty, int
|
||||||
// this function fill server with bots, with specified team & personality
|
// this function fill server with bots, with specified team & personality
|
||||||
|
|
||||||
// always keep one slot
|
// always keep one slot
|
||||||
const int maxClients = cv_autovacate.bool_ ()
|
const int maxClients = cv_autovacate
|
||||||
? game.maxClients () - cv_autovacate_keep_slots.int_ () - (game.isDedicated () ? 0 : getHumansCount ()) : game.maxClients ();
|
? game.maxClients () - cv_autovacate_keep_slots.as <int> () - (game.isDedicated () ? 0 : getHumansCount ()) : game.maxClients ();
|
||||||
|
|
||||||
if (getBotCount () >= maxClients - getHumansCount ()) {
|
if (getBotCount () >= maxClients - getHumansCount ()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -636,7 +636,7 @@ void BotManager::serverFill (int selection, int personality, int difficulty, int
|
||||||
void BotManager::kickEveryone (bool instant, bool zeroQuota) {
|
void BotManager::kickEveryone (bool instant, bool zeroQuota) {
|
||||||
// this function drops all bot clients from server (this function removes only yapb's)
|
// this function drops all bot clients from server (this function removes only yapb's)
|
||||||
|
|
||||||
if (cv_quota.bool_ () && hasBotsOnline ()) {
|
if (cv_quota && hasBotsOnline ()) {
|
||||||
ctrl.msg ("Bots are removed from server.");
|
ctrl.msg ("Bots are removed from server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -645,7 +645,7 @@ void BotManager::kickEveryone (bool instant, bool zeroQuota) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if everyone is kicked, clear the saved bot names
|
// if everyone is kicked, clear the saved bot names
|
||||||
if (cv_save_bots_names.bool_ () && !m_saveBotNames.empty ()) {
|
if (cv_save_bots_names && !m_saveBotNames.empty ()) {
|
||||||
m_saveBotNames.clear ();
|
m_saveBotNames.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -794,7 +794,7 @@ void BotManager::setLastWinner (int winner) {
|
||||||
m_lastWinner = winner;
|
m_lastWinner = winner;
|
||||||
m_roundOver = true;
|
m_roundOver = true;
|
||||||
|
|
||||||
if (cv_radio_mode.int_ () != 2) {
|
if (cv_radio_mode.as <int> () != 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto notify = findAliveBot ();
|
auto notify = findAliveBot ();
|
||||||
|
|
@ -893,7 +893,7 @@ void BotManager::listBots () {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &bot : bots) {
|
for (const auto &bot : bots) {
|
||||||
auto timelimitStr = cv_rotate_bots.bool_ () ? strings.format ("%-3.0f secs", bot->m_stayTime - game.time ()) : "unlimited";
|
auto timelimitStr = cv_rotate_bots ? strings.format ("%-3.0f secs", bot->m_stayTime - game.time ()) : "unlimited";
|
||||||
|
|
||||||
ctrl.msg ("[%-2.1d]\t%-22.16s\t%-10.12s\t%-3.4s\t%-3.1d\t%-3.1d\t%-3.4s\t%s",
|
ctrl.msg ("[%-2.1d]\t%-22.16s\t%-10.12s\t%-3.4s\t%-3.1d\t%-3.1d\t%-3.4s\t%s",
|
||||||
bot->index (), bot->pev->netname.chars (), bot->m_personality == Personality::Rusher ? "rusher" : bot->m_personality == Personality::Normal ? "normal" : "careful",
|
bot->index (), bot->pev->netname.chars (), bot->m_personality == Personality::Rusher ? "rusher" : bot->m_personality == Personality::Normal ? "normal" : "careful",
|
||||||
|
|
@ -975,7 +975,7 @@ void BotManager::updateTeamEconomics (int team, bool setTrue) {
|
||||||
// that have not enough money to buy primary (with economics), and if this result higher 80%, player is can't
|
// that have not enough money to buy primary (with economics), and if this result higher 80%, player is can't
|
||||||
// buy primary weapons.
|
// buy primary weapons.
|
||||||
|
|
||||||
if (setTrue || !cv_economics_rounds.bool_ ()) {
|
if (setTrue || !cv_economics_rounds) {
|
||||||
m_economicsGood[team] = true;
|
m_economicsGood[team] = true;
|
||||||
return; // don't check economics while economics disable
|
return; // don't check economics while economics disable
|
||||||
}
|
}
|
||||||
|
|
@ -1011,10 +1011,10 @@ void BotManager::updateTeamEconomics (int team, bool setTrue) {
|
||||||
|
|
||||||
void BotManager::updateBotDifficulties () {
|
void BotManager::updateBotDifficulties () {
|
||||||
// if min/max difficulty is specified this should not have effect
|
// if min/max difficulty is specified this should not have effect
|
||||||
if (cv_difficulty_min.int_ () != Difficulty::Invalid || cv_difficulty_max.int_ () != Difficulty::Invalid || cv_difficulty_auto.bool_ ()) {
|
if (cv_difficulty_min.as <int> () != Difficulty::Invalid || cv_difficulty_max.as <int> () != Difficulty::Invalid || cv_difficulty_auto) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto difficulty = cv_difficulty.int_ ();
|
const auto difficulty = cv_difficulty.as <int> ();
|
||||||
|
|
||||||
if (difficulty != m_lastDifficulty) {
|
if (difficulty != m_lastDifficulty) {
|
||||||
|
|
||||||
|
|
@ -1033,11 +1033,11 @@ void BotManager::balanceBotDifficulties () {
|
||||||
};
|
};
|
||||||
|
|
||||||
// with nightmare difficulty, there is no balance
|
// with nightmare difficulty, there is no balance
|
||||||
if (cv_whose_your_daddy.bool_ ()) {
|
if (cv_whose_your_daddy) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cv_difficulty_auto.bool_ () && m_difficultyBalanceTime < game.time ()) {
|
if (cv_difficulty_auto && m_difficultyBalanceTime < game.time ()) {
|
||||||
const auto ratioPlayer = getAverageTeamKPD (false);
|
const auto ratioPlayer = getAverageTeamKPD (false);
|
||||||
const auto ratioBots = getAverageTeamKPD (true);
|
const auto ratioBots = getAverageTeamKPD (true);
|
||||||
|
|
||||||
|
|
@ -1053,7 +1053,7 @@ void BotManager::balanceBotDifficulties () {
|
||||||
updateDifficulty (bot.get (), -1);
|
updateDifficulty (bot.get (), -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_difficultyBalanceTime = game.time () + cv_difficulty_auto_balance_interval.float_ ();
|
m_difficultyBalanceTime = game.time () + cv_difficulty_auto_balance_interval.as <float> ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1090,12 +1090,12 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
|
||||||
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "_ah", "0");
|
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "_ah", "0");
|
||||||
|
|
||||||
if (!game.is (GameFlags::Legacy)) {
|
if (!game.is (GameFlags::Legacy)) {
|
||||||
if (cv_show_latency.int_ () == 1) {
|
if (cv_show_latency.as <int> () == 1) {
|
||||||
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*bot", "1");
|
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*bot", "1");
|
||||||
}
|
}
|
||||||
auto avatar = conf.getRandomAvatar ();
|
auto avatar = conf.getRandomAvatar ();
|
||||||
|
|
||||||
if (cv_show_avatars.bool_ () && !avatar.empty ()) {
|
if (cv_show_avatars && !avatar.empty ()) {
|
||||||
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*sid", avatar.chars ());
|
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*sid", avatar.chars ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1124,32 +1124,32 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
|
||||||
m_moneyAmount = 0;
|
m_moneyAmount = 0;
|
||||||
m_logotypeIndex = conf.getRandomLogoIndex ();
|
m_logotypeIndex = conf.getRandomLogoIndex ();
|
||||||
|
|
||||||
if (cv_rotate_bots.bool_ ()) {
|
if (cv_rotate_bots) {
|
||||||
m_stayTime = game.time () + rg.get (cv_rotate_stay_min.float_ (), cv_rotate_stay_max.float_ ());
|
m_stayTime = game.time () + rg (cv_rotate_stay_min.as <float> (), cv_rotate_stay_max.as <float> ());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_stayTime = game.time () + kInfiniteDistance;
|
m_stayTime = game.time () + kInfiniteDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign how talkative this bot will be
|
// assign how talkative this bot will be
|
||||||
m_sayTextBuffer.chatDelay = rg.get (3.8f, 10.0f);
|
m_sayTextBuffer.chatDelay = rg (3.8f, 10.0f);
|
||||||
m_sayTextBuffer.chatProbability = rg.get (10, 100);
|
m_sayTextBuffer.chatProbability = rg (10, 100);
|
||||||
|
|
||||||
m_isAlive = false;
|
m_isAlive = false;
|
||||||
m_weaponBurstMode = BurstMode::Off;
|
m_weaponBurstMode = BurstMode::Off;
|
||||||
m_difficulty = cr::clamp (static_cast <Difficulty> (difficulty), Difficulty::Noob, Difficulty::Expert);
|
m_difficulty = cr::clamp (static_cast <Difficulty> (difficulty), Difficulty::Noob, Difficulty::Expert);
|
||||||
|
|
||||||
auto minDifficulty = cv_difficulty_min.int_ ();
|
auto minDifficulty = cv_difficulty_min.as <int> ();
|
||||||
auto maxDifficulty = cv_difficulty_max.int_ ();
|
auto maxDifficulty = cv_difficulty_max.as <int> ();
|
||||||
|
|
||||||
// if we're have min/max difficulty specified, choose value from they
|
// if we're have min/max difficulty specified, choose value from they
|
||||||
if (minDifficulty != Difficulty::Invalid && maxDifficulty != Difficulty::Invalid) {
|
if (minDifficulty != Difficulty::Invalid && maxDifficulty != Difficulty::Invalid) {
|
||||||
if (maxDifficulty > minDifficulty) {
|
if (maxDifficulty > minDifficulty) {
|
||||||
cr::swap (maxDifficulty, minDifficulty);
|
cr::swap (maxDifficulty, minDifficulty);
|
||||||
}
|
}
|
||||||
m_difficulty = rg.get (minDifficulty, maxDifficulty);
|
m_difficulty = rg (minDifficulty, maxDifficulty);
|
||||||
}
|
}
|
||||||
m_basePing = rg.get (cv_ping_base_min.int_ (), cv_ping_base_max.int_ ());
|
m_basePing = rg (cv_ping_base_min.as <int> (), cv_ping_base_max.as <int> ());
|
||||||
|
|
||||||
m_previousThinkTime = game.time () - 0.1f;
|
m_previousThinkTime = game.time () - 0.1f;
|
||||||
m_frameInterval = game.time ();
|
m_frameInterval = game.time ();
|
||||||
|
|
@ -1158,26 +1158,26 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
|
||||||
m_kpdRatio = 0.0f;
|
m_kpdRatio = 0.0f;
|
||||||
|
|
||||||
// stuff from jk_botti
|
// stuff from jk_botti
|
||||||
m_playServerTime = 60.0f * rg.get (30.0f, 240.0f);
|
m_playServerTime = 60.0f * rg (30.0f, 240.0f);
|
||||||
m_joinServerTime = plat.seconds () - m_playServerTime * rg.get (0.2f, 0.8f);
|
m_joinServerTime = plat.seconds () - m_playServerTime * rg (0.2f, 0.8f);
|
||||||
|
|
||||||
switch (personality) {
|
switch (personality) {
|
||||||
case 1:
|
case 1:
|
||||||
m_personality = Personality::Rusher;
|
m_personality = Personality::Rusher;
|
||||||
m_baseAgressionLevel = rg.get (0.7f, 1.0f);
|
m_baseAgressionLevel = rg (0.7f, 1.0f);
|
||||||
m_baseFearLevel = rg.get (0.0f, 0.4f);
|
m_baseFearLevel = rg (0.0f, 0.4f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
m_personality = Personality::Careful;
|
m_personality = Personality::Careful;
|
||||||
m_baseAgressionLevel = rg.get (0.2f, 0.5f);
|
m_baseAgressionLevel = rg (0.2f, 0.5f);
|
||||||
m_baseFearLevel = rg.get (0.7f, 1.0f);
|
m_baseFearLevel = rg (0.7f, 1.0f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
m_personality = Personality::Normal;
|
m_personality = Personality::Normal;
|
||||||
m_baseAgressionLevel = rg.get (0.4f, 0.7f);
|
m_baseAgressionLevel = rg (0.4f, 0.7f);
|
||||||
m_baseFearLevel = rg.get (0.4f, 0.7f);
|
m_baseFearLevel = rg (0.4f, 0.7f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1187,7 +1187,7 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
|
||||||
m_currentWeapon = 0; // current weapon is not assigned at start
|
m_currentWeapon = 0; // current weapon is not assigned at start
|
||||||
m_weaponType = WeaponType::None; // current weapon type is not assigned at start
|
m_weaponType = WeaponType::None; // current weapon type is not assigned at start
|
||||||
|
|
||||||
m_voicePitch = rg.get (80, 115); // assign voice pitch
|
m_voicePitch = rg (80, 115); // assign voice pitch
|
||||||
|
|
||||||
// copy them over to the temp level variables
|
// copy them over to the temp level variables
|
||||||
m_agressionLevel = m_baseAgressionLevel;
|
m_agressionLevel = m_baseAgressionLevel;
|
||||||
|
|
@ -1220,8 +1220,8 @@ float Bot::getConnectionTime () {
|
||||||
const auto current = plat.seconds ();
|
const auto current = plat.seconds ();
|
||||||
|
|
||||||
if (current - m_joinServerTime > m_playServerTime || current - m_joinServerTime <= 0.0f) {
|
if (current - m_joinServerTime > m_playServerTime || current - m_joinServerTime <= 0.0f) {
|
||||||
m_playServerTime = 60.0f * rg.get (30.0f, 240.0f);
|
m_playServerTime = 60.0f * rg (30.0f, 240.0f);
|
||||||
m_joinServerTime = current - m_playServerTime * rg.get (0.2f, 0.8f);
|
m_joinServerTime = current - m_playServerTime * rg (0.2f, 0.8f);
|
||||||
}
|
}
|
||||||
return current - m_joinServerTime;
|
return current - m_joinServerTime;
|
||||||
}
|
}
|
||||||
|
|
@ -1283,7 +1283,7 @@ bool BotManager::isTeamStacked (int team) {
|
||||||
if (team != Team::CT && team != Team::Terrorist) {
|
if (team != Team::CT && team != Team::Terrorist) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const int limitTeams = mp_limitteams.int_ ();
|
const int limitTeams = mp_limitteams.as <int> ();
|
||||||
|
|
||||||
if (!limitTeams) {
|
if (!limitTeams) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1304,7 +1304,7 @@ void BotManager::erase (Bot *bot) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bot->m_kickedByRotation && cv_save_bots_names.bool_ ()) {
|
if (!bot->m_kickedByRotation && cv_save_bots_names) {
|
||||||
m_saveBotNames.emplaceLast (bot->pev->netname.str ());
|
m_saveBotNames.emplaceLast (bot->pev->netname.str ());
|
||||||
}
|
}
|
||||||
bot->markStale ();
|
bot->markStale ();
|
||||||
|
|
@ -1321,7 +1321,7 @@ void BotManager::handleDeath (edict_t *killer, edict_t *victim) {
|
||||||
const auto killerTeam = game.getRealTeam (killer);
|
const auto killerTeam = game.getRealTeam (killer);
|
||||||
const auto victimTeam = game.getRealTeam (victim);
|
const auto victimTeam = game.getRealTeam (victim);
|
||||||
|
|
||||||
if (cv_radio_mode.int_ () == 2) {
|
if (cv_radio_mode.as <int> () == 2) {
|
||||||
// need to send congrats on well placed shot
|
// need to send congrats on well placed shot
|
||||||
for (const auto ¬ify : bots) {
|
for (const auto ¬ify : bots) {
|
||||||
if (notify->m_isAlive
|
if (notify->m_isAlive
|
||||||
|
|
@ -1443,14 +1443,14 @@ void Bot::newRound () {
|
||||||
m_preventFlashing = 0.0f;
|
m_preventFlashing = 0.0f;
|
||||||
|
|
||||||
m_timeTeamOrder = 0.0f;
|
m_timeTeamOrder = 0.0f;
|
||||||
m_askCheckTime = rg.get (30.0f, 90.0f);
|
m_askCheckTime = rg (30.0f, 90.0f);
|
||||||
m_minSpeed = 260.0f;
|
m_minSpeed = 260.0f;
|
||||||
m_prevSpeed = 0.0f;
|
m_prevSpeed = 0.0f;
|
||||||
m_prevVelocity = 0.0f;
|
m_prevVelocity = 0.0f;
|
||||||
m_prevOrigin = Vector (kInfiniteDistance, kInfiniteDistance, kInfiniteDistance);
|
m_prevOrigin = Vector (kInfiniteDistance, kInfiniteDistance, kInfiniteDistance);
|
||||||
m_prevTime = game.time ();
|
m_prevTime = game.time ();
|
||||||
m_lookUpdateTime = game.time ();
|
m_lookUpdateTime = game.time ();
|
||||||
m_changeViewTime = game.time () + (rg.chance (25) ? mp_freezetime.float_ () : 0.0f);
|
m_changeViewTime = game.time () + (rg.chance (25) ? mp_freezetime.as <float> () : 0.0f);
|
||||||
m_aimErrorTime = game.time ();
|
m_aimErrorTime = game.time ();
|
||||||
|
|
||||||
m_viewDistance = Frustum::kMaxViewDistance;
|
m_viewDistance = Frustum::kMaxViewDistance;
|
||||||
|
|
@ -1555,8 +1555,8 @@ void Bot::newRound () {
|
||||||
m_flashLevel = 100;
|
m_flashLevel = 100;
|
||||||
m_checkDarkTime = game.time ();
|
m_checkDarkTime = game.time ();
|
||||||
|
|
||||||
m_knifeAttackTime = game.time () + rg.get (1.3f, 2.6f);
|
m_knifeAttackTime = game.time () + rg (1.3f, 2.6f);
|
||||||
m_nextBuyTime = game.time () + rg.get (0.6f, 2.0f);
|
m_nextBuyTime = game.time () + rg (0.6f, 2.0f);
|
||||||
|
|
||||||
m_buyPending = false;
|
m_buyPending = false;
|
||||||
m_inBombZone = false;
|
m_inBombZone = false;
|
||||||
|
|
@ -1568,7 +1568,7 @@ void Bot::newRound () {
|
||||||
m_shieldCheckTime = 0.0f;
|
m_shieldCheckTime = 0.0f;
|
||||||
m_zoomCheckTime = 0.0f;
|
m_zoomCheckTime = 0.0f;
|
||||||
m_strafeSetTime = 0.0f;
|
m_strafeSetTime = 0.0f;
|
||||||
m_combatStrafeDir = Dodge::None;
|
m_dodgeStrafeDir = Dodge::None;
|
||||||
m_fightStyle = Fight::None;
|
m_fightStyle = Fight::None;
|
||||||
m_lastFightStyleCheck = 0.0f;
|
m_lastFightStyleCheck = 0.0f;
|
||||||
m_stuckTimestamp = 0.0f;
|
m_stuckTimestamp = 0.0f;
|
||||||
|
|
@ -1583,7 +1583,7 @@ void Bot::newRound () {
|
||||||
m_defendHostage = false;
|
m_defendHostage = false;
|
||||||
m_headedTime = 0.0f;
|
m_headedTime = 0.0f;
|
||||||
|
|
||||||
m_timeLogoSpray = game.time () + rg.get (5.0f, 30.0f);
|
m_timeLogoSpray = game.time () + rg (5.0f, 30.0f);
|
||||||
m_spawnTime = game.time ();
|
m_spawnTime = game.time ();
|
||||||
m_lastChatTime = game.time ();
|
m_lastChatTime = game.time ();
|
||||||
|
|
||||||
|
|
@ -1600,8 +1600,8 @@ void Bot::newRound () {
|
||||||
m_ignoredBreakable.clear ();
|
m_ignoredBreakable.clear ();
|
||||||
|
|
||||||
// ignore enemies for some time if needed
|
// ignore enemies for some time if needed
|
||||||
if (cv_ignore_enemies_after_spawn_time.float_ () > 0.0f) {
|
if (cv_ignore_enemies_after_spawn_time.as <float> () > 0.0f) {
|
||||||
m_enemyIgnoreTimer = game.time () + cv_ignore_enemies_after_spawn_time.float_ ();
|
m_enemyIgnoreTimer = game.time () + cv_ignore_enemies_after_spawn_time.as <float> ();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_enemyIgnoreTimer = 0.0f;
|
m_enemyIgnoreTimer = 0.0f;
|
||||||
|
|
@ -1620,11 +1620,11 @@ void Bot::newRound () {
|
||||||
if (rg.chance (50)) {
|
if (rg.chance (50)) {
|
||||||
pushChatterMessage (Chatter::NewRound);
|
pushChatterMessage (Chatter::NewRound);
|
||||||
}
|
}
|
||||||
auto thinkFps = cr::clamp (cv_think_fps.float_ (), 30.0f, 90.0f);
|
auto thinkFps = cr::clamp (cv_think_fps.as <float> (), 30.0f, 90.0f);
|
||||||
auto updateInterval = 1.0f / thinkFps;
|
auto updateInterval = 1.0f / thinkFps;
|
||||||
|
|
||||||
if (game.is (GameFlags::Xash3D)) {
|
if (game.is (GameFlags::Xash3D)) {
|
||||||
if (cv_think_fps_disable.bool_ ()) {
|
if (cv_think_fps_disable) {
|
||||||
updateInterval = 0.0f;
|
updateInterval = 0.0f;
|
||||||
}
|
}
|
||||||
else if (thinkFps < 50) {
|
else if (thinkFps < 50) {
|
||||||
|
|
@ -1657,7 +1657,7 @@ void Bot::resetPathSearchType () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if debug goal - set the fastest
|
// if debug goal - set the fastest
|
||||||
if (cv_debug_goal.int_ () != kInvalidNodeIndex) {
|
if (cv_debug_goal.as <int> () != kInvalidNodeIndex) {
|
||||||
m_pathType = FindPath::Fast;
|
m_pathType = FindPath::Fast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1749,7 +1749,7 @@ void Bot::updateTeamJoin () {
|
||||||
m_startAction = BotMsg::None; // switch back to idle
|
m_startAction = BotMsg::None; // switch back to idle
|
||||||
|
|
||||||
if (m_wantedTeam == -1) {
|
if (m_wantedTeam == -1) {
|
||||||
char teamJoin = cv_join_team.str ()[0];
|
char teamJoin = cv_join_team.as <StringRef> ()[0];
|
||||||
|
|
||||||
if (teamJoin == 'C' || teamJoin == 'c') {
|
if (teamJoin == 'C' || teamJoin == 'c') {
|
||||||
m_wantedTeam = 2;
|
m_wantedTeam = 2;
|
||||||
|
|
@ -1772,7 +1772,7 @@ void Bot::updateTeamJoin () {
|
||||||
m_wantedTeam = 1;
|
m_wantedTeam = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_wantedTeam = rg.get (1, 2);
|
m_wantedTeam = rg (1, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1788,16 +1788,16 @@ void Bot::updateTeamJoin () {
|
||||||
|
|
||||||
// setup enforced skin based on selected team
|
// setup enforced skin based on selected team
|
||||||
if (m_wantedTeam == 1 || botTeam == Team::Terrorist) {
|
if (m_wantedTeam == 1 || botTeam == Team::Terrorist) {
|
||||||
enforcedSkin = cv_botskin_t.int_ ();
|
enforcedSkin = cv_botskin_t.as <int> ();
|
||||||
}
|
}
|
||||||
else if (m_wantedTeam == 2 || botTeam == Team::CT) {
|
else if (m_wantedTeam == 2 || botTeam == Team::CT) {
|
||||||
enforcedSkin = cv_botskin_ct.int_ ();
|
enforcedSkin = cv_botskin_ct.as <int> ();
|
||||||
}
|
}
|
||||||
enforcedSkin = cr::clamp (enforcedSkin, 0, maxChoice);
|
enforcedSkin = cr::clamp (enforcedSkin, 0, maxChoice);
|
||||||
|
|
||||||
// try to choice manually
|
// try to choice manually
|
||||||
if (m_wantedSkin < 1 || m_wantedSkin > maxChoice) {
|
if (m_wantedSkin < 1 || m_wantedSkin > maxChoice) {
|
||||||
m_wantedSkin = rg.get (1, maxChoice); // use random if invalid
|
m_wantedSkin = rg (1, maxChoice); // use random if invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
// and set enforced if any
|
// and set enforced if any
|
||||||
|
|
@ -1852,7 +1852,7 @@ void BotManager::captureChatRadio (StringRef cmd, StringRef arg, edict_t *ent) {
|
||||||
|
|
||||||
// check if this player alive, and issue something
|
// check if this player alive, and issue something
|
||||||
if ((target.flags & ClientFlags::Alive) && target.radio != 0 && cmd.startsWith ("menuselect")) {
|
if ((target.flags & ClientFlags::Alive) && target.radio != 0 && cmd.startsWith ("menuselect")) {
|
||||||
auto radioCommand = arg.int_ ();
|
auto radioCommand = arg.as <int> ();
|
||||||
|
|
||||||
if (radioCommand != 0) {
|
if (radioCommand != 0) {
|
||||||
radioCommand += 10 * (target.radio - 1);
|
radioCommand += 10 * (target.radio - 1);
|
||||||
|
|
@ -1872,7 +1872,7 @@ void BotManager::captureChatRadio (StringRef cmd, StringRef arg, edict_t *ent) {
|
||||||
target.radio = 0;
|
target.radio = 0;
|
||||||
}
|
}
|
||||||
else if (cmd.startsWith ("radio")) {
|
else if (cmd.startsWith ("radio")) {
|
||||||
target.radio = cmd.substr (5).int_ ();
|
target.radio = cmd.substr (5).as <int> ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1890,7 +1890,7 @@ void BotManager::notifyBombDefuse () {
|
||||||
&& task != Task::DefuseBomb
|
&& task != Task::DefuseBomb
|
||||||
&& task != Task::EscapeFromBomb) {
|
&& task != Task::EscapeFromBomb) {
|
||||||
|
|
||||||
if (bot->m_team == Team::Terrorist && bot->pev->origin.distanceSq (bombPos) < cr::sqrf (384.0f)) {
|
if (bot->m_team == Team::Terrorist && bot->pev->origin.distanceSq (bombPos) < cr::sqrf (512.0f)) {
|
||||||
bot->clearSearchNodes ();
|
bot->clearSearchNodes ();
|
||||||
|
|
||||||
bot->m_pathType = FindPath::Fast;
|
bot->m_pathType = FindPath::Fast;
|
||||||
|
|
@ -1955,7 +1955,7 @@ void BotManager::updateInterestingEntities () {
|
||||||
m_interestingEntities.push (e);
|
m_interestingEntities.push (e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cv_attack_monsters.bool_ () && util.isMonster (e)) {
|
if (cv_attack_monsters && util.isMonster (e)) {
|
||||||
m_interestingEntities.push (e);
|
m_interestingEntities.push (e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2012,7 +2012,7 @@ void BotManager::selectLeaders (int team, bool reset) {
|
||||||
|
|
||||||
// terrorist carrying a bomb needs to have some company
|
// terrorist carrying a bomb needs to have some company
|
||||||
if (rg.chance (75)) {
|
if (rg.chance (75)) {
|
||||||
if (cv_radio_mode.int_ () == 2) {
|
if (cv_radio_mode.as <int> () == 2) {
|
||||||
bot->pushChatterMessage (Chatter::GoingToPlantBomb);
|
bot->pushChatterMessage (Chatter::GoingToPlantBomb);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -2098,13 +2098,13 @@ void BotManager::initRound () {
|
||||||
practice.update (); // update practice data on round start
|
practice.update (); // update practice data on round start
|
||||||
|
|
||||||
// calculate the round mid/end in world time
|
// calculate the round mid/end in world time
|
||||||
m_timeRoundStart = game.time () + mp_freezetime.float_ ();
|
m_timeRoundStart = game.time () + mp_freezetime.as <float> ();
|
||||||
m_timeRoundMid = m_timeRoundStart + mp_roundtime.float_ () * 60.0f * 0.5f;
|
m_timeRoundMid = m_timeRoundStart + mp_roundtime.as <float> () * 60.0f * 0.5f;
|
||||||
m_timeRoundEnd = m_timeRoundStart + mp_roundtime.float_ () * 60.0f;
|
m_timeRoundEnd = m_timeRoundStart + mp_roundtime.as <float> () * 60.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotManager::setBombPlanted (bool isPlanted) {
|
void BotManager::setBombPlanted (bool isPlanted) {
|
||||||
if (cv_ignore_objectives.bool_ ()) {
|
if (cv_ignore_objectives) {
|
||||||
m_bombPlanted = false;
|
m_bombPlanted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ void MessageDispatcher::netMsgTextMsg () {
|
||||||
|
|
||||||
// set balance for all players
|
// set balance for all players
|
||||||
bots.forEach ([] (Bot *bot) {
|
bots.forEach ([] (Bot *bot) {
|
||||||
bot->m_moneyAmount = mp_startmoney.int_ ();
|
bot->m_moneyAmount = mp_startmoney.as <int> ();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ void MessageDispatcher::netMsgTextMsg () {
|
||||||
// clear only camp tasks
|
// clear only camp tasks
|
||||||
notify->clearTask (Task::Camp);
|
notify->clearTask (Task::Camp);
|
||||||
|
|
||||||
if (cv_radio_mode.int_ () == 2 && rg.chance (55) && notify->m_team == Team::CT) {
|
if (cv_radio_mode.as <int> () == 2 && rg.chance (55) && notify->m_team == Team::CT) {
|
||||||
notify->pushChatterMessage (Chatter::WhereIsTheC4);
|
notify->pushChatterMessage (Chatter::WhereIsTheC4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
126
src/navigate.cpp
126
src/navigate.cpp
|
|
@ -163,11 +163,11 @@ int Bot::findBestGoal () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const float goalDesire = rg.get (0.0f, 100.0f) + offensive;
|
const float goalDesire = rg (0.0f, 100.0f) + offensive;
|
||||||
const float forwardDesire = rg.get (0.0f, 100.0f) + offensive;
|
const float forwardDesire = rg (0.0f, 100.0f) + offensive;
|
||||||
const float backoffDesire = rg.get (0.0f, 100.0f) + defensive;
|
const float backoffDesire = rg (0.0f, 100.0f) + defensive;
|
||||||
|
|
||||||
float campDesire = rg.get (0.0f, 100.0f) + defensive;
|
float campDesire = rg (0.0f, 100.0f) + defensive;
|
||||||
|
|
||||||
if (!usesCampGun ()) {
|
if (!usesCampGun ()) {
|
||||||
campDesire *= 0.5f;
|
campDesire *= 0.5f;
|
||||||
|
|
@ -226,7 +226,7 @@ int Bot::findBestGoalWhenBombAction () {
|
||||||
result = findDefendNode (bombOrigin);
|
result = findDefendNode (bombOrigin);
|
||||||
const Path &path = graph[result];
|
const Path &path = graph[result];
|
||||||
|
|
||||||
const float bombTimer = mp_c4timer.float_ ();
|
const float bombTimer = mp_c4timer.as <float> ();
|
||||||
const float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
|
const float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
|
||||||
|
|
||||||
if (timeMidBlowup > game.time ()) {
|
if (timeMidBlowup > game.time ()) {
|
||||||
|
|
@ -334,7 +334,7 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offensive) {
|
||||||
|
|
||||||
// rusher bots does not care any danger (idea from pbmm)
|
// rusher bots does not care any danger (idea from pbmm)
|
||||||
if (m_personality == Personality::Rusher) {
|
if (m_personality == Personality::Rusher) {
|
||||||
const auto randomGoal = goalChoices[rg.get (0, 3)];
|
const auto randomGoal = goalChoices[rg (0, 3)];
|
||||||
|
|
||||||
if (graph.exists (randomGoal)) {
|
if (graph.exists (randomGoal)) {
|
||||||
return m_chosenGoalIndex = randomGoal;
|
return m_chosenGoalIndex = randomGoal;
|
||||||
|
|
@ -454,7 +454,7 @@ void Bot::ignoreCollision () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::doPlayerAvoidance (const Vector &normal) {
|
void Bot::doPlayerAvoidance (const Vector &normal) {
|
||||||
if (cv_has_team_semiclip.bool_ () || game.is (GameFlags::FreeForAll)) {
|
if (cv_has_team_semiclip || game.is (GameFlags::FreeForAll)) {
|
||||||
return; // no player avoiding when with semiclip plugin
|
return; // no player avoiding when with semiclip plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -517,7 +517,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
|
||||||
|
|
||||||
// is player that near now or in future that we need to steer away?
|
// is player that near now or in future that we need to steer away?
|
||||||
if (movedDistanceSq <= cr::sqrf (64.0f) || (distanceSq <= cr::sqrf (72.0f) && nextFrameDistanceSq < distanceSq)) {
|
if (movedDistanceSq <= cr::sqrf (64.0f) || (distanceSq <= cr::sqrf (72.0f) && nextFrameDistanceSq < distanceSq)) {
|
||||||
auto dir = (pev->origin - m_hindrance->v.origin).normalize2d_apx ();
|
const auto &dir = (pev->origin - m_hindrance->v.origin).normalize2d_apx ();
|
||||||
|
|
||||||
// to start strafing, we have to first figure out if the target is on the left side or right side
|
// to start strafing, we have to first figure out if the target is on the left side or right side
|
||||||
if ((dir | right.normalize2d_apx ()) > 0.0f) {
|
if ((dir | right.normalize2d_apx ()) > 0.0f) {
|
||||||
|
|
@ -570,7 +570,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
|
||||||
|
|
||||||
// not stuck?
|
// not stuck?
|
||||||
if (!m_isStuck) {
|
if (!m_isStuck) {
|
||||||
if (m_probeTime + rg.get (0.75f, 1.15f) < game.time ()) {
|
if (m_probeTime + rg (0.75f, 1.15f) < game.time ()) {
|
||||||
resetCollision (); // reset collision memory if not being stuck for 0.5 secs
|
resetCollision (); // reset collision memory if not being stuck for 0.5 secs
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -928,7 +928,7 @@ bool Bot::updateNavigation () {
|
||||||
// pressing the jump button gives the illusion of the bot actual jumping.
|
// pressing the jump button gives the illusion of the bot actual jumping.
|
||||||
if (isOnFloor () || isOnLadder ()) {
|
if (isOnFloor () || isOnLadder ()) {
|
||||||
if (m_desiredVelocity.length2d () > 0.0f) {
|
if (m_desiredVelocity.length2d () > 0.0f) {
|
||||||
pev->velocity = m_desiredVelocity + m_desiredVelocity * m_frameInterval;
|
pev->velocity = m_desiredVelocity;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto feet = pev->origin + pev->mins;
|
auto feet = pev->origin + pev->mins;
|
||||||
|
|
@ -965,12 +965,12 @@ bool Bot::updateNavigation () {
|
||||||
|
|
||||||
// cool down a little if next path after current will be jump
|
// cool down a little if next path after current will be jump
|
||||||
if (m_jumpSequence) {
|
if (m_jumpSequence) {
|
||||||
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg.get (0.75, 1.2f) + m_frameInterval, false);
|
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg (0.75f, 1.2f) + m_frameInterval, false);
|
||||||
m_jumpSequence = false;
|
m_jumpSequence = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!cv_jasonmode.bool_ () && usesKnife () && isOnFloor () && getCurrentTaskId () != Task::EscapeFromBomb) {
|
else if (!cv_jasonmode && usesKnife () && isOnFloor () && getCurrentTaskId () != Task::EscapeFromBomb) {
|
||||||
selectBestWeapon ();
|
selectBestWeapon ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1031,7 +1031,7 @@ bool Bot::updateNavigation () {
|
||||||
&& cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f
|
&& cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f
|
||||||
&& (client.ent->v.movetype == MOVETYPE_FLY)) {
|
&& (client.ent->v.movetype == MOVETYPE_FLY)) {
|
||||||
|
|
||||||
const auto numPreviousNode = rg.get (0, 2);
|
const auto numPreviousNode = rg (0, 2);
|
||||||
|
|
||||||
for (int i = 0; i < numPreviousNode; ++i) {
|
for (int i = 0; i < numPreviousNode; ++i) {
|
||||||
if (graph.exists (m_previousNodes[i]) && (graph[m_previousNodes[i]].flags & NodeFlag::Ladder)) {
|
if (graph.exists (m_previousNodes[i]) && (graph[m_previousNodes[i]].flags & NodeFlag::Ladder)) {
|
||||||
|
|
@ -1115,7 +1115,7 @@ bool Bot::updateNavigation () {
|
||||||
util.findNearestPlayer (reinterpret_cast <void **> (&nearest), ent (), 192.0f, false, false, true, true, false);
|
util.findNearestPlayer (reinterpret_cast <void **> (&nearest), ent (), 192.0f, false, false, true, true, false);
|
||||||
|
|
||||||
// check if enemy is penetrable
|
// check if enemy is penetrable
|
||||||
if (util.isAlive (nearest) && isPenetrableObstacle (nearest->v.origin) && !cv_ignore_enemies.bool_ ()) {
|
if (util.isAlive (nearest) && isPenetrableObstacle (nearest->v.origin) && !cv_ignore_enemies) {
|
||||||
m_seeEnemyTime = game.time ();
|
m_seeEnemyTime = game.time ();
|
||||||
|
|
||||||
m_states |= Sense::SeeingEnemy | Sense::SuspectEnemy;
|
m_states |= Sense::SeeingEnemy | Sense::SuspectEnemy;
|
||||||
|
|
@ -1137,7 +1137,7 @@ bool Bot::updateNavigation () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float desiredDistanceSq = cr::sqrf (4.0f);
|
float desiredDistanceSq = cr::sqrf (8.0f);
|
||||||
const float nodeDistanceSq = pev->origin.distanceSq (m_pathOrigin);
|
const float nodeDistanceSq = pev->origin.distanceSq (m_pathOrigin);
|
||||||
|
|
||||||
// initialize the radius for a special node type, where the node is considered to be reached
|
// initialize the radius for a special node type, where the node is considered to be reached
|
||||||
|
|
@ -1145,7 +1145,7 @@ bool Bot::updateNavigation () {
|
||||||
desiredDistanceSq = cr::sqrf (50.0f);
|
desiredDistanceSq = cr::sqrf (50.0f);
|
||||||
}
|
}
|
||||||
else if (isDucking () || (m_pathFlags & NodeFlag::Goal)) {
|
else if (isDucking () || (m_pathFlags & NodeFlag::Goal)) {
|
||||||
desiredDistanceSq = cr::sqrf (12.0f);
|
desiredDistanceSq = cr::sqrf (9.0f);
|
||||||
|
|
||||||
// on cs_ maps goals are usually hostages, so increase reachability distance for them, they (hostages) picked anyway
|
// on cs_ maps goals are usually hostages, so increase reachability distance for them, they (hostages) picked anyway
|
||||||
if (game.mapIs (MapFlags::HostageRescue) && (m_pathFlags & NodeFlag::Goal)) {
|
if (game.mapIs (MapFlags::HostageRescue) && (m_pathFlags & NodeFlag::Goal)) {
|
||||||
|
|
@ -1155,17 +1155,14 @@ bool Bot::updateNavigation () {
|
||||||
else if (m_pathFlags & NodeFlag::Ladder) {
|
else if (m_pathFlags & NodeFlag::Ladder) {
|
||||||
desiredDistanceSq = cr::sqrf (16.0f);
|
desiredDistanceSq = cr::sqrf (16.0f);
|
||||||
}
|
}
|
||||||
else if (m_pathFlags & NodeFlag::Camp) {
|
|
||||||
desiredDistanceSq = cr::sqrf (32.0f);
|
|
||||||
}
|
|
||||||
else if (m_currentTravelFlags & PathFlag::Jump) {
|
else if (m_currentTravelFlags & PathFlag::Jump) {
|
||||||
desiredDistanceSq = 0.0f;
|
desiredDistanceSq = 0.0f;
|
||||||
}
|
}
|
||||||
else if (m_path->number == cv_debug_goal.int_ ()) {
|
else if (m_path->number == cv_debug_goal.as <int> ()) {
|
||||||
desiredDistanceSq = 0.0f;
|
desiredDistanceSq = 0.0f;
|
||||||
}
|
}
|
||||||
else if (isOccupiedNode (m_path->number)) {
|
else if (isOccupiedNode (m_path->number)) {
|
||||||
desiredDistanceSq = cr::sqrf (120.0f);
|
desiredDistanceSq = cr::sqrf (148.0f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
desiredDistanceSq = cr::max (cr::sqrf (m_path->radius), desiredDistanceSq);
|
desiredDistanceSq = cr::max (cr::sqrf (m_path->radius), desiredDistanceSq);
|
||||||
|
|
@ -1180,7 +1177,7 @@ bool Bot::updateNavigation () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// needs precise placement - check if we get past the point
|
// needs precise placement - check if we get past the point
|
||||||
if (desiredDistanceSq < cr::sqrf (16.0f)
|
if (desiredDistanceSq < cr::sqrf (22.0f)
|
||||||
&& nodeDistanceSq < cr::sqrf (30.0f)
|
&& nodeDistanceSq < cr::sqrf (30.0f)
|
||||||
&& m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) >= nodeDistanceSq) {
|
&& m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) >= nodeDistanceSq) {
|
||||||
|
|
||||||
|
|
@ -1720,10 +1717,10 @@ bool Bot::findNextBestNode () {
|
||||||
|
|
||||||
// choice from found
|
// choice from found
|
||||||
if (lessIndex[2] != kInvalidNodeIndex) {
|
if (lessIndex[2] != kInvalidNodeIndex) {
|
||||||
index = rg.get (0, 2);
|
index = rg (0, 2);
|
||||||
}
|
}
|
||||||
else if (lessIndex[1] != kInvalidNodeIndex) {
|
else if (lessIndex[1] != kInvalidNodeIndex) {
|
||||||
index = rg.get (0, 1);
|
index = rg (0, 1);
|
||||||
}
|
}
|
||||||
else if (lessIndex[0] != kInvalidNodeIndex) {
|
else if (lessIndex[0] != kInvalidNodeIndex) {
|
||||||
index = 0;
|
index = 0;
|
||||||
|
|
@ -1739,7 +1736,13 @@ bool Bot::findNextBestNode () {
|
||||||
if (selected == kInvalidNodeIndex) {
|
if (selected == kInvalidNodeIndex) {
|
||||||
selected = findNearestNode ();
|
selected = findNearestNode ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark bot as searching for new best next node
|
||||||
|
if (selected != kInvalidNodeIndex) {
|
||||||
|
m_lostReachableNodeTimer.start (pev->origin.distanceSq (graph[selected].origin) / cr::sqrf (pev->maxspeed) * 4.0f);
|
||||||
|
}
|
||||||
changeNodeIndex (selected);
|
changeNodeIndex (selected);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1806,7 +1809,7 @@ void Bot::findValidNode () {
|
||||||
|
|
||||||
int Bot::changeNodeIndex (int index) {
|
int Bot::changeNodeIndex (int index) {
|
||||||
if (index == kInvalidNodeIndex) {
|
if (index == kInvalidNodeIndex) {
|
||||||
return 0;
|
return kInvalidNodeIndex;
|
||||||
}
|
}
|
||||||
m_previousNodes[4] = m_previousNodes[3];
|
m_previousNodes[4] = m_previousNodes[3];
|
||||||
m_previousNodes[3] = m_previousNodes[2];
|
m_previousNodes[3] = m_previousNodes[2];
|
||||||
|
|
@ -2077,7 +2080,7 @@ int Bot::findDefendNode (const Vector &origin) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nodeIndex[rg.get (0, (index - 1) / 2)];
|
return nodeIndex[rg (0, (index - 1) / 2)];
|
||||||
}
|
}
|
||||||
|
|
||||||
int Bot::findCoverNode (float maxDistance) {
|
int Bot::findCoverNode (float maxDistance) {
|
||||||
|
|
@ -2334,8 +2337,8 @@ bool Bot::advanceMovement () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_baseAgressionLevel < kills && hasPrimaryWeapon ()) {
|
if (m_baseAgressionLevel < kills && hasPrimaryWeapon ()) {
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (static_cast <float> (m_difficulty / 2), static_cast <float> (m_difficulty)) * 5.0f, true);
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (static_cast <float> (m_difficulty / 2), static_cast <float> (m_difficulty)) * 5.0f, true);
|
||||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, findDefendNode (graph[nextIndex].origin), game.time () + rg.get (3.0f, 10.0f), true);
|
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, findDefendNode (graph[nextIndex].origin), game.time () + rg (3.0f, 10.0f), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bots.canPause () && !isOnLadder () && !isInWater () && !m_currentTravelFlags && isOnFloor ()) {
|
else if (bots.canPause () && !isOnLadder () && !isInWater () && !m_currentTravelFlags && isOnFloor ()) {
|
||||||
|
|
@ -2366,7 +2369,7 @@ bool Bot::advanceMovement () {
|
||||||
for (const auto &link : m_path->links) {
|
for (const auto &link : m_path->links) {
|
||||||
if (link.index == destIndex) {
|
if (link.index == destIndex) {
|
||||||
m_currentTravelFlags = link.flags;
|
m_currentTravelFlags = link.flags;
|
||||||
m_desiredVelocity = link.velocity - link.velocity * m_frameInterval;
|
m_desiredVelocity = link.velocity;
|
||||||
m_jumpFinished = false;
|
m_jumpFinished = false;
|
||||||
|
|
||||||
isCurrentJump = true;
|
isCurrentJump = true;
|
||||||
|
|
@ -2467,7 +2470,7 @@ void Bot::setPathOrigin () {
|
||||||
Vector orgs[kMaxAlternatives] {};
|
Vector orgs[kMaxAlternatives] {};
|
||||||
|
|
||||||
for (int i = 0; i < kMaxAlternatives; ++i) {
|
for (int i = 0; i < kMaxAlternatives; ++i) {
|
||||||
orgs[i] = m_pathOrigin + Vector (rg.get (-m_path->radius, m_path->radius), rg.get (-m_path->radius, m_path->radius), 0.0f);
|
orgs[i] = m_pathOrigin + Vector (rg (-m_path->radius, m_path->radius), rg (-m_path->radius, m_path->radius), 0.0f);
|
||||||
}
|
}
|
||||||
float nearestDistanceSq = kInfiniteDistance;
|
float nearestDistanceSq = kInfiniteDistance;
|
||||||
|
|
||||||
|
|
@ -2487,7 +2490,7 @@ void Bot::setPathOrigin () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nearestIndex == kInvalidNodeIndex) {
|
if (nearestIndex == kInvalidNodeIndex) {
|
||||||
m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius);
|
m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg (-90.0f, 90.0f)), 0.0f).forward () * rg (0.0f, m_path->radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2938,7 +2941,7 @@ bool Bot::isDeadlyMove (const Vector &to) {
|
||||||
TraceResult tr {};
|
TraceResult tr {};
|
||||||
|
|
||||||
constexpr auto kUnitsDown = 1000.0f;
|
constexpr auto kUnitsDown = 1000.0f;
|
||||||
constexpr auto kFallLimit = 150.0f;
|
constexpr auto kFallLimit = 160.0f;
|
||||||
|
|
||||||
Vector check = to, down = to;
|
Vector check = to, down = to;
|
||||||
down.z -= kUnitsDown; // straight down 1000 units
|
down.z -= kUnitsDown; // straight down 1000 units
|
||||||
|
|
@ -2981,7 +2984,7 @@ bool Bot::isNotSafeToMove (const Vector &to) {
|
||||||
// simplified version of isDeadlyMove() just for combat movement checking
|
// simplified version of isDeadlyMove() just for combat movement checking
|
||||||
|
|
||||||
constexpr auto kUnitsDown = 1000.0f;
|
constexpr auto kUnitsDown = 1000.0f;
|
||||||
constexpr auto kFallLimit = 150.0f;
|
constexpr auto kFallLimit = 160.0f;
|
||||||
|
|
||||||
TraceResult tr {};
|
TraceResult tr {};
|
||||||
game.testLine (to, to + Vector { 0.0f, 0.0f, -kUnitsDown }, TraceIgnore::Monsters, ent (), &tr);
|
game.testLine (to, to + Vector { 0.0f, 0.0f, -kUnitsDown }, TraceIgnore::Monsters, ent (), &tr);
|
||||||
|
|
@ -3031,7 +3034,7 @@ int Bot::getRandomCampDir () {
|
||||||
count--;
|
count--;
|
||||||
|
|
||||||
if (count >= 0) {
|
if (count >= 0) {
|
||||||
return indices[rg.get (0, count)];
|
return indices[rg (0, count)];
|
||||||
}
|
}
|
||||||
return graph.random ();
|
return graph.random ();
|
||||||
}
|
}
|
||||||
|
|
@ -3146,46 +3149,43 @@ bool Bot::isReachableNode (int index) {
|
||||||
if (!graph.exists (index)) {
|
if (!graph.exists (index)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const Vector &src = pev->origin;
|
const auto &src = pev->origin;
|
||||||
const Vector &dst = graph[index].origin;
|
const auto &dst = graph[index].origin;
|
||||||
|
|
||||||
// is the destination close enough?
|
// is the destination close enough?
|
||||||
if (dst.distanceSq (src) >= cr::sqrf (400.0f)) {
|
if (dst.distanceSq (src) > cr::sqrf (600.0f)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// it's should be not a problem to reach node inside water...
|
||||||
|
if (pev->waterlevel == 2 || pev->waterlevel == 3) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const float distanceSq2d = dst.distanceSq2d (src);
|
||||||
|
|
||||||
|
// check for ladder
|
||||||
|
const bool nonLadder = !(graph[index].flags & NodeFlag::Ladder) || distanceSq2d > cr::sqrf (16.0f);
|
||||||
|
|
||||||
|
// is dest node higher than src? (62 is max jump height)
|
||||||
|
if (nonLadder && dst.z > src.z + 62.0f) {
|
||||||
|
return false; // can't reach this one
|
||||||
|
}
|
||||||
|
|
||||||
|
// is dest node lower than src?
|
||||||
|
if (nonLadder && dst.z < src.z - 100.0f) {
|
||||||
|
return false; // can't reach this one
|
||||||
|
}
|
||||||
|
|
||||||
// some one seems to camp at this node
|
// some one seems to camp at this node
|
||||||
if (isOccupiedNode (index, true)) {
|
if (isOccupiedNode (index, true)) {
|
||||||
return false;
|
return false; // can't reach this one
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceResult tr {};
|
TraceResult tr {};
|
||||||
game.testHull (src, dst, TraceIgnore::Monsters, head_hull, ent (), &tr);
|
game.testLine (src, dst, TraceIgnore::Monsters, ent (), &tr);
|
||||||
|
|
||||||
// if node is visible from current position (even behind head)...
|
// if node is visible from current position (even behind head)...
|
||||||
if (tr.flFraction >= 1.0f && !tr.fStartSolid) {
|
return tr.flFraction >= 1.0f;
|
||||||
|
|
||||||
// it's should be not a problem to reach node inside water...
|
|
||||||
if (pev->waterlevel == 2 || pev->waterlevel == 3) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const float ladderDistSq = dst.distanceSq2d (src);
|
|
||||||
|
|
||||||
// check for ladder
|
|
||||||
const bool nonLadder = !(graph[index].flags & NodeFlag::Ladder) || ladderDistSq > cr::sqrf (16.0f);
|
|
||||||
|
|
||||||
// is dest node higher than src? (62 is max jump height)
|
|
||||||
if (nonLadder && dst.z > src.z + 62.0f) {
|
|
||||||
return false; // can't reach this one
|
|
||||||
}
|
|
||||||
|
|
||||||
// is dest node lower than src?
|
|
||||||
if (nonLadder && dst.z < src.z - 100.0f) {
|
|
||||||
return false; // can't reach this one
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::isOnLadderPath () {
|
bool Bot::isOnLadderPath () {
|
||||||
|
|
@ -3309,7 +3309,7 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) {
|
||||||
// fallback to shortest path
|
// fallback to shortest path
|
||||||
findShortestPath (srcIndex, destIndex); // A* found no path, try floyd pathfinder instead
|
findShortestPath (srcIndex, destIndex); // A* found no path, try floyd pathfinder instead
|
||||||
|
|
||||||
if (cv_debug.bool_ ()) {
|
if (cv_debug) {
|
||||||
fprintf (stderr, "A* Search for bot \"%s\" has failed. Falling back to shortest-path algorithm. Seems to be graph is broken.\n", pev->netname.chars ());
|
fprintf (stderr, "A* Search for bot \"%s\" has failed. Falling back to shortest-path algorithm. Seems to be graph is broken.\n", pev->netname.chars ());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ float Heuristic::hfunctionPathDist (int index, int, int goalIndex) {
|
||||||
const float y = start.origin.y - goal.origin.y;
|
const float y = start.origin.y - goal.origin.y;
|
||||||
const float z = start.origin.z - goal.origin.z;
|
const float z = start.origin.z - goal.origin.z;
|
||||||
|
|
||||||
switch (cv_path_heuristic_mode.int_ ()) {
|
switch (cv_path_heuristic_mode.as <int> ()) {
|
||||||
case 0:
|
case 0:
|
||||||
return cr::max (cr::max (cr::abs (x), cr::abs (y)), cr::abs (z)); // chebyshev distance
|
return cr::max (cr::max (cr::abs (x), cr::abs (y)), cr::abs (z)); // chebyshev distance
|
||||||
|
|
||||||
|
|
@ -255,7 +255,7 @@ AStarResult AStarAlgo::find (int botTeam, int srcIndex, int destIndex, NodeAdder
|
||||||
m_routeQue.clear ();
|
m_routeQue.clear ();
|
||||||
m_routeQue.emplace (srcIndex, srcRoute->g);
|
m_routeQue.emplace (srcIndex, srcRoute->g);
|
||||||
|
|
||||||
const bool postSmoothPath = cv_path_astar_post_smooth.bool_ () && vistab.isReady ();
|
const bool postSmoothPath = cv_path_astar_post_smooth && vistab.isReady ();
|
||||||
|
|
||||||
// always clear constructed path
|
// always clear constructed path
|
||||||
m_constructedPath.clear ();
|
m_constructedPath.clear ();
|
||||||
|
|
@ -264,8 +264,8 @@ AStarResult AStarAlgo::find (int botTeam, int srcIndex, int destIndex, NodeAdder
|
||||||
auto rsRandomizer = 1.0f;
|
auto rsRandomizer = 1.0f;
|
||||||
|
|
||||||
// randomize path on round start now and then
|
// randomize path on round start now and then
|
||||||
if (cv_path_randomize_on_round_start.bool_ () && bots.getRoundStartTime () + 4.0f > game.time ()) {
|
if (cv_path_randomize_on_round_start && bots.getRoundStartTime () + 4.0f > game.time ()) {
|
||||||
rsRandomizer = rg.get (0.5f, static_cast <float> (botTeam) * 2.0f + 5.0f);
|
rsRandomizer = rg (0.5f, static_cast <float> (botTeam) * 2.0f + 5.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!m_routeQue.empty ()) {
|
while (!m_routeQue.empty ()) {
|
||||||
|
|
@ -512,7 +512,7 @@ PathPlanner::PathPlanner () {
|
||||||
void PathPlanner::init () {
|
void PathPlanner::init () {
|
||||||
const int length = graph.length ();
|
const int length = graph.length ();
|
||||||
|
|
||||||
const float limitInMb = cv_path_floyd_memory_limit.float_ ();
|
const float limitInMb = cv_path_floyd_memory_limit.as <float> ();
|
||||||
const float memoryUse = static_cast <float> (sizeof (FloydWarshallAlgo::Matrix) * cr::sqrf (static_cast <size_t> (length)) / 1024 / 1024);
|
const float memoryUse = static_cast <float> (sizeof (FloydWarshallAlgo::Matrix) * cr::sqrf (static_cast <size_t> (length)) / 1024 / 1024);
|
||||||
|
|
||||||
// if we're have too much memory for floyd matrices, planner will use dijkstra or uniform planner for other than pathfinding needs
|
// if we're have too much memory for floyd matrices, planner will use dijkstra or uniform planner for other than pathfinding needs
|
||||||
|
|
@ -528,7 +528,7 @@ void PathPlanner::init () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathPlanner::hasRealPathDistance () const {
|
bool PathPlanner::hasRealPathDistance () const {
|
||||||
return !m_memoryLimitHit || !cv_path_dijkstra_simple_distance.bool_ ();
|
return !m_memoryLimitHit || !cv_path_dijkstra_simple_distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathPlanner::find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance) {
|
bool PathPlanner::find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance) {
|
||||||
|
|
@ -553,7 +553,7 @@ float PathPlanner::dist (int srcIndex, int destIndex) {
|
||||||
|
|
||||||
// limit hit, use dijkstra
|
// limit hit, use dijkstra
|
||||||
if (m_memoryLimitHit) {
|
if (m_memoryLimitHit) {
|
||||||
if (cv_path_dijkstra_simple_distance.bool_ ()) {
|
if (cv_path_dijkstra_simple_distance) {
|
||||||
return graph[srcIndex].origin.distance2d (graph[destIndex].origin);
|
return graph[srcIndex].origin.distance2d (graph[destIndex].origin);
|
||||||
}
|
}
|
||||||
return static_cast <float> (m_dijkstra->dist (srcIndex, destIndex));
|
return static_cast <float> (m_dijkstra->dist (srcIndex, destIndex));
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,7 @@ void BotPractice::save () {
|
||||||
return; // no action
|
return; // no action
|
||||||
}
|
}
|
||||||
SmallArray <DangerSaveRestore> data;
|
SmallArray <DangerSaveRestore> data;
|
||||||
|
data.reserve (m_data.length ());
|
||||||
|
|
||||||
// copy hash-map data to our vector
|
// copy hash-map data to our vector
|
||||||
m_data.foreach ([&data] (const DangerStorage &ds, const PracticeData &pd) {
|
m_data.foreach ([&data] (const DangerStorage &ds, const PracticeData &pd) {
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ void BotSounds::simulateNoise (int playerIndex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (mp_footsteps.bool_ ()) {
|
if (mp_footsteps) {
|
||||||
// moves fast enough?
|
// moves fast enough?
|
||||||
noise.dist = 1280.0f * (client.ent->v.velocity.length2d () / 260.0f);
|
noise.dist = 1280.0f * (client.ent->v.velocity.length2d () / 260.0f);
|
||||||
noise.last = game.time () + 0.3f;
|
noise.last = game.time () + 0.3f;
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ template <typename U> bool BotStorage::load (SmallArray <U> &data, ExtenHeader *
|
||||||
extern ConVar cv_debug, cv_graph_url;
|
extern ConVar cv_debug, cv_graph_url;
|
||||||
|
|
||||||
// graphs can be downloaded...
|
// graphs can be downloaded...
|
||||||
const auto isGraph = !!(type.option & StorageOption::Graph);
|
const bool isGraph = !!(type.option & StorageOption::Graph);
|
||||||
const auto isDebug = cv_debug.bool_ ();
|
const bool isDebug = cv_debug;
|
||||||
|
|
||||||
MemFile file (filename); // open the file
|
MemFile file (filename); // open the file
|
||||||
data.clear ();
|
data.clear ();
|
||||||
|
|
@ -46,7 +46,7 @@ template <typename U> bool BotStorage::load (SmallArray <U> &data, ExtenHeader *
|
||||||
String lowercaseMapName = game.getMapName ();
|
String lowercaseMapName = game.getMapName ();
|
||||||
lowercaseMapName = lowercaseMapName.lowercase ();
|
lowercaseMapName = lowercaseMapName.lowercase ();
|
||||||
|
|
||||||
auto downloadAddress = cv_graph_url.str ();
|
auto downloadAddress = cv_graph_url.as <StringRef> ();
|
||||||
|
|
||||||
auto toDownload = buildPath (storageToBotFile (type.option), false);
|
auto toDownload = buildPath (storageToBotFile (type.option), false);
|
||||||
auto fromDownload = strings.format ("%s://%s/graph/%s.graph", product.httpScheme, downloadAddress, lowercaseMapName);
|
auto fromDownload = strings.format ("%s://%s/graph/%s.graph", product.httpScheme, downloadAddress, lowercaseMapName);
|
||||||
|
|
@ -272,7 +272,7 @@ template <typename U> bool BotStorage::save (const SmallArray <U> &data, ExtenHe
|
||||||
extern ConVar cv_debug;
|
extern ConVar cv_debug;
|
||||||
|
|
||||||
// notify only about graph
|
// notify only about graph
|
||||||
if (isGraph || cv_debug.bool_ ()) {
|
if (isGraph || cv_debug) {
|
||||||
ctrl.msg ("Successfully saved Bots %s data.", type.name);
|
ctrl.msg ("Successfully saved Bots %s data.", type.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ bool BotSupport::isShootableBreakable (edict_t *ent) {
|
||||||
if (game.isNullEntity (ent) || ent == game.getStartEntity ()) {
|
if (game.isNullEntity (ent) || ent == game.getStartEntity ()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto limit = cv_breakable_health_limit.float_ ();
|
const auto limit = cv_breakable_health_limit.as <float> ();
|
||||||
|
|
||||||
// not shootable
|
// not shootable
|
||||||
if (ent->v.health >= limit) {
|
if (ent->v.health >= limit) {
|
||||||
|
|
@ -263,7 +263,7 @@ bool BotSupport::isFakeClient (edict_t *ent) {
|
||||||
void BotSupport::checkWelcome () {
|
void BotSupport::checkWelcome () {
|
||||||
// the purpose of this function, is to send quick welcome message, to the listenserver entity.
|
// the purpose of this function, is to send quick welcome message, to the listenserver entity.
|
||||||
|
|
||||||
if (game.isDedicated () || !cv_display_welcome_text.bool_ () || !m_needToSendWelcome) {
|
if (game.isDedicated () || !cv_display_welcome_text || !m_needToSendWelcome) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,7 +271,7 @@ void BotSupport::checkWelcome () {
|
||||||
auto receiveEnt = game.getLocalEntity ();
|
auto receiveEnt = game.getLocalEntity ();
|
||||||
|
|
||||||
if (isAlive (receiveEnt) && m_welcomeReceiveTime < 1.0f && needToSendMsg) {
|
if (isAlive (receiveEnt) && m_welcomeReceiveTime < 1.0f && needToSendMsg) {
|
||||||
m_welcomeReceiveTime = game.time () + 2.0f + mp_freezetime.float_ (); // receive welcome message in four seconds after game has commencing
|
m_welcomeReceiveTime = game.time () + 2.0f + mp_freezetime.as <float> (); // receive welcome message in four seconds after game has commencing
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_welcomeReceiveTime > 0.0f && m_welcomeReceiveTime < game.time () && needToSendMsg) {
|
if (m_welcomeReceiveTime > 0.0f && m_welcomeReceiveTime < game.time () && needToSendMsg) {
|
||||||
|
|
@ -309,16 +309,16 @@ void BotSupport::checkWelcome () {
|
||||||
textParams.channel = 1;
|
textParams.channel = 1;
|
||||||
textParams.x = -1.0f;
|
textParams.x = -1.0f;
|
||||||
textParams.y = sendLegacyWelcome ? 0.0f : -1.0f;
|
textParams.y = sendLegacyWelcome ? 0.0f : -1.0f;
|
||||||
textParams.effect = rg.get (1, 2);
|
textParams.effect = rg (1, 2);
|
||||||
|
|
||||||
textParams.r1 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg.get (33, 255));
|
textParams.r1 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg (33, 255));
|
||||||
textParams.g1 = static_cast <uint8_t> (sendLegacyWelcome ? 0 : rg.get (33, 255));
|
textParams.g1 = static_cast <uint8_t> (sendLegacyWelcome ? 0 : rg (33, 255));
|
||||||
textParams.b1 = static_cast <uint8_t> (sendLegacyWelcome ? 0 : rg.get (33, 255));
|
textParams.b1 = static_cast <uint8_t> (sendLegacyWelcome ? 0 : rg (33, 255));
|
||||||
textParams.a1 = static_cast <uint8_t> (0);
|
textParams.a1 = static_cast <uint8_t> (0);
|
||||||
|
|
||||||
textParams.r2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg.get (230, 255));
|
textParams.r2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg (230, 255));
|
||||||
textParams.g2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg.get (230, 255));
|
textParams.g2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg (230, 255));
|
||||||
textParams.b2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg.get (230, 255));
|
textParams.b2 = static_cast <uint8_t> (sendLegacyWelcome ? 255 : rg (230, 255));
|
||||||
textParams.a2 = static_cast <uint8_t> (200);
|
textParams.a2 = static_cast <uint8_t> (200);
|
||||||
|
|
||||||
textParams.fadeinTime = 0.0078125f;
|
textParams.fadeinTime = 0.0078125f;
|
||||||
|
|
@ -425,7 +425,7 @@ void BotSupport::calculatePings () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotSupport::syncCalculatePings () {
|
void BotSupport::syncCalculatePings () {
|
||||||
if (!game.is (GameFlags::HasFakePings) || cv_show_latency.int_ () != 2) {
|
if (!game.is (GameFlags::HasFakePings) || cv_show_latency.as <int> () != 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MutexScopedLock lock (m_cs);
|
MutexScopedLock lock (m_cs);
|
||||||
|
|
@ -434,7 +434,7 @@ void BotSupport::syncCalculatePings () {
|
||||||
int numHumans = 0;
|
int numHumans = 0;
|
||||||
|
|
||||||
// only count player pings if we're allowed to
|
// only count player pings if we're allowed to
|
||||||
if (cv_count_players_for_fakeping.bool_ ()) {
|
if (cv_count_players_for_fakeping) {
|
||||||
// first get average ping on server, and store real client pings
|
// first get average ping on server, and store real client pings
|
||||||
for (auto &client : m_clients) {
|
for (auto &client : m_clients) {
|
||||||
if (!(client.flags & ClientFlags::Used) || isFakeClient (client.ent)) {
|
if (!(client.flags & ClientFlags::Used) || isFakeClient (client.ent)) {
|
||||||
|
|
@ -454,7 +454,7 @@ void BotSupport::syncCalculatePings () {
|
||||||
// https://github.com/fwgs/xash3d-fwgs/blob/f5b9826fd9bbbdc5293c1ff522de11ce28d3c9f2/engine/server/sv_game.c#L4443
|
// https://github.com/fwgs/xash3d-fwgs/blob/f5b9826fd9bbbdc5293c1ff522de11ce28d3c9f2/engine/server/sv_game.c#L4443
|
||||||
|
|
||||||
// store normal client ping
|
// store normal client ping
|
||||||
client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping : rg.get (8, 16)); // getting player ping sometimes fails
|
client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping : rg (8, 16)); // getting player ping sometimes fails
|
||||||
++numHumans;
|
++numHumans;
|
||||||
|
|
||||||
average.first += ping;
|
average.first += ping;
|
||||||
|
|
@ -466,13 +466,13 @@ void BotSupport::syncCalculatePings () {
|
||||||
average.second /= numHumans;
|
average.second /= numHumans;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
average.first = rg.get (10, 20);
|
average.first = rg (10, 20);
|
||||||
average.second = rg.get (5, 10);
|
average.second = rg (5, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
average.first = rg.get (10, 20);
|
average.first = rg (10, 20);
|
||||||
average.second = rg.get (5, 10);
|
average.second = rg (5, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now calculate bot ping based on average from players
|
// now calculate bot ping based on average from players
|
||||||
|
|
@ -488,14 +488,14 @@ void BotSupport::syncCalculatePings () {
|
||||||
}
|
}
|
||||||
const int part = static_cast <int> (static_cast <float> (average.first) * 0.2f);
|
const int part = static_cast <int> (static_cast <float> (average.first) * 0.2f);
|
||||||
|
|
||||||
int botPing = bot->m_basePing + rg.get (average.first - part, average.first + part) + rg.get (bot->m_difficulty / 2, bot->m_difficulty);
|
int botPing = bot->m_basePing + rg (average.first - part, average.first + part) + rg (bot->m_difficulty / 2, bot->m_difficulty);
|
||||||
const int botLoss = rg.get (average.second / 2, average.second);
|
const int botLoss = rg (average.second / 2, average.second);
|
||||||
|
|
||||||
if (botPing < 2) {
|
if (botPing < 2) {
|
||||||
botPing = rg.get (10, 23);
|
botPing = rg (10, 23);
|
||||||
}
|
}
|
||||||
else if (botPing > 100) {
|
else if (botPing > 100) {
|
||||||
botPing = rg.get (30, 40);
|
botPing = rg (30, 40);
|
||||||
}
|
}
|
||||||
client.ping = getPingBitmask (client.ent, botLoss, botPing);
|
client.ping = getPingBitmask (client.ent, botLoss, botPing);
|
||||||
}
|
}
|
||||||
|
|
@ -520,7 +520,7 @@ void BotSupport::emitPings (edict_t *to) {
|
||||||
|
|
||||||
// no ping, no fun
|
// no ping, no fun
|
||||||
if (!client.ping) {
|
if (!client.ping) {
|
||||||
client.ping = getPingBitmask (client.ent, rg.get (5, 10), rg.get (15, 40));
|
client.ping = getPingBitmask (client.ent, rg (5, 10), rg (15, 40));
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.start (MSG_ONE_UNRELIABLE, SVC_PINGS, nullptr, to)
|
msg.start (MSG_ONE_UNRELIABLE, SVC_PINGS, nullptr, to)
|
||||||
|
|
@ -565,7 +565,7 @@ String BotSupport::getCurrentDateTime () {
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef BotSupport::getFakeSteamId (edict_t *ent) {
|
StringRef BotSupport::getFakeSteamId (edict_t *ent) {
|
||||||
if (!cv_enable_fake_steamids.bool_ () || !isPlayer (ent)) {
|
if (!cv_enable_fake_steamids || !isPlayer (ent)) {
|
||||||
return "BOT";
|
return "BOT";
|
||||||
}
|
}
|
||||||
auto botNameHash = StringRef::fnv1a32 (ent->v.netname.chars ());
|
auto botNameHash = StringRef::fnv1a32 (ent->v.netname.chars ());
|
||||||
|
|
@ -610,7 +610,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
float BotSupport::getWaveLength (StringRef filename) {
|
float BotSupport::getWaveLength (StringRef filename) {
|
||||||
auto filePath = strings.joinPath (cv_chatter_path.str (), strings.format ("%s.wav", filename));
|
auto filePath = strings.joinPath (cv_chatter_path.as <StringRef> (), strings.format ("%s.wav", filename));
|
||||||
|
|
||||||
MemFile fp (filePath);
|
MemFile fp (filePath);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ ConVar cv_random_knife_attacks ("random_knife_attacks", "1", "Allows or disallow
|
||||||
void Bot::normal_ () {
|
void Bot::normal_ () {
|
||||||
m_aimFlags |= AimFlags::Nav;
|
m_aimFlags |= AimFlags::Nav;
|
||||||
|
|
||||||
const int debugGoal = cv_debug_goal.int_ ();
|
const int debugGoal = cv_debug_goal.as <int> ();
|
||||||
|
|
||||||
// user forced a node as a goal?
|
// user forced a node as a goal?
|
||||||
if (debugGoal != kInvalidNodeIndex) {
|
if (debugGoal != kInvalidNodeIndex) {
|
||||||
|
|
@ -46,14 +46,14 @@ void Bot::normal_ () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// bots rushing with knife, when have no enemy (thanks for idea to nicebot project)
|
// bots rushing with knife, when have no enemy (thanks for idea to nicebot project)
|
||||||
if (cv_random_knife_attacks.bool_ () && usesKnife () && (game.isNullEntity (m_lastEnemy) || !util.isAlive (m_lastEnemy)) && game.isNullEntity (m_enemy) && m_knifeAttackTime < game.time () && !m_hasHostage && !hasShield () && numFriendsNear (pev->origin, 96.0f) == 0) {
|
if (cv_random_knife_attacks && usesKnife () && (game.isNullEntity (m_lastEnemy) || !util.isAlive (m_lastEnemy)) && game.isNullEntity (m_enemy) && m_knifeAttackTime < game.time () && !m_hasHostage && !hasShield () && numFriendsNear (pev->origin, 96.0f) == 0) {
|
||||||
if (rg.chance (40)) {
|
if (rg.chance (40)) {
|
||||||
pev->button |= IN_ATTACK;
|
pev->button |= IN_ATTACK;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pev->button |= IN_ATTACK2;
|
pev->button |= IN_ATTACK2;
|
||||||
}
|
}
|
||||||
m_knifeAttackTime = game.time () + rg.get (2.5f, 6.0f);
|
m_knifeAttackTime = game.time () + rg (2.5f, 6.0f);
|
||||||
}
|
}
|
||||||
const auto &prop = conf.getWeaponProp (m_currentWeapon);
|
const auto &prop = conf.getWeaponProp (m_currentWeapon);
|
||||||
|
|
||||||
|
|
@ -92,7 +92,7 @@ void Bot::normal_ () {
|
||||||
if (!(m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy))
|
if (!(m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy))
|
||||||
&& m_seeEnemyTime + 5.0f < game.time ()
|
&& m_seeEnemyTime + 5.0f < game.time ()
|
||||||
&& !m_reloadState && m_timeLogoSpray < game.time ()
|
&& !m_reloadState && m_timeLogoSpray < game.time ()
|
||||||
&& cv_spraypaints.bool_ ()
|
&& cv_spraypaints
|
||||||
&& rg.chance (50)
|
&& rg.chance (50)
|
||||||
&& m_moveSpeed > getShiftSpeed ()
|
&& m_moveSpeed > getShiftSpeed ()
|
||||||
&& game.isNullEntity (m_pickupItem)) {
|
&& game.isNullEntity (m_pickupItem)) {
|
||||||
|
|
@ -103,7 +103,7 @@ void Bot::normal_ () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// reached node is a camp node
|
// reached node is a camp node
|
||||||
if ((m_pathFlags & NodeFlag::Camp) && !game.is (GameFlags::CSDM) && cv_camping_allowed.bool_ () && !isKnifeMode ()) {
|
if ((m_pathFlags & NodeFlag::Camp) && !game.is (GameFlags::CSDM) && cv_camping_allowed && !isKnifeMode ()) {
|
||||||
const bool allowedCampWeapon = hasPrimaryWeapon ()
|
const bool allowedCampWeapon = hasPrimaryWeapon ()
|
||||||
|| hasShield ()
|
|| hasShield ()
|
||||||
|| (hasSecondaryWeapon () && !hasPrimaryWeapon () && m_numFriendsLeft > game.maxClients () / 6);
|
|| (hasSecondaryWeapon () && !hasPrimaryWeapon () && m_numFriendsLeft > game.maxClients () / 6);
|
||||||
|
|
@ -153,7 +153,7 @@ void Bot::normal_ () {
|
||||||
if (!(m_states & (Sense::SeeingEnemy | Sense::HearingEnemy)) && !m_reloadState) {
|
if (!(m_states & (Sense::SeeingEnemy | Sense::HearingEnemy)) && !m_reloadState) {
|
||||||
m_reloadState = Reload::Primary;
|
m_reloadState = Reload::Primary;
|
||||||
}
|
}
|
||||||
m_timeCamping = game.time () + rg.get (cv_camping_time_min.float_ (), cv_camping_time_max.float_ ());
|
m_timeCamping = game.time () + rg (cv_camping_time_min.as <float> (), cv_camping_time_max.as <float> ());
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, m_timeCamping, true);
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, m_timeCamping, true);
|
||||||
|
|
||||||
m_lookAtSafe = m_pathOrigin + m_path->start.forward () * 500.0f;
|
m_lookAtSafe = m_pathOrigin + m_path->start.forward () * 500.0f;
|
||||||
|
|
@ -185,8 +185,8 @@ void Bot::normal_ () {
|
||||||
else if (m_team == Team::Terrorist && rg.chance (75) && !game.mapIs (MapFlags::Demolition)) {
|
else if (m_team == Team::Terrorist && rg.chance (75) && !game.mapIs (MapFlags::Demolition)) {
|
||||||
const int index = findDefendNode (m_path->origin);
|
const int index = findDefendNode (m_path->origin);
|
||||||
|
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (60.0f, 120.0f), true); // push camp task on to stack
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (60.0f, 120.0f), true); // push camp task on to stack
|
||||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (5.0f, 10.0f), true); // push move command
|
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (5.0f, 10.0f), true); // push move command
|
||||||
|
|
||||||
// decide to duck or not to duck
|
// decide to duck or not to duck
|
||||||
selectCampButtons (index);
|
selectCampButtons (index);
|
||||||
|
|
@ -202,7 +202,7 @@ void Bot::normal_ () {
|
||||||
pushRadioMessage (Radio::NeedBackup);
|
pushRadioMessage (Radio::NeedBackup);
|
||||||
pushChatterMessage (Chatter::ScaredEmotion);
|
pushChatterMessage (Chatter::ScaredEmotion);
|
||||||
|
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (4.0f, 8.0f), true);
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (4.0f, 8.0f), true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
startTask (Task::PlantBomb, TaskPri::PlantBomb, kInvalidNodeIndex, 0.0f, false);
|
startTask (Task::PlantBomb, TaskPri::PlantBomb, kInvalidNodeIndex, 0.0f, false);
|
||||||
|
|
@ -211,14 +211,14 @@ void Bot::normal_ () {
|
||||||
else if (m_team == Team::CT) {
|
else if (m_team == Team::CT) {
|
||||||
if (!bots.isBombPlanted () && numFriendsNear (pev->origin, 210.0f) < 4) {
|
if (!bots.isBombPlanted () && numFriendsNear (pev->origin, 210.0f) < 4) {
|
||||||
const int index = findDefendNode (m_path->origin);
|
const int index = findDefendNode (m_path->origin);
|
||||||
float campTime = rg.get (25.0f, 40.f);
|
float campTime = rg (25.0f, 40.f);
|
||||||
|
|
||||||
// rusher bots don't like to camp too much
|
// rusher bots don't like to camp too much
|
||||||
if (m_personality == Personality::Rusher) {
|
if (m_personality == Personality::Rusher) {
|
||||||
campTime *= 0.5f;
|
campTime *= 0.5f;
|
||||||
}
|
}
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + campTime, true); // push camp task on to stack
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + campTime, true); // push camp task on to stack
|
||||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (5.0f, 11.0f), true); // push move command
|
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg (5.0f, 11.0f), true); // push move command
|
||||||
|
|
||||||
// decide to duck or not to duck
|
// decide to duck or not to duck
|
||||||
selectCampButtons (index);
|
selectCampButtons (index);
|
||||||
|
|
@ -267,7 +267,7 @@ void Bot::normal_ () {
|
||||||
}
|
}
|
||||||
const float shiftSpeed = getShiftSpeed ();
|
const float shiftSpeed = getShiftSpeed ();
|
||||||
|
|
||||||
if ((!cr::fzero (m_moveSpeed) && m_moveSpeed > shiftSpeed) && (cv_walking_allowed.bool_ () && mp_footsteps.bool_ ())
|
if ((!cr::fzero (m_moveSpeed) && m_moveSpeed > shiftSpeed) && (cv_walking_allowed && mp_footsteps)
|
||||||
&& m_difficulty >= Difficulty::Normal
|
&& m_difficulty >= Difficulty::Normal
|
||||||
&& (m_heardSoundTime + 6.0f >= game.time () || (m_states & Sense::HearingEnemy))
|
&& (m_heardSoundTime + 6.0f >= game.time () || (m_states & Sense::HearingEnemy))
|
||||||
&& pev->origin.distanceSq (m_lastEnemyOrigin) < cr::sqrf (768.0f)
|
&& pev->origin.distanceSq (m_lastEnemyOrigin) < cr::sqrf (768.0f)
|
||||||
|
|
@ -278,21 +278,21 @@ void Bot::normal_ () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// bot hasn't seen anything in a long time and is asking his teammates to report in
|
// bot hasn't seen anything in a long time and is asking his teammates to report in
|
||||||
if (cv_radio_mode.int_ () > 1
|
if (cv_radio_mode.as <int> () > 1
|
||||||
&& bots.getLastRadio (m_team) != Radio::ReportInTeam
|
&& bots.getLastRadio (m_team) != Radio::ReportInTeam
|
||||||
&& bots.getRoundStartTime () + 20.0f < game.time ()
|
&& bots.getRoundStartTime () + 20.0f < game.time ()
|
||||||
&& m_askCheckTime < game.time () && rg.chance (15)
|
&& m_askCheckTime < game.time () && rg.chance (15)
|
||||||
&& m_seeEnemyTime + rg.get (45.0f, 80.0f) < game.time ()
|
&& m_seeEnemyTime + rg (45.0f, 80.0f) < game.time ()
|
||||||
&& numFriendsNear (pev->origin, 1024.0f) == 0) {
|
&& numFriendsNear (pev->origin, 1024.0f) == 0) {
|
||||||
|
|
||||||
pushRadioMessage (Radio::ReportInTeam);
|
pushRadioMessage (Radio::ReportInTeam);
|
||||||
|
|
||||||
m_askCheckTime = game.time () + rg.get (45.0f, 80.0f);
|
m_askCheckTime = game.time () + rg (45.0f, 80.0f);
|
||||||
|
|
||||||
// make sure everyone else will not ask next few moments
|
// make sure everyone else will not ask next few moments
|
||||||
for (const auto &bot : bots) {
|
for (const auto &bot : bots) {
|
||||||
if (bot->m_isAlive) {
|
if (bot->m_isAlive) {
|
||||||
bot->m_askCheckTime = game.time () + rg.get (5.0f, 30.0f);
|
bot->m_askCheckTime = game.time () + rg (5.0f, 30.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -322,7 +322,7 @@ void Bot::spraypaint_ () {
|
||||||
|
|
||||||
// paint the actual logo decal
|
// paint the actual logo decal
|
||||||
util.decalTrace (pev, &tr, m_logotypeIndex);
|
util.decalTrace (pev, &tr, m_logotypeIndex);
|
||||||
m_timeLogoSpray = game.time () + rg.get (60.0f, 90.0f);
|
m_timeLogoSpray = game.time () + rg (60.0f, 90.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -390,7 +390,7 @@ void Bot::huntEnemy_ () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// bots skill higher than 60?
|
// bots skill higher than 60?
|
||||||
if (cv_walking_allowed.bool_ () && mp_footsteps.bool_ () && m_difficulty >= Difficulty::Normal && !isKnifeMode ()) {
|
if (cv_walking_allowed && mp_footsteps && m_difficulty >= Difficulty::Normal && !isKnifeMode ()) {
|
||||||
// then make him move slow if near enemy
|
// then make him move slow if near enemy
|
||||||
if (!(m_currentTravelFlags & PathFlag::Jump)) {
|
if (!(m_currentTravelFlags & PathFlag::Jump)) {
|
||||||
if (m_currentNodeIndex != kInvalidNodeIndex) {
|
if (m_currentNodeIndex != kInvalidNodeIndex) {
|
||||||
|
|
@ -417,7 +417,7 @@ void Bot::seekCover_ () {
|
||||||
m_prevGoalIndex = kInvalidNodeIndex;
|
m_prevGoalIndex = kInvalidNodeIndex;
|
||||||
|
|
||||||
// start hide task
|
// start hide task
|
||||||
startTask (Task::Hide, TaskPri::Hide, kInvalidNodeIndex, game.time () + rg.get (3.0f, 12.0f), false);
|
startTask (Task::Hide, TaskPri::Hide, kInvalidNodeIndex, game.time () + rg (3.0f, 12.0f), false);
|
||||||
|
|
||||||
// get a valid look direction
|
// get a valid look direction
|
||||||
const Vector &dest = getCampDirection (m_lastEnemyOrigin);
|
const Vector &dest = getCampDirection (m_lastEnemyOrigin);
|
||||||
|
|
@ -470,7 +470,7 @@ void Bot::seekCover_ () {
|
||||||
destIndex = findCoverNode (900.0f);
|
destIndex = findCoverNode (900.0f);
|
||||||
|
|
||||||
if (destIndex == kInvalidNodeIndex) {
|
if (destIndex == kInvalidNodeIndex) {
|
||||||
m_retreatTime = game.time () + rg.get (1.0f, 2.0f);
|
m_retreatTime = game.time () + rg (1.0f, 2.0f);
|
||||||
m_prevGoalIndex = kInvalidNodeIndex;
|
m_prevGoalIndex = kInvalidNodeIndex;
|
||||||
|
|
||||||
completeTask ();
|
completeTask ();
|
||||||
|
|
@ -594,7 +594,7 @@ void Bot::blind_ () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::camp_ () {
|
void Bot::camp_ () {
|
||||||
if (!cv_camping_allowed.bool_ () || m_isCreature) {
|
if (!cv_camping_allowed || m_isCreature) {
|
||||||
completeTask ();
|
completeTask ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -637,7 +637,7 @@ void Bot::camp_ () {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (m_nextCampDirTime < game.time ()) {
|
if (m_nextCampDirTime < game.time ()) {
|
||||||
m_nextCampDirTime = game.time () + rg.get (2.0f, 5.0f);
|
m_nextCampDirTime = game.time () + rg (2.0f, 5.0f);
|
||||||
|
|
||||||
if (m_pathFlags & NodeFlag::Camp) {
|
if (m_pathFlags & NodeFlag::Camp) {
|
||||||
Vector dest;
|
Vector dest;
|
||||||
|
|
@ -838,7 +838,7 @@ void Bot::plantBomb_ () {
|
||||||
pushRadioMessage (Radio::NeedBackup);
|
pushRadioMessage (Radio::NeedBackup);
|
||||||
}
|
}
|
||||||
const auto index = findDefendNode (pev->origin);
|
const auto index = findDefendNode (pev->origin);
|
||||||
const auto guardTime = mp_c4timer.float_ () * 0.5f + mp_c4timer.float_ () * 0.25f;
|
const auto guardTime = mp_c4timer.as <float> () * 0.5f + mp_c4timer.as <float> () * 0.25f;
|
||||||
|
|
||||||
// push camp task on to stack
|
// push camp task on to stack
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + guardTime, true);
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + guardTime, true);
|
||||||
|
|
@ -871,18 +871,18 @@ void Bot::defuseBomb_ () {
|
||||||
if (bot->m_team == m_team && bot->m_isAlive) {
|
if (bot->m_team == m_team && bot->m_isAlive) {
|
||||||
auto defendPoint = graph.getFarest (bot->pev->origin);
|
auto defendPoint = graph.getFarest (bot->pev->origin);
|
||||||
|
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true); // push camp task on to stack
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg (30.0f, 60.0f), true); // push camp task on to stack
|
||||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, defendPoint, game.time () + rg.get (3.0f, 6.0f), true); // push move command
|
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, defendPoint, game.time () + rg (3.0f, 6.0f), true); // push move command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
graph.setBombOrigin (true);
|
graph.setBombOrigin (true);
|
||||||
|
|
||||||
if (m_numFriendsLeft != 0 && rg.chance (50)) {
|
if (m_numFriendsLeft != 0 && rg.chance (50)) {
|
||||||
if (timeToBlowUp <= 3.0f) {
|
if (timeToBlowUp <= 3.0f) {
|
||||||
if (cv_radio_mode.int_ () == 2) {
|
if (cv_radio_mode.as <int> () == 2) {
|
||||||
pushChatterMessage (Chatter::BarelyDefused);
|
pushChatterMessage (Chatter::BarelyDefused);
|
||||||
}
|
}
|
||||||
else if (cv_radio_mode.int_ () == 1) {
|
else if (cv_radio_mode.as <int> () == 1) {
|
||||||
pushRadioMessage (Radio::SectorClear);
|
pushRadioMessage (Radio::SectorClear);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1083,7 +1083,7 @@ void Bot::followUser_ () {
|
||||||
}
|
}
|
||||||
m_aimFlags |= AimFlags::Nav;
|
m_aimFlags |= AimFlags::Nav;
|
||||||
|
|
||||||
if (cv_walking_allowed.bool_ () && m_targetEntity->v.maxspeed < m_moveSpeed && !isKnifeMode ()) {
|
if (cv_walking_allowed && m_targetEntity->v.maxspeed < m_moveSpeed && !isKnifeMode ()) {
|
||||||
m_moveSpeed = getShiftSpeed ();
|
m_moveSpeed = getShiftSpeed ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1324,7 +1324,7 @@ void Bot::doublejump_ () {
|
||||||
game.testLine (src, dest, TraceIgnore::None, ent (), &tr);
|
game.testLine (src, dest, TraceIgnore::None, ent (), &tr);
|
||||||
|
|
||||||
if (tr.flFraction < 1.0f && tr.pHit == m_doubleJumpEntity && inJump) {
|
if (tr.flFraction < 1.0f && tr.pHit == m_doubleJumpEntity && inJump) {
|
||||||
m_duckForJump = game.time () + rg.get (3.0f, 5.0f);
|
m_duckForJump = game.time () + rg (3.0f, 5.0f);
|
||||||
getTask ()->time = game.time ();
|
getTask ()->time = game.time ();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -1394,7 +1394,7 @@ void Bot::escapeFromBomb_ () {
|
||||||
else if (!hasActiveGoal ()) {
|
else if (!hasActiveGoal ()) {
|
||||||
int bestIndex = kInvalidNodeIndex;
|
int bestIndex = kInvalidNodeIndex;
|
||||||
|
|
||||||
const float safeRadius = rg.get (1513.0f, 2048.0f);
|
const float safeRadius = rg (1513.0f, 2048.0f);
|
||||||
float nearestDistanceSq = kInfiniteDistance;
|
float nearestDistanceSq = kInfiniteDistance;
|
||||||
|
|
||||||
for (const auto &path : graph) {
|
for (const auto &path : graph) {
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ void Bot::checkDarkness () {
|
||||||
const auto skyColor = illum.getSkyColor ();
|
const auto skyColor = illum.getSkyColor ();
|
||||||
const auto flashOn = (pev->effects & EF_DIMLIGHT);
|
const auto flashOn = (pev->effects & EF_DIMLIGHT);
|
||||||
|
|
||||||
if (mp_flashlight.bool_ () && !m_hasNVG) {
|
if (mp_flashlight && !m_hasNVG) {
|
||||||
const auto tid = getCurrentTaskId ();
|
const auto tid = getCurrentTaskId ();
|
||||||
|
|
||||||
if (!flashOn &&
|
if (!flashOn &&
|
||||||
|
|
@ -105,7 +105,7 @@ void Bot::checkDarkness () {
|
||||||
issueCommand ("nightvision");
|
issueCommand ("nightvision");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_checkDarkTime = game.time () + rg.get (2.0f, 4.0f);
|
m_checkDarkTime = game.time () + rg (2.0f, 4.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::changePitch (float speed) {
|
void Bot::changePitch (float speed) {
|
||||||
|
|
@ -203,7 +203,7 @@ void Bot::updateLookAngles () {
|
||||||
if (m_difficulty == Difficulty::Expert
|
if (m_difficulty == Difficulty::Expert
|
||||||
&& (m_aimFlags & AimFlags::Enemy)
|
&& (m_aimFlags & AimFlags::Enemy)
|
||||||
&& (m_wantsToFire || usesSniper ())
|
&& (m_wantsToFire || usesSniper ())
|
||||||
&& cv_whose_your_daddy.bool_ ()) {
|
&& cv_whose_your_daddy) {
|
||||||
|
|
||||||
pev->v_angle = direction;
|
pev->v_angle = direction;
|
||||||
pev->v_angle.clampAngles ();
|
pev->v_angle.clampAngles ();
|
||||||
|
|
@ -311,10 +311,10 @@ void Bot::updateLookAnglesNewbie (const Vector &direction, float delta) {
|
||||||
randomize = randomization;
|
randomize = randomization;
|
||||||
}
|
}
|
||||||
// randomize targeted location bit (slightly towards the ground)
|
// randomize targeted location bit (slightly towards the ground)
|
||||||
m_randomizedIdealAngles = m_idealAngles + Vector (rg.get (-randomize.x * 0.5f, randomize.x * 1.5f), rg.get (-randomize.y, randomize.y), 0.0f);
|
m_randomizedIdealAngles = m_idealAngles + Vector (rg (-randomize.x * 0.5f, randomize.x * 1.5f), rg (-randomize.y, randomize.y), 0.0f);
|
||||||
|
|
||||||
// set next time to do this
|
// set next time to do this
|
||||||
m_randomizeAnglesTime = game.time () + rg.get (0.4f, offsetDelay);
|
m_randomizeAnglesTime = game.time () + rg (0.4f, offsetDelay);
|
||||||
}
|
}
|
||||||
float stiffnessMultiplier = noTargetRatio;
|
float stiffnessMultiplier = noTargetRatio;
|
||||||
|
|
||||||
|
|
@ -425,6 +425,16 @@ void Bot::setAimDirection () {
|
||||||
flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
|
flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
|
||||||
m_canChooseAimDirection = false;
|
m_canChooseAimDirection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't switch view right away after loosing focus with current enemy
|
||||||
|
if ((m_shootTime + 1.5f > game.time () || m_seeEnemyTime + 1.5 > game.time ())
|
||||||
|
&& m_forgetLastVictimTimer.elapsed ()
|
||||||
|
&& !m_lastEnemyOrigin.empty ()
|
||||||
|
&& util.isAlive (m_lastEnemy)
|
||||||
|
&& game.isNullEntity (m_enemy)) {
|
||||||
|
|
||||||
|
flags |= AimFlags::LastEnemy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & AimFlags::Override) {
|
if (flags & AimFlags::Override) {
|
||||||
|
|
@ -500,14 +510,14 @@ void Bot::setAimDirection () {
|
||||||
predictNode = kInvalidNodeIndex;
|
predictNode = kInvalidNodeIndex;
|
||||||
pathLength = kInfiniteDistanceLong;
|
pathLength = kInfiniteDistanceLong;
|
||||||
}
|
}
|
||||||
return graph.exists (predictNode) && pathLength < cv_max_nodes_for_predict.int_ ();
|
return graph.exists (predictNode) && pathLength < cv_max_nodes_for_predict.as <int> ();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (changePredictedEnemy) {
|
if (changePredictedEnemy) {
|
||||||
if (isPredictedIndexApplicable ()) {
|
if (isPredictedIndexApplicable ()) {
|
||||||
m_lookAtPredict = graph[predictNode].origin;
|
m_lookAtPredict = graph[predictNode].origin;
|
||||||
|
|
||||||
m_timeNextTracking = game.time () + rg.get (0.5f, 1.0f);
|
m_timeNextTracking = game.time () + rg (0.5f, 1.0f);
|
||||||
m_trackingEdict = m_lastEnemy;
|
m_trackingEdict = m_lastEnemy;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ void GraphVistable::rebuild () {
|
||||||
sourceCrouch.z += -18.0f + 12.0f;
|
sourceCrouch.z += -18.0f + 12.0f;
|
||||||
sourceStand.z += 28.0f;
|
sourceStand.z += 28.0f;
|
||||||
}
|
}
|
||||||
auto end = m_sliceIndex + rg.get (250, 400);
|
auto end = m_sliceIndex + rg (250, 400);
|
||||||
|
|
||||||
if (end > m_length) {
|
if (end > m_length) {
|
||||||
end = m_length;
|
end = m_length;
|
||||||
|
|
@ -122,7 +122,7 @@ void GraphVistable::rebuild () {
|
||||||
m_curIndex++;
|
m_curIndex++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_sliceIndex += rg.get (250, 400);
|
m_sliceIndex += rg (250, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify host about rebuilding
|
// notify host about rebuilding
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue