bot: disable spray logo task on xash3d engine
fix: crash on aarch64 builds (ref #667) nav: improved player avoidance nav: improved handling of short path radii conf: control min and max cvar values build: probably fix i386 build when building with cmake (untested)
This commit is contained in:
parent
9738e088da
commit
e820527703
12 changed files with 104 additions and 40 deletions
|
|
@ -61,7 +61,7 @@ if(GIT_FOUND)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE VERSION_GENERATED)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE VERSION_GENERATED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)" AND NOT CMAKE_LIBRARY_ARCHITECTURE MATCHES "^(arm|aarch64|ppc)")
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86)|(x86_64)|(X86)|(amd64)|(AMD64)" AND NOT CMAKE_LIBRARY_ARCHITECTURE MATCHES "^(arm|aarch64|ppc)")
|
||||||
set(BUILD_X86 true)
|
set(BUILD_X86 true)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -439,6 +439,7 @@ constexpr auto kSprayDistanceX2 = kSprayDistance * 2;
|
||||||
constexpr auto kMaxChatterRepeatInterval = 99.0f;
|
constexpr auto kMaxChatterRepeatInterval = 99.0f;
|
||||||
constexpr auto kViewFrameUpdate = 1.0f / 25.0f;
|
constexpr auto kViewFrameUpdate = 1.0f / 25.0f;
|
||||||
constexpr auto kGrenadeDamageRadius = 385.0f;
|
constexpr auto kGrenadeDamageRadius = 385.0f;
|
||||||
|
constexpr auto kMinMovedDistance = 3.0f;
|
||||||
|
|
||||||
constexpr auto kInfiniteDistanceLong = static_cast <int> (kInfiniteDistance);
|
constexpr auto kInfiniteDistanceLong = static_cast <int> (kInfiniteDistance);
|
||||||
constexpr auto kMaxWeapons = 32;
|
constexpr auto kMaxWeapons = 32;
|
||||||
|
|
|
||||||
|
|
@ -269,10 +269,6 @@ public:
|
||||||
const IntArray &getNodesInBucket (const Vector &pos);
|
const IntArray &getNodesInBucket (const Vector &pos);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int32_t getMaxRouteLength () const {
|
|
||||||
return (length () / 2) + (kMaxNodes / 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
StringRef getAuthor () const {
|
StringRef getAuthor () const {
|
||||||
return m_graphAuthor;
|
return m_graphAuthor;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ public:
|
||||||
|
|
||||||
// get route max length, route length should not be larger than half of map nodes
|
// get route max length, route length should not be larger than half of map nodes
|
||||||
size_t getMaxLength () const {
|
size_t getMaxLength () const {
|
||||||
return m_length / 2;
|
return m_length / 2 + kMaxNodes / 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -315,6 +315,7 @@ private:
|
||||||
|
|
||||||
PathWalk m_pathWalk {}; // pointer to current node from path
|
PathWalk m_pathWalk {}; // pointer to current node from path
|
||||||
Dodge m_dodgeStrafeDir {}; // direction to strafe
|
Dodge m_dodgeStrafeDir {}; // direction to strafe
|
||||||
|
Dodge m_avoidAction {}; // player avoid action
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -3149,7 +3149,7 @@ void Bot::checkSpawnConditions () {
|
||||||
|
|
||||||
// switch to knife if time to do this
|
// switch to knife if time to do this
|
||||||
if (m_checkKnifeSwitch && m_buyingFinished && m_spawnTime + rg (5.0f, 7.5f) < game.time ()) {
|
if (m_checkKnifeSwitch && m_buyingFinished && m_spawnTime + rg (5.0f, 7.5f) < game.time ()) {
|
||||||
if (rg (1, 100) < 2 && cv_spraypaints) {
|
if (!game.is (GameFlags::Xash3D) && 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3204,7 +3204,7 @@ void Bot::checkSpawnConditions () {
|
||||||
void Bot::logic () {
|
void Bot::logic () {
|
||||||
// this function gets called each frame and is the core of all bot ai. from here all other subroutines are called
|
// this function gets called each frame and is the core of all bot ai. from here all other subroutines are called
|
||||||
|
|
||||||
float movedDistance = 2.0f; // length of different vector (distance bot moved)
|
float movedDistance = kMinMovedDistance; // length of different vector (distance bot moved)
|
||||||
|
|
||||||
resetMovement ();
|
resetMovement ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -697,6 +697,27 @@ void Game::checkCvarsBounds () {
|
||||||
|
|
||||||
// notify about that
|
// notify about that
|
||||||
ctrl.msg ("Bogus value for cvar '%s', min is '%.1f' and max is '%.1f', and we're got '%s', value reverted to default '%.1f'.", var.name, var.min, var.max, str, var.initial);
|
ctrl.msg ("Bogus value for cvar '%s', min is '%.1f' and max is '%.1f', and we're got '%s', value reverted to default '%.1f'.", var.name, var.min, var.max, str, var.initial);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// prevent min/max problems
|
||||||
|
if (var.name.contains ("_max")) {
|
||||||
|
String minVar = String (var.name);
|
||||||
|
minVar.replace ("_max", "_min");
|
||||||
|
|
||||||
|
for (auto &mv : m_cvars) {
|
||||||
|
if (mv.name == minVar) {
|
||||||
|
const auto minValue = mv.self->as <float> ();
|
||||||
|
|
||||||
|
if (minValue > value) {
|
||||||
|
var.self->set (minValue);
|
||||||
|
mv.self->set (value);
|
||||||
|
|
||||||
|
// notify about that
|
||||||
|
ctrl.msg ("Bogus value for min/max cvar '%s' can't be higher than '%s'. Values swapped.", mv.name, var.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2541,7 +2541,7 @@ bool BotGraph::checkNodes (bool teleportPlayer, bool onlyPaths) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform DFS instead of floyd-warshall, this shit speedup this process in a bit
|
// perform DFS instead of floyd-warshall, this shit speedup this process in a bit
|
||||||
const auto length = cr::min (static_cast <size_t> (kMaxNodes), m_paths.length ());
|
const auto length = cr::min (static_cast <size_t> (kMaxNodes), m_paths.length () + 1);
|
||||||
|
|
||||||
// ensure valid capacity
|
// ensure valid capacity
|
||||||
assert (length > 8 && length < static_cast <size_t> (kMaxNodes));
|
assert (length > 8 && length < static_cast <size_t> (kMaxNodes));
|
||||||
|
|
|
||||||
|
|
@ -1233,12 +1233,13 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
|
||||||
// just to be sure
|
// just to be sure
|
||||||
m_msgQueue.clear ();
|
m_msgQueue.clear ();
|
||||||
|
|
||||||
// init path walker
|
|
||||||
m_pathWalk.init (graph.getMaxRouteLength ());
|
|
||||||
|
|
||||||
// init async planner
|
// init async planner
|
||||||
m_planner = cr::makeUnique <AStarAlgo> (graph.length ());
|
m_planner = cr::makeUnique <AStarAlgo> (graph.length ());
|
||||||
|
|
||||||
|
// init path walker
|
||||||
|
m_pathWalk.init (m_planner->getMaxLength ());
|
||||||
|
|
||||||
|
|
||||||
// init player models parts enumerator
|
// init player models parts enumerator
|
||||||
m_hitboxEnumerator = cr::makeUnique <PlayerHitboxEnumerator> ();
|
m_hitboxEnumerator = cr::makeUnique <PlayerHitboxEnumerator> ();
|
||||||
|
|
||||||
|
|
@ -1291,7 +1292,9 @@ int BotManager::getAliveHumansCount () {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (const auto &client : util.getClients ()) {
|
for (const auto &client : util.getClients ()) {
|
||||||
if ((client.flags & ClientFlags::Alive) && !bots[client.ent] && !(client.ent->v.flags & FL_FAKECLIENT)) {
|
if ((client.flags & ClientFlags::Alive)
|
||||||
|
&& !bots[client.ent]
|
||||||
|
&& !(client.ent->v.flags & FL_FAKECLIENT)) {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1299,24 +1302,28 @@ int BotManager::getAliveHumansCount () {
|
||||||
}
|
}
|
||||||
|
|
||||||
int BotManager::getPlayerPriority (edict_t *ent) {
|
int BotManager::getPlayerPriority (edict_t *ent) {
|
||||||
constexpr auto kHighPriority = 512;
|
constexpr auto kHighPriority = 1024;
|
||||||
|
|
||||||
// always check for only our own bots
|
// always check for only our own bots
|
||||||
auto bot = bots[ent];
|
auto bot = bots[ent];
|
||||||
|
|
||||||
// if player just return high prio
|
// if player just return high prio
|
||||||
if (!bot) {
|
if (!bot) {
|
||||||
return game.indexOfEntity (ent) + kHighPriority;
|
return game.indexOfEntity (ent) + kHighPriority * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// give bots some priority
|
// give bots some priority
|
||||||
if (bot->m_hasC4 || bot->m_isVIP || bot->m_hasHostage || bot->m_healthValue < ent->v.health || (bot->m_currentTravelFlags & PathFlag::Jump)) {
|
if (bot->m_hasC4 || bot->m_isVIP || bot->m_hasHostage || (bot->m_currentTravelFlags & PathFlag::Jump)) {
|
||||||
return bot->entindex () + kHighPriority;
|
return bot->entindex () + kHighPriority;
|
||||||
}
|
}
|
||||||
const auto task = bot->getCurrentTaskId ();
|
const auto task = bot->getCurrentTaskId ();
|
||||||
|
|
||||||
// higher priority if camping or hiding
|
// higher priority if important task
|
||||||
if (task == Task::Camp || task == Task::Hide || task == Task::MoveToPosition) {
|
if (task == Task::MoveToPosition
|
||||||
|
|| task == Task::SeekCover
|
||||||
|
|| task == Task::Camp
|
||||||
|
|| task == Task::Hide) {
|
||||||
|
|
||||||
return bot->entindex () + kHighPriority;
|
return bot->entindex () + kHighPriority;
|
||||||
}
|
}
|
||||||
return bot->entindex ();
|
return bot->entindex ();
|
||||||
|
|
@ -1623,6 +1630,7 @@ void Bot::newRound () {
|
||||||
m_zoomCheckTime = 0.0f;
|
m_zoomCheckTime = 0.0f;
|
||||||
m_strafeSetTime = 0.0f;
|
m_strafeSetTime = 0.0f;
|
||||||
m_dodgeStrafeDir = Dodge::None;
|
m_dodgeStrafeDir = Dodge::None;
|
||||||
|
m_avoidAction = Dodge::None;
|
||||||
m_fightStyle = Fight::None;
|
m_fightStyle = Fight::None;
|
||||||
m_lastFightStyleCheck = 0.0f;
|
m_lastFightStyleCheck = 0.0f;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -486,7 +486,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
|
||||||
const auto otherPrio = bots.getPlayerPriority (client.ent);
|
const auto otherPrio = bots.getPlayerPriority (client.ent);
|
||||||
|
|
||||||
// give some priorities to bot avoidance
|
// give some priorities to bot avoidance
|
||||||
if (ownPrio > otherPrio) {
|
if (ownPrio < otherPrio) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,7 +495,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
|
||||||
const auto avoidPrio = bots.getPlayerPriority (m_hindrance);
|
const auto avoidPrio = bots.getPlayerPriority (m_hindrance);
|
||||||
|
|
||||||
// ignore because we're already avoiding someone better
|
// ignore because we're already avoiding someone better
|
||||||
if (avoidPrio > otherPrio) {
|
if (avoidPrio < otherPrio) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -509,8 +509,17 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
|
||||||
|
|
||||||
// found somebody?
|
// found somebody?
|
||||||
if (game.isNullEntity (m_hindrance)) {
|
if (game.isNullEntity (m_hindrance)) {
|
||||||
|
m_avoidAction = Dodge::None;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (m_avoidAction != Dodge::None) {
|
||||||
|
if (m_avoidAction == Dodge::Left) {
|
||||||
|
setStrafeSpeed (normal, pev->maxspeed);
|
||||||
|
}
|
||||||
|
else if (m_avoidAction == Dodge::Right) {
|
||||||
|
setStrafeSpeed (normal, -pev->maxspeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
const float interval = m_frameInterval * (!isDucking () && pev->velocity.lengthSq2d () > 0.0f ? 7.5f : 2.0f);
|
const float interval = m_frameInterval * (!isDucking () && pev->velocity.lengthSq2d () > 0.0f ? 7.5f : 2.0f);
|
||||||
|
|
||||||
// use our movement angles, try to predict where we should be next frame
|
// use our movement angles, try to predict where we should be next frame
|
||||||
|
|
@ -526,16 +535,25 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
|
||||||
const auto nextFrameDistanceSq = pev->origin.distanceSq (m_hindrance->v.origin + m_hindrance->v.velocity * interval);
|
const auto nextFrameDistanceSq = pev->origin.distanceSq (m_hindrance->v.origin + m_hindrance->v.velocity * interval);
|
||||||
|
|
||||||
// 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 (96.0f) && nextFrameDistanceSq < distanceSq)) {
|
||||||
const 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 (m_avoidAction == Dodge::None && m_path->radius > 16.0f && !isInNarrowPlace ()) {
|
||||||
if ((dir | right.normalize2d_apx ()) > 0.0f) {
|
if ((dir | right.normalize2d_apx ()) > 0.0f) {
|
||||||
|
m_avoidAction = Dodge::Left;
|
||||||
|
|
||||||
|
// start strafing
|
||||||
setStrafeSpeed (normal, pev->maxspeed);
|
setStrafeSpeed (normal, pev->maxspeed);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
m_avoidAction = Dodge::Right;
|
||||||
|
|
||||||
|
// start strafing
|
||||||
setStrafeSpeed (normal, -pev->maxspeed);
|
setStrafeSpeed (normal, -pev->maxspeed);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
m_isStuck = false;
|
||||||
|
|
||||||
if (distanceSq < cr::sqrf (96.0f)) {
|
if (distanceSq < cr::sqrf (96.0f)) {
|
||||||
if ((dir | forward.normalize2d_apx ()) < 0.0f) {
|
if ((dir | forward.normalize2d_apx ()) < 0.0f) {
|
||||||
|
|
@ -545,6 +563,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
|
||||||
m_moveSpeed = pev->maxspeed;
|
m_moveSpeed = pev->maxspeed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ignoreCollision ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -557,7 +576,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
|
||||||
// standing still, no need to check?
|
// standing still, no need to check?
|
||||||
if (m_lastCollTime < game.time () && getCurrentTaskId () != Task::Attack) {
|
if (m_lastCollTime < game.time () && getCurrentTaskId () != Task::Attack) {
|
||||||
// didn't we move enough previously?
|
// didn't we move enough previously?
|
||||||
if (movedDistance < 2.0f && (m_prevSpeed > 20.0f || m_prevVelocity < m_moveSpeed / 2)) {
|
if (movedDistance < kMinMovedDistance && (m_prevSpeed > 20.0f || m_prevVelocity < m_moveSpeed / 2)) {
|
||||||
m_prevTime = game.time (); // then consider being stuck
|
m_prevTime = game.time (); // then consider being stuck
|
||||||
m_isStuck = true;
|
m_isStuck = true;
|
||||||
|
|
||||||
|
|
@ -1241,7 +1260,7 @@ bool Bot::updateNavigation () {
|
||||||
}
|
}
|
||||||
|
|
||||||
float desiredDistanceSq = cr::sqrf (8.0f);
|
float desiredDistanceSq = cr::sqrf (8.0f);
|
||||||
const float nodeDistanceSq = pev->origin.distanceSq (m_pathOrigin);
|
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
|
||||||
if (m_pathFlags & NodeFlag::Lift) {
|
if (m_pathFlags & NodeFlag::Lift) {
|
||||||
|
|
@ -1264,17 +1283,17 @@ bool Bot::updateNavigation () {
|
||||||
else if (m_path->number == cv_debug_goal.as <int> ()) {
|
else if (m_path->number == cv_debug_goal.as <int> ()) {
|
||||||
desiredDistanceSq = 0.0f;
|
desiredDistanceSq = 0.0f;
|
||||||
}
|
}
|
||||||
else if (isOccupiedNode (m_path->number)) {
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
bool pathHasFlags = false;
|
||||||
|
|
||||||
// check if node has a special travel flags, so they need to be reached more precisely
|
// check if node has a special travel flags, so they need to be reached more precisely
|
||||||
for (const auto &link : m_path->links) {
|
for (const auto &link : m_path->links) {
|
||||||
if (link.flags != 0) {
|
if (link.flags != 0) {
|
||||||
desiredDistanceSq = 0.0f;
|
desiredDistanceSq = 0.0f;
|
||||||
|
pathHasFlags = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1284,6 +1303,12 @@ bool Bot::updateNavigation () {
|
||||||
desiredDistanceSq = 0.0f;
|
desiredDistanceSq = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// always increase reachability distance for occupied nodes
|
||||||
|
if (isOccupiedNode (m_path->number, pathHasFlags)) {
|
||||||
|
desiredDistanceSq = cr::sqrf (96.0f);
|
||||||
|
nodeDistanceSq *= 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
// needs precise placement - check if we get past the point
|
// needs precise placement - check if we get past the point
|
||||||
if (desiredDistanceSq < cr::sqrf (20.0f) && nodeDistanceSq < cr::sqrf (30.0f)) {
|
if (desiredDistanceSq < cr::sqrf (20.0f) && nodeDistanceSq < cr::sqrf (30.0f)) {
|
||||||
const auto predictRangeSq = m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval);
|
const auto predictRangeSq = m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval);
|
||||||
|
|
@ -1297,12 +1322,13 @@ bool Bot::updateNavigation () {
|
||||||
// is sitting there, so the bot is unable to reach the node because of other player on it, and he starts to jumping and so on
|
// is sitting there, so the bot is unable to reach the node because of other player on it, and he starts to jumping and so on
|
||||||
// here we're clearing task memory data (important!), since task executor may restart goal with one from memory, so this process
|
// here we're clearing task memory data (important!), since task executor may restart goal with one from memory, so this process
|
||||||
// will go in cycle, and forcing bot to re-create new route.
|
// will go in cycle, and forcing bot to re-create new route.
|
||||||
if (m_pathWalk.hasNext () && m_pathWalk.next () == m_pathWalk.last () && isOccupiedNode (m_pathWalk.next (), true)) {
|
if (m_pathWalk.hasNext () && m_pathWalk.next () == m_pathWalk.last () && isOccupiedNode (m_pathWalk.next (), pathHasFlags)) {
|
||||||
getTask ()->data = kInvalidNodeIndex;
|
getTask ()->data = kInvalidNodeIndex;
|
||||||
m_currentNodeIndex = kInvalidNodeIndex;
|
|
||||||
|
|
||||||
clearSearchNodes ();
|
m_currentNodeIndex = kInvalidNodeIndex;
|
||||||
return false;
|
m_chosenGoalIndex = kInvalidNodeIndex;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeDistanceSq <= desiredDistanceSq) {
|
if (nodeDistanceSq <= desiredDistanceSq) {
|
||||||
|
|
@ -2591,8 +2617,12 @@ void Bot::setPathOrigin () {
|
||||||
constexpr int kMaxAlternatives = 5;
|
constexpr int kMaxAlternatives = 5;
|
||||||
const float radius = m_path->radius;
|
const float radius = m_path->radius;
|
||||||
|
|
||||||
|
auto setNonZeroPathOrigin = [&] () -> void {
|
||||||
|
m_pathOrigin += Vector { pev->angles.x, cr::wrapAngle (pev->angles.y + rg (-90.0f, 90.0f)), 0.0f }.forward () * rg (0.0f, radius);
|
||||||
|
};
|
||||||
|
|
||||||
// if node radius non zero vary origin a bit depending on the body angles
|
// if node radius non zero vary origin a bit depending on the body angles
|
||||||
if (radius > 0.0f) {
|
if (radius > 16.0f) {
|
||||||
int nearestIndex = kInvalidNodeIndex;
|
int nearestIndex = kInvalidNodeIndex;
|
||||||
|
|
||||||
if (!m_pathWalk.empty () && m_pathWalk.hasNext ()) {
|
if (!m_pathWalk.empty () && m_pathWalk.hasNext ()) {
|
||||||
|
|
@ -2619,9 +2649,12 @@ void Bot::setPathOrigin () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nearestIndex == kInvalidNodeIndex) {
|
if (nearestIndex == kInvalidNodeIndex) {
|
||||||
m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg (-90.0f, 90.0f)), 0.0f).forward () * rg (0.0f, radius);
|
setNonZeroPathOrigin ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (radius > 0.0f) {
|
||||||
|
setNonZeroPathOrigin ();
|
||||||
|
}
|
||||||
|
|
||||||
if (isOnLadder ()) {
|
if (isOnLadder ()) {
|
||||||
TraceResult tr {};
|
TraceResult tr {};
|
||||||
|
|
@ -3246,7 +3279,7 @@ bool Bot::isOccupiedNode (int index, bool needZeroVelocity) {
|
||||||
}
|
}
|
||||||
const auto distanceSq = client.origin.distanceSq (graph[index].origin);
|
const auto distanceSq = client.origin.distanceSq (graph[index].origin);
|
||||||
|
|
||||||
if (distanceSq < cr::clamp (cr::sqrf (graph[index].radius) * 2.0f, cr::sqrf (90.0f), cr::sqrf (120.0f))) {
|
if (distanceSq < cr::clamp (cr::sqrf (graph[index].radius) * 2.0f, cr::sqrf (98.0f), cr::sqrf (120.0f))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
auto bot = bots[client.ent];
|
auto bot = bots[client.ent];
|
||||||
|
|
|
||||||
|
|
@ -106,16 +106,19 @@ bool BotSupport::isVisible (const Vector &origin, edict_t *ent) {
|
||||||
void BotSupport::decalTrace (entvars_t *pev, TraceResult *trace, int logotypeIndex) {
|
void BotSupport::decalTrace (entvars_t *pev, TraceResult *trace, int logotypeIndex) {
|
||||||
// this function draw spraypaint depending on the tracing results.
|
// this function draw spraypaint depending on the tracing results.
|
||||||
|
|
||||||
|
if (cr::fequal (trace->flFraction, 1.0f)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto logo = conf.getLogoName (logotypeIndex);
|
auto logo = conf.getLogoName (logotypeIndex);
|
||||||
|
|
||||||
int entityIndex = -1, message = TE_DECAL;
|
int entityIndex = -1, message = TE_DECAL;
|
||||||
int decalIndex = engfuncs.pfnDecalIndex (logo.chars ());
|
int decalIndex = engfuncs.pfnDecalIndex (logo.chars ());
|
||||||
|
|
||||||
if (decalIndex < 0) {
|
if (decalIndex <= 0) {
|
||||||
decalIndex = engfuncs.pfnDecalIndex ("{lambda06");
|
decalIndex = engfuncs.pfnDecalIndex ("{lambda06");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cr::fequal (trace->flFraction, 1.0f)) {
|
if (decalIndex <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,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 ()
|
||||||
|
&& !game.is (GameFlags::Xash3D)
|
||||||
&& cv_spraypaints
|
&& cv_spraypaints
|
||||||
&& rg.chance (50)
|
&& rg.chance (50)
|
||||||
&& m_moveSpeed > getShiftSpeed ()
|
&& m_moveSpeed > getShiftSpeed ()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue