nav: more fixes to ladder navigation
refactor: bot difficulty data and add graph refresh command combat: fixes for smoke grenades (ref #743) engine: fixes to spawn management (ref #744)
This commit is contained in:
parent
7b378ba3fa
commit
17ed252b60
26 changed files with 506 additions and 408 deletions
201
src/navigate.cpp
201
src/navigate.cpp
|
|
@ -470,7 +470,7 @@ void Bot::resetCollision () {
|
|||
void Bot::ignoreCollision () {
|
||||
resetCollision ();
|
||||
|
||||
m_lastCollTime = game.time () + 0.5f;
|
||||
m_lastCollTime = game.time () + 0.65f;
|
||||
m_checkTerrain = false;
|
||||
}
|
||||
|
||||
|
|
@ -602,11 +602,11 @@ void Bot::checkTerrain (const Vector &dirNormal) {
|
|||
const auto tid = getCurrentTaskId ();
|
||||
|
||||
// minimal speed for consider stuck
|
||||
const float minimalSpeed = isDucking () ? kMinMovedDistance : kMinMovedDistance * 4;
|
||||
const float minimalSpeed = isDucking () ? 7.0f : 10.0f;
|
||||
const auto randomProbeTime = rg (0.50f, 0.75f);
|
||||
|
||||
// standing still, no need to check?
|
||||
if ((cr::abs (m_moveSpeed) >= minimalSpeed || cr::abs (m_strafeSpeed) >= minimalSpeed)
|
||||
if ((m_moveSpeed >= minimalSpeed || m_strafeSpeed >= minimalSpeed)
|
||||
&& m_lastCollTime < game.time ()
|
||||
&& tid != Task::Attack
|
||||
&& tid != Task::Camp) {
|
||||
|
|
@ -617,7 +617,7 @@ void Bot::checkTerrain (const Vector &dirNormal) {
|
|||
m_firstCollideTime = 0.0f;
|
||||
}
|
||||
// didn't we move enough previously?
|
||||
else if (m_movedDistance < kMinMovedDistance && (m_prevSpeed > 20.0f || m_prevVelocity < m_moveSpeed / 2)) {
|
||||
else if (m_movedDistance < kMinMovedDistance && m_prevSpeed > 20.0f) {
|
||||
m_prevTime = game.time (); // then consider being stuck
|
||||
m_isStuck = true;
|
||||
|
||||
|
|
@ -653,14 +653,16 @@ void Bot::checkTerrain (const Vector &dirNormal) {
|
|||
resetCollision (); // reset collision memory if not being stuck for 0.5 secs
|
||||
}
|
||||
else {
|
||||
const auto state = m_collideMoves[m_collStateIndex];
|
||||
|
||||
// remember to keep pressing stuff if it was necessary ago
|
||||
if (m_collideMoves[m_collStateIndex] == CollisionState::Duck && (isOnFloor () || isInWater ())) {
|
||||
if (state == CollisionState::Duck && (isOnFloor () || isInWater ())) {
|
||||
pev->button |= IN_DUCK;
|
||||
}
|
||||
else if (m_collideMoves[m_collStateIndex] == CollisionState::StrafeLeft) {
|
||||
else if (state == CollisionState::StrafeLeft) {
|
||||
setStrafeSpeed (dirNormal, -pev->maxspeed);
|
||||
}
|
||||
else if (m_collideMoves[m_collStateIndex] == CollisionState::StrafeRight) {
|
||||
else if (state == CollisionState::StrafeRight) {
|
||||
setStrafeSpeed (dirNormal, pev->maxspeed);
|
||||
}
|
||||
}
|
||||
|
|
@ -683,6 +685,7 @@ void Bot::checkTerrain (const Vector &dirNormal) {
|
|||
bits |= CollisionProbe::Duck;
|
||||
}
|
||||
|
||||
|
||||
// collision check allowed if not flying through the air
|
||||
if (isOnFloor () || isOnLadder () || isInWater ()) {
|
||||
uint32_t state[kMaxCollideMoves * 2 + 1] {};
|
||||
|
|
@ -696,7 +699,6 @@ void Bot::checkTerrain (const Vector &dirNormal) {
|
|||
state[i++] = CollisionState::StrafeRight;
|
||||
state[i++] = CollisionState::Duck;
|
||||
|
||||
// now weight all possible states
|
||||
if (bits & CollisionProbe::Jump) {
|
||||
state[i] = 0;
|
||||
|
||||
|
|
@ -745,7 +747,7 @@ void Bot::checkTerrain (const Vector &dirNormal) {
|
|||
}
|
||||
++i;
|
||||
|
||||
|
||||
// now weight all possible states
|
||||
if (bits & CollisionProbe::Strafe) {
|
||||
state[i] = 0;
|
||||
state[i + 1] = 0;
|
||||
|
|
@ -813,6 +815,7 @@ void Bot::checkTerrain (const Vector &dirNormal) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (bits & CollisionProbe::Duck) {
|
||||
state[i] = 0;
|
||||
|
||||
|
|
@ -901,7 +904,7 @@ void Bot::checkTerrain (const Vector &dirNormal) {
|
|||
}
|
||||
|
||||
void Bot::checkFall () {
|
||||
if (isPreviousLadder () || (m_pathFlags & NodeFlag::Ladder)) {
|
||||
if (isPreviousLadder () || (m_pathFlags & NodeFlag::Ladder) || isOnLadder ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -945,26 +948,28 @@ void Bot::checkFall () {
|
|||
const float nowDistanceSq = pev->origin.distanceSq (m_checkFallPoint[1]);
|
||||
|
||||
if (nowDistanceSq > baseDistanceSq
|
||||
&& (nowDistanceSq > baseDistanceSq * 1.2f || nowDistanceSq > baseDistanceSq + 200.0f)
|
||||
&& baseDistanceSq >= cr::sqrf (80.0f) && nowDistanceSq >= cr::sqrf (100.0f)) {
|
||||
&& (nowDistanceSq > baseDistanceSq * 1.8f || nowDistanceSq > baseDistanceSq + 260.0f)
|
||||
&& baseDistanceSq >= cr::sqrf (124.0f) && nowDistanceSq >= cr::sqrf (146.0f)) {
|
||||
fixFall = true;
|
||||
|
||||
}
|
||||
else if (m_checkFallPoint[1].z > pev->origin.z + 128.0f
|
||||
&& m_checkFallPoint[0].z > pev->origin.z + 128.0f) {
|
||||
else if (m_checkFallPoint[1].z > pev->origin.z + 138.0f
|
||||
|| m_checkFallPoint[0].z > pev->origin.z + 138.0f) {
|
||||
fixFall = true;
|
||||
}
|
||||
else if (m_currentNodeIndex != kInvalidNodeIndex
|
||||
&& nowDistanceSq > cr::sqrf (16.0f)
|
||||
&& m_checkFallPoint[1].z > pev->origin.z + 62.0f) {
|
||||
&& nowDistanceSq > cr::sqrf (32.0f)
|
||||
&& m_checkFallPoint[1].z > pev->origin.z + 72.0f) {
|
||||
fixFall = true;
|
||||
}
|
||||
|
||||
if (fixFall) {
|
||||
m_currentNodeIndex = kInvalidNodeIndex;
|
||||
findValidNode ();
|
||||
if (graph.exists (m_currentNodeIndex) && !isReachableNode (m_currentNodeIndex)) {
|
||||
m_currentNodeIndex = kInvalidNodeIndex;
|
||||
findValidNode ();
|
||||
|
||||
m_fixFallTimer.start (1.0f);
|
||||
m_fixFallTimer.start (1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1000,22 +1005,22 @@ void Bot::moveToGoal () {
|
|||
// press jump button if we need to leave the ladder
|
||||
if (!(m_pathFlags & NodeFlag::Ladder)
|
||||
&& isPreviousLadder ()
|
||||
&& isOnFloor ()
|
||||
&& isOnLadder ()
|
||||
&& m_moveSpeed > 50.0f
|
||||
&& pev->velocity.lengthSq () < 50.0f) {
|
||||
&& pev->velocity.lengthSq () < 50.0f
|
||||
&& m_ladderDir == LadderDir::Down) {
|
||||
|
||||
pev->button |= IN_JUMP;
|
||||
m_jumpTime = game.time () + 1.0f;
|
||||
}
|
||||
#if 0
|
||||
const auto distanceSq2d = m_destOrigin.distanceSq2d (pev->origin + pev->velocity * m_frameInterval);
|
||||
|
||||
if (distanceSq2d < cr::sqrf (m_moveSpeed) * m_frameInterval && getTask ()->data != kInvalidNodeIndex) {
|
||||
m_moveSpeed = distanceSq2d;
|
||||
}
|
||||
if (m_moveSpeed > pev->maxspeed) {
|
||||
m_moveSpeed = pev->maxspeed;
|
||||
if (distanceSq2d < cr::sqrf (m_moveSpeed * m_frameInterval) && getTask ()->data != kInvalidNodeIndex) {
|
||||
m_moveSpeed = distanceSq2d * 2.0f;
|
||||
}
|
||||
m_moveSpeed = cr::clamp (m_moveSpeed, 4.0f, pev->maxspeed);
|
||||
#endif
|
||||
m_lastUsedNodesTime = game.time ();
|
||||
|
||||
// special movement for swimming here
|
||||
|
|
@ -1135,10 +1140,11 @@ bool Bot::updateNavigation () {
|
|||
m_jumpFinished = true;
|
||||
m_checkTerrain = false;
|
||||
m_desiredVelocity.clear ();
|
||||
m_currentTravelFlags &= ~PathFlag::Jump;
|
||||
|
||||
// cool down a little if next path after current will be jump
|
||||
if (m_jumpSequence) {
|
||||
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg (0.75f, 1.2f) + m_frameInterval, false);
|
||||
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + rg (0.75f, 1.25f) + m_frameInterval, false);
|
||||
m_jumpSequence = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1149,19 +1155,13 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
|
||||
if (m_pathFlags & NodeFlag::Ladder) {
|
||||
constexpr auto kLadderOffset = Vector { 0.0f, 0.0f, 36.0f };
|
||||
|
||||
const auto prevNodeIndex = m_previousNodes[0];
|
||||
const float ladderDistance = pev->origin.distance (m_pathOrigin);
|
||||
const auto ladderDistanceSq = pev->origin.distanceSq (m_pathOrigin);
|
||||
|
||||
// do a precise movement when very near
|
||||
if (graph.exists (prevNodeIndex) && !(graph[prevNodeIndex].flags & NodeFlag::Ladder) && ladderDistance < 64.0f) {
|
||||
if (m_pathOrigin.z >= pev->origin.z + 16.0f) {
|
||||
m_pathOrigin = m_path->origin + kLadderOffset;
|
||||
}
|
||||
else if (m_pathOrigin.z < pev->origin.z - 16.0f) {
|
||||
m_pathOrigin = m_path->origin - kLadderOffset;
|
||||
}
|
||||
if (graph.exists (prevNodeIndex)
|
||||
&& !(graph[prevNodeIndex].flags & NodeFlag::Ladder)
|
||||
&& ladderDistanceSq < cr::sqrf (64.0f)) {
|
||||
|
||||
if (!isDucking ()) {
|
||||
m_moveSpeed = pev->maxspeed * 0.4f;
|
||||
|
|
@ -1171,20 +1171,14 @@ bool Bot::updateNavigation () {
|
|||
if (!isOnLadder ()) {
|
||||
pev->button &= ~IN_DUCK;
|
||||
}
|
||||
m_approachingLadderTimer.start (m_frameInterval * 6.0f);
|
||||
m_approachingLadderTimer.start (2.0f * m_frameInterval);
|
||||
}
|
||||
|
||||
if (!isOnLadder () && isOnFloor () && !isDucking ()) {
|
||||
if (!isPreviousLadder ()) {
|
||||
m_moveSpeed = ladderDistance;
|
||||
}
|
||||
|
||||
if (m_moveSpeed < 150.0f) {
|
||||
m_moveSpeed = 150.0f;
|
||||
}
|
||||
else if (m_moveSpeed > pev->maxspeed) {
|
||||
m_moveSpeed = pev->maxspeed;
|
||||
m_moveSpeed = cr::sqrtf (ladderDistanceSq);
|
||||
}
|
||||
m_moveSpeed = cr::clamp (m_moveSpeed, 160.0f, pev->maxspeed);
|
||||
}
|
||||
|
||||
// special detection if someone is using the ladder (to prevent to have bots-towers on ladders)
|
||||
|
|
@ -1238,7 +1232,7 @@ bool Bot::updateNavigation () {
|
|||
ignoreCollision (); // don't consider being stuck
|
||||
|
||||
// also 'use' the door randomly
|
||||
if (rg.chance (50)) {
|
||||
if (m_buttonPushTime < game.time () && rg.chance (50)) {
|
||||
// do not use door directly under xash, or we will get failed assert in gamedll code
|
||||
if (game.is (GameFlags::Xash3D)) {
|
||||
pev->button |= IN_USE;
|
||||
|
|
@ -1252,7 +1246,7 @@ bool Bot::updateNavigation () {
|
|||
|
||||
// make sure we are always facing the door when going through it
|
||||
m_aimFlags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
|
||||
m_canChooseAimDirection = false;
|
||||
m_canSetAimDirection = false;
|
||||
|
||||
// delay task
|
||||
if (m_buttonPushTime < game.time ()) {
|
||||
|
|
@ -1322,26 +1316,35 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
}
|
||||
|
||||
float desiredDistanceSq = cr::sqrf (32.0f);
|
||||
const float nodeDistanceSq = pev->origin.distanceSq (m_pathOrigin);
|
||||
float desiredDistanceSq = cr::sqrf (48.0f);
|
||||
float nodeDistanceSq = pev->origin.distanceSq (m_pathOrigin);
|
||||
|
||||
// initialize the radius for a special node type, where the node is considered to be reached
|
||||
if (m_pathFlags & NodeFlag::Lift) {
|
||||
desiredDistanceSq = cr::sqrf (50.0f);
|
||||
}
|
||||
else if (isDucking () || (m_pathFlags & NodeFlag::Goal)) {
|
||||
desiredDistanceSq = cr::sqrf (9.0f);
|
||||
desiredDistanceSq = cr::sqrf (25.0f);
|
||||
|
||||
// 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)) {
|
||||
|
||||
desiredDistanceSq = cr::sqrf (96.0f);
|
||||
}
|
||||
}
|
||||
else if (m_pathFlags & NodeFlag::Ladder) {
|
||||
desiredDistanceSq = cr::sqrf (16.0f);
|
||||
else if (isOnLadder () || (m_pathFlags & NodeFlag::Ladder)) {
|
||||
desiredDistanceSq = cr::sqrf (15.0f);
|
||||
}
|
||||
else if (m_currentTravelFlags & PathFlag::Jump) {
|
||||
desiredDistanceSq = 0.0f;
|
||||
|
||||
if (pev->velocity.z > 16.0f) {
|
||||
desiredDistanceSq = cr::sqrf (8.0f);
|
||||
}
|
||||
}
|
||||
else if (m_pathFlags & NodeFlag::Crouch) {
|
||||
desiredDistanceSq = cr::sqrf (6.0f);
|
||||
}
|
||||
else if (m_path->number == cv_debug_goal.as <int> ()) {
|
||||
desiredDistanceSq = 0.0f;
|
||||
|
|
@ -1368,14 +1371,14 @@ bool Bot::updateNavigation () {
|
|||
|
||||
// if just recalculated path, assume reached current node
|
||||
if (!m_repathTimer.elapsed () && !pathHasFlags) {
|
||||
desiredDistanceSq = cr::sqrf (72.0f);
|
||||
desiredDistanceSq = cr::sqrf (48.0f);
|
||||
}
|
||||
|
||||
// needs precise placement - check if we get past the point
|
||||
if (desiredDistanceSq < cr::sqrf (16.0f) && nodeDistanceSq < cr::sqrf (30.0f)) {
|
||||
const auto predictRangeSq = m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval);
|
||||
|
||||
if (predictRangeSq >= nodeDistanceSq || predictRangeSq <= desiredDistanceSq) {
|
||||
if (predictRangeSq > nodeDistanceSq || predictRangeSq <= desiredDistanceSq) {
|
||||
desiredDistanceSq = nodeDistanceSq + 1.0f;
|
||||
}
|
||||
}
|
||||
|
|
@ -1410,6 +1413,9 @@ bool Bot::updateNavigation () {
|
|||
|
||||
// update the practice for team
|
||||
practice.setValue (m_team, m_chosenGoalIndex, m_currentNodeIndex, goalValue);
|
||||
|
||||
// ignore collision
|
||||
ignoreCollision ();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1870,7 +1876,7 @@ bool Bot::findNextBestNodeEx (const IntArray &data, bool handleFails) {
|
|||
}
|
||||
|
||||
// in case low node density do not skip previous ones, in case of fail reduce max nodes to skip
|
||||
const auto &numToSkip = graph.length () < 512 ? 0 : (handleFails ? 1 : rg (1, 4));
|
||||
const auto &numToSkip = graph.length () < 512 || m_isStuck ? 0 : (handleFails ? 1 : rg (1, 4));
|
||||
|
||||
for (const auto &i : data) {
|
||||
const auto &path = graph[i];
|
||||
|
|
@ -2460,7 +2466,7 @@ bool Bot::selectBestNextNode () {
|
|||
const auto currentNodeIndex = m_pathWalk.first ();
|
||||
const auto prevNodeIndex = m_currentNodeIndex;
|
||||
|
||||
if (!isOccupiedNode (currentNodeIndex)) {
|
||||
if (isOnLadder () || !isOccupiedNode (currentNodeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2590,10 +2596,11 @@ bool Bot::advanceMovement () {
|
|||
bool isCurrentJump = false;
|
||||
|
||||
// find out about connection flags
|
||||
if (destIndex != kInvalidNodeIndex && m_currentNodeIndex != kInvalidNodeIndex) {
|
||||
if (graph.exists (destIndex) && m_path) {
|
||||
for (const auto &link : m_path->links) {
|
||||
if (link.index == destIndex) {
|
||||
m_currentTravelFlags = link.flags;
|
||||
|
||||
m_desiredVelocity = link.velocity;
|
||||
m_jumpFinished = false;
|
||||
|
||||
|
|
@ -2603,7 +2610,7 @@ bool Bot::advanceMovement () {
|
|||
}
|
||||
|
||||
// if graph is analyzed try our special jumps
|
||||
if (graph.isAnalyzed () || analyzer.isAnalyzed ()) {
|
||||
if ((graph.isAnalyzed () || analyzer.isAnalyzed ()) && !(m_path->flags & NodeFlag::Ladder)) {
|
||||
for (const auto &link : m_path->links) {
|
||||
if (link.index == destIndex) {
|
||||
const float diff = cr::abs (m_path->origin.z - graph[destIndex].origin.z);
|
||||
|
|
@ -2666,6 +2673,7 @@ bool Bot::advanceMovement () {
|
|||
|
||||
// get ladder nodes used by other (first moving) bots
|
||||
for (const auto &other : bots) {
|
||||
|
||||
// if another bot uses this ladder, wait 3 secs
|
||||
if (other.get () != this && other->m_isAlive && other->m_currentNodeIndex == destIndex && other->isOnLadder ()) {
|
||||
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + 3.0f, false);
|
||||
|
|
@ -2725,21 +2733,30 @@ void Bot::setPathOrigin () {
|
|||
else if (radius > 0.0f) {
|
||||
setNonZeroPathOrigin ();
|
||||
}
|
||||
|
||||
if (isOnLadder ()) {
|
||||
TraceResult tr {};
|
||||
game.testLine (Vector (pev->origin.x, pev->origin.y, pev->absmin.z), m_pathOrigin, TraceIgnore::Everything, ent (), &tr);
|
||||
edict_t *ladder = nullptr;
|
||||
|
||||
if (tr.flFraction < 1.0f) {
|
||||
m_pathOrigin = m_pathOrigin + (pev->origin - m_pathOrigin) * 0.5f + Vector (0.0f, 0.0f, 32.0f);
|
||||
game.searchEntities (m_pathOrigin, 96.0f, [&] (edict_t *e) {
|
||||
if (e->v.classname.str () == "func_ladder") {
|
||||
ladder = e;
|
||||
return EntitySearchResult::Break;
|
||||
}
|
||||
return EntitySearchResult::Continue;
|
||||
});
|
||||
|
||||
|
||||
if (!game.isNullEntity (ladder)) {
|
||||
TraceResult tr {};
|
||||
game.testLine ({ pev->origin.x, pev->origin.y, ladder->v.absmin.z }, m_pathOrigin, TraceIgnore::Monsters, ent (), &tr);
|
||||
|
||||
if (tr.flFraction < 1.0f) {
|
||||
m_pathOrigin = graph[m_currentNodeIndex].origin + (pev->origin - m_pathOrigin) * 0.5 + Vector (0.0f, 0.0f, 32.0f);
|
||||
}
|
||||
m_ladderDir = m_pathOrigin.z < pev->origin.z ? LadderDir::Down : LadderDir::Up;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::updateRightRef () {
|
||||
m_rightRef = Vector { 0.0f, pev->angles.y, 0.0f }.right (); // convert current view angle to vectors for traceline math...
|
||||
}
|
||||
|
||||
bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
||||
// checks if bot is blocked in his movement direction (excluding doors)
|
||||
|
||||
|
|
@ -2774,12 +2791,12 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
constexpr auto kVec00N16 = Vector (0.0f, 0.0f, -16.0f);
|
||||
|
||||
// right referential vector
|
||||
updateRightRef ();
|
||||
auto right = Vector { 0.0f, pev->angles.y, 0.0f }.right ();
|
||||
|
||||
// bot's head is clear, check at shoulder level...
|
||||
// trace from the bot's shoulder left diagonal forward to the right shoulder...
|
||||
src = getEyesPos () + kVec00N16 - m_rightRef * -16.0f;
|
||||
forward = getEyesPos () + kVec00N16 + m_rightRef * 16.0f + normal * 24.0f;
|
||||
src = getEyesPos () + kVec00N16 - right * -16.0f;
|
||||
forward = getEyesPos () + kVec00N16 + right * 16.0f + normal * 24.0f;
|
||||
|
||||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
|
|
@ -2790,8 +2807,8 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
|
||||
// bot's head is clear, check at shoulder level...
|
||||
// trace from the bot's shoulder right diagonal forward to the left shoulder...
|
||||
src = getEyesPos () + kVec00N16 + m_rightRef * 16.0f;
|
||||
forward = getEyesPos () + kVec00N16 - m_rightRef * -16.0f + normal * 24.0f;
|
||||
src = getEyesPos () + kVec00N16 + right * 16.0f;
|
||||
forward = getEyesPos () + kVec00N16 - right * -16.0f + normal * 24.0f;
|
||||
|
||||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
|
|
@ -2826,8 +2843,8 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
constexpr auto kVec00N24 = Vector (0.0f, 0.0f, -24.0f);
|
||||
|
||||
// trace from the left waist to the right forward waist pos
|
||||
src = pev->origin + kVec00N17 - m_rightRef * -16.0f;
|
||||
forward = pev->origin + kVec00N17 + m_rightRef * 16.0f + normal * 24.0f;
|
||||
src = pev->origin + kVec00N17 - right * -16.0f;
|
||||
forward = pev->origin + kVec00N17 + right * 16.0f + normal * 24.0f;
|
||||
|
||||
// trace from the bot's waist straight forward...
|
||||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
|
@ -2838,8 +2855,8 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
}
|
||||
|
||||
// trace from the left waist to the right forward waist pos
|
||||
src = pev->origin + kVec00N24 + m_rightRef * 16.0f;
|
||||
forward = pev->origin + kVec00N24 - m_rightRef * -16.0f + normal * 24.0f;
|
||||
src = pev->origin + kVec00N24 + right * 16.0f;
|
||||
forward = pev->origin + kVec00N24 - right * -16.0f + normal * 24.0f;
|
||||
|
||||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
|
|
@ -2918,7 +2935,7 @@ bool Bot::canJumpUp (const Vector &normal) {
|
|||
if (!isOnFloor () && (isOnLadder () || !isInWater ())) {
|
||||
return false;
|
||||
}
|
||||
updateRightRef ();
|
||||
auto right = Vector { 0.0f, pev->angles.y, 0.0f }.right (); // convert current view angle to vectors for traceline math...
|
||||
|
||||
// check for normal jump height first...
|
||||
auto src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 45.0f);
|
||||
|
|
@ -2928,7 +2945,7 @@ bool Bot::canJumpUp (const Vector &normal) {
|
|||
game.testLine (src, dest, TraceIgnore::Monsters, ent (), &tr);
|
||||
|
||||
if (tr.flFraction < 1.0f) {
|
||||
return doneCanJumpUp (normal, m_rightRef);
|
||||
return doneCanJumpUp (normal, right);
|
||||
}
|
||||
else {
|
||||
// now trace from jump height upward to check for obstructions...
|
||||
|
|
@ -2943,7 +2960,7 @@ bool Bot::canJumpUp (const Vector &normal) {
|
|||
}
|
||||
|
||||
// now check same height to one side of the bot...
|
||||
src = pev->origin + m_rightRef * 16.0f + Vector (0.0f, 0.0f, -36.0f + 45.0f);
|
||||
src = pev->origin + right * 16.0f + Vector (0.0f, 0.0f, -36.0f + 45.0f);
|
||||
dest = src + normal * 32.0f;
|
||||
|
||||
// trace a line forward at maximum jump height...
|
||||
|
|
@ -2951,7 +2968,7 @@ bool Bot::canJumpUp (const Vector &normal) {
|
|||
|
||||
// if trace hit something, return false
|
||||
if (tr.flFraction < 1.0f) {
|
||||
return doneCanJumpUp (normal, m_rightRef);
|
||||
return doneCanJumpUp (normal, right);
|
||||
}
|
||||
|
||||
// now trace from jump height upward to check for obstructions...
|
||||
|
|
@ -2966,7 +2983,7 @@ bool Bot::canJumpUp (const Vector &normal) {
|
|||
}
|
||||
|
||||
// now check same height on the other side of the bot...
|
||||
src = pev->origin + (-m_rightRef * 16.0f) + Vector (0.0f, 0.0f, -36.0f + 45.0f);
|
||||
src = pev->origin + (-right * 16.0f) + Vector (0.0f, 0.0f, -36.0f + 45.0f);
|
||||
dest = src + normal * 32.0f;
|
||||
|
||||
// trace a line forward at maximum jump height...
|
||||
|
|
@ -2974,7 +2991,7 @@ bool Bot::canJumpUp (const Vector &normal) {
|
|||
|
||||
// if trace hit something, return false
|
||||
if (tr.flFraction < 1.0f) {
|
||||
return doneCanJumpUp (normal, m_rightRef);
|
||||
return doneCanJumpUp (normal, right);
|
||||
}
|
||||
|
||||
// now trace from jump height upward to check for obstructions...
|
||||
|
|
@ -3082,10 +3099,10 @@ bool Bot::canDuckUnder (const Vector &normal) {
|
|||
if (tr.flFraction < 1.0f) {
|
||||
return false;
|
||||
}
|
||||
updateRightRef ();
|
||||
auto right = Vector { 0.0f, pev->angles.y, 0.0f }.right ();
|
||||
|
||||
// now check same height to one side of the bot...
|
||||
src = baseHeight + m_rightRef * 16.0f;
|
||||
src = baseHeight + right * 16.0f;
|
||||
dest = src + normal * 32.0f;
|
||||
|
||||
// trace a line forward at duck height...
|
||||
|
|
@ -3097,7 +3114,7 @@ bool Bot::canDuckUnder (const Vector &normal) {
|
|||
}
|
||||
|
||||
// now check same height on the other side of the bot...
|
||||
src = baseHeight + (-m_rightRef * 16.0f);
|
||||
src = baseHeight + (-right * 16.0f);
|
||||
dest = src + normal * 32.0f;
|
||||
|
||||
// trace a line forward at duck height...
|
||||
|
|
@ -3114,11 +3131,11 @@ bool Bot::isBlockedLeft () {
|
|||
if (m_moveSpeed < 0.0f) {
|
||||
direction = -48.0f;
|
||||
}
|
||||
Vector right {}, forward {};
|
||||
pev->angles.angleVectors (&forward, &right, nullptr);
|
||||
Vector left {}, forward {};
|
||||
pev->angles.angleVectors (&forward, &left, nullptr);
|
||||
|
||||
// do a trace to the left...
|
||||
game.testLine (pev->origin, pev->origin - forward * direction - right * 48.0f, TraceIgnore::Monsters, ent (), &tr);
|
||||
game.testLine (pev->origin, pev->origin + forward * direction - left * -48.0f, TraceIgnore::Monsters, ent (), &tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (game.mapIs (MapFlags::HasDoors) && tr.flFraction < 1.0f && !game.isDoorEntity (tr.pHit)) {
|
||||
|
|
@ -3131,8 +3148,8 @@ bool Bot::isBlockedRight () {
|
|||
TraceResult tr {};
|
||||
float direction = 48.0f;
|
||||
|
||||
if (m_moveSpeed > 0.0f) {
|
||||
direction = 48.0f;
|
||||
if (m_moveSpeed < 0.0f) {
|
||||
direction = -48.0f;
|
||||
}
|
||||
Vector right {}, forward {};
|
||||
pev->angles.angleVectors (&forward, &right, nullptr);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue