Merge pull request #520 from commandcobra7/master

nav: rusher bots does not care any danger (idea from pbmm) nav: some changes in collision motion
This commit is contained in:
jeefo 2024-02-10 21:21:13 +03:00 committed by GitHub
commit f05091d6cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 109 additions and 162 deletions

View file

@ -1566,8 +1566,10 @@ void Bot::updateEmotions () {
}
void Bot::overrideConditions () {
const auto tid = getCurrentTaskId ();
// check if we need to escape from bomb
if (game.mapIs (MapFlags::Demolition) && bots.isBombPlanted () && m_isAlive && getCurrentTaskId () != Task::EscapeFromBomb && getCurrentTaskId () != Task::Camp && isOutOfBombTimer ()) {
if (game.mapIs (MapFlags::Demolition) && bots.isBombPlanted () && m_isAlive && tid != Task::EscapeFromBomb && tid != Task::Camp && isOutOfBombTimer ()) {
completeTask (); // complete current task
// then start escape from bomb immediate
@ -1583,11 +1585,11 @@ void Bot::overrideConditions () {
const int nearestToEnemyPoint = graph.getNearest (m_enemy->v.origin);
if (nearestToEnemyPoint != kInvalidNodeIndex && nearestToEnemyPoint != m_currentNodeIndex && cr::abs (graph[nearestToEnemyPoint].origin.z - m_enemy->v.origin.z) < 16.0f) {
if (getCurrentTaskId () != Task::MoveToPosition && !cr::fequal (getTask ()->desire, TaskPri::Hide)) {
if (tid != Task::MoveToPosition && !cr::fequal (getTask ()->desire, TaskPri::Hide)) {
startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, game.time () + length / (m_moveSpeed * 2.0f), true);
}
else {
if (getCurrentTaskId () == Task::MoveToPosition && getTask ()->data != nearestToEnemyPoint) {
if (tid == Task::MoveToPosition && getTask ()->data != nearestToEnemyPoint) {
clearTask (Task::MoveToPosition);
startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, game.time () + length / (m_moveSpeed * 2.0f), true);
}
@ -1595,14 +1597,14 @@ void Bot::overrideConditions () {
}
}
else {
if (length <= 250.0f && (m_states & Sense::SeeingEnemy) && getCurrentTaskId () == Task::MoveToPosition) {
if (length <= 250.0f && (m_states & Sense::SeeingEnemy) && tid == Task::MoveToPosition) {
clearTask (Task::MoveToPosition); // remove any move tasks
}
}
}
// special handling for sniping
if (usesSniper () && (m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy)) && m_sniperStopTime > game.time () && getCurrentTaskId () != Task::SeekCover) {
if (usesSniper () && (m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy)) && m_sniperStopTime > game.time () && tid != Task::SeekCover) {
m_moveSpeed = 0.0f;
m_strafeSpeed = 0.0f;
@ -1610,7 +1612,7 @@ void Bot::overrideConditions () {
}
// special handling for reloading
if (!bots.isRoundOver () && getCurrentTaskId () == Task::Normal && m_reloadState != Reload::None && m_isReloading && !isDucking () && !isInNarrowPlace ()) {
if (!bots.isRoundOver () && tid == Task::Normal && m_reloadState != Reload::None && m_isReloading && !isDucking () && !isInNarrowPlace ()) {
if (m_reloadState != Reload::None || m_isReloading) {
const auto maxClip = conf.findWeaponById (m_currentWeapon).maxClip;
const auto curClip = getAmmoInClip ();
@ -1689,7 +1691,7 @@ void Bot::refreshEnemyPredict () {
if (game.isNullEntity (m_enemy) && !game.isNullEntity (m_lastEnemy) && !m_lastEnemyOrigin.empty ()) {
const auto distanceToLastEnemySq = m_lastEnemyOrigin.distanceSq (pev->origin);
if (distanceToLastEnemySq > cr::sqrf (128.0f) && (distanceToLastEnemySq < cr::sqrf (2048.0f) || usesSniper ())) {
if (distanceToLastEnemySq > cr::sqrf (256.0f) && (distanceToLastEnemySq < cr::sqrf (2048.0f) || usesSniper ())) {
m_aimFlags |= AimFlags::PredictPath;
}
const bool denyLastEnemy = pev->velocity.lengthSq2d () > 0.0f && distanceToLastEnemySq < cr::sqrf (256.0f) && m_shootTime + 2.5f > game.time ();
@ -1921,8 +1923,8 @@ void Bot::filterTasks () {
else if (m_isVIP || m_isReloading || (sniping && usesSniper ())) {
ratio *= 3.0f; // triple the seek cover desire if bot is VIP or reloading
}
else if (m_lastEnemyOrigin.distance2d (pev->origin) < 200.0f) {
ratio *= 5.0f;
else if (m_lastEnemyOrigin.distanceSq2d (pev->origin) < cr::sqrf (200.0f)) {
ratio *= 3.0f;
}
else if (m_isCreature) {
ratio = 0.0f;
@ -3208,12 +3210,12 @@ void Bot::showDebugOverlay () {
StringRef debugData = strings.format (
"\n\n\n\n\n\n%s (H:%.1f/A:%.1f)- Task: %d=%s Desire:%.02f\n"
"Item: %s Clip: %d Ammo: %d%s Money: %d AimFlags: %s\n"
"SP=%.02f SSP=%.02f I=%d PG=%d G=%d T: %.02f MT: %d\n"
"SP=%.02f SSP=%.02f I=%d CG=%d PG=%d G=%d T: %.02f MT: %d\n"
"Enemy=%s Pickup=%s Type=%s Terrain=%s Stuck=%s\n",
pev->netname.str (), m_healthValue, pev->armorvalue,
tid, tasks[tid], getTask ()->desire, weapon, getAmmoInClip (),
getAmmo (), m_isReloading ? " (R)" : "", m_moneyAmount, aimFlags.trim (),
m_moveSpeed, m_strafeSpeed, index, m_prevGoalIndex, goal, m_navTimeset - game.time (),
m_moveSpeed, m_strafeSpeed, index, m_chosenGoalIndex, m_prevGoalIndex, goal, m_navTimeset - game.time (),
pev->movetype, enemy, pickup, personalities[m_personality], boolValue (m_checkTerrain),
boolValue (m_isStuck));

View file

@ -504,7 +504,7 @@ Vector Bot::getBodyOffsetError (float distance) {
return m_aimLastError;
}
Vector Bot::getEnemyBodyOffset () {
Vector Bot::getEnemyBodyOffset () {
// the purpose of this function, is to make bot aiming not so ideal. it's mutate m_enemyOrigin enemy vector
// returned from visibility check function.
@ -586,7 +586,7 @@ Vector Bot::getCustomHeight (float distance) {
Long, Middle, Short
};
constexpr float offsetRanges[9][3] = {
constexpr float kOffsetRanges[9][3] = {
{ 0.0f, 0.0f, 0.0f }, // none
{ 0.0f, 0.0f, 0.0f }, // melee
{ 0.5f, -0.1f, -1.5f }, // pistol
@ -613,7 +613,7 @@ Vector Bot::getCustomHeight (float distance) {
else if (distance > kSprayDistance && distance <= kDoubleSprayDistance) {
distanceIndex = DistanceIndex::Middle;
}
return { 0.0f, 0.0f, offsetRanges[m_weaponType][distanceIndex] };
return { 0.0f, 0.0f, kOffsetRanges[m_weaponType][distanceIndex] };
}
bool Bot::isFriendInLineOfFire (float distance) {
@ -711,7 +711,9 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
bool Bot::isPenetrableObstacle2 (const Vector &dest) {
// this function returns if enemy can be shoot through some obstacle
if (m_isUsingGrenade || m_difficulty < Difficulty::Normal || !conf.findWeaponById (m_currentWeapon).penetratePower) {
auto power = conf.findWeaponById (m_currentWeapon).penetratePower;
if (m_isUsingGrenade || m_difficulty < Difficulty::Normal || !power) {
return false;
}
@ -1357,6 +1359,9 @@ void Bot::attackMovement () {
pev->button |= IN_JUMP;
}
}
else {
m_duckTime = game.time () + m_frameInterval * 2.0f;
}
}
if (m_isReloading) {

View file

@ -320,6 +320,15 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offensive) {
if (goalChoices[0] == kInvalidNodeIndex) {
return m_chosenGoalIndex = graph.random ();
}
// rusher bots does not care any danger (idea from pbmm)
if (m_personality == Personality::Rusher) {
const auto randomGoal = goalChoices[rg.get (0, 3)];
if (graph.exists (randomGoal)) {
return m_chosenGoalIndex = randomGoal;
}
}
bool sorting = false;
do {
@ -609,7 +618,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
dirLeft = true;
}
const auto &testDir = m_moveSpeed > 0.0f ? forward : -forward;
constexpr float kBlockDistance = 32.0f;
constexpr float kBlockDistance = 42.0f;
// now check which side is blocked
src = pev->origin + right * kBlockDistance;
@ -787,44 +796,12 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
void Bot::moveToGoal () {
findValidNode ();
bool prevLadder = false;
if (graph.exists (m_previousNodes[0])) {
if (graph[m_previousNodes[0]].flags & NodeFlag::Ladder) {
prevLadder = true;
}
}
// press duck button if we need to
if ((m_pathFlags & NodeFlag::Crouch) && !(m_pathFlags & (NodeFlag::Camp | NodeFlag::Goal))) {
pev->button |= IN_DUCK;
}
m_lastUsedNodesTime = game.time ();
// press jump button if we need to leave the ladder
if (!(m_pathFlags & NodeFlag::Ladder) && prevLadder && isOnFloor () && isOnLadder () && m_moveSpeed > 50.0f && pev->velocity.length () < 50.0f) {
pev->button |= IN_JUMP;
m_jumpTime = game.time () + 1.0f;
}
if (m_pathFlags & NodeFlag::Ladder) {
if (m_pathOrigin.z < pev->origin.z + 16.0f && !isOnLadder () && isOnFloor () && !isDucking ()) {
if (!prevLadder) {
m_moveSpeed = pev->origin.distance (m_pathOrigin);
}
else {
m_moveSpeed = 150.0f;
}
if (m_moveSpeed < 150.0f) {
m_moveSpeed = 150.0f;
}
else if (m_moveSpeed > pev->maxspeed) {
m_moveSpeed = pev->maxspeed;
}
}
}
m_lastUsedNodesTime = game.time ();
// special movement for swimming here
if (isInWater ()) {
// check if we need to go forward or back press the correct buttons
@ -955,7 +932,7 @@ bool Bot::updateNavigation () {
}
}
if ((m_pathFlags & NodeFlag::Ladder) || isOnLadder ()) {
if (m_pathFlags & NodeFlag::Ladder) {
if (m_pathOrigin.z >= (pev->origin.z + 16.0f)) {
constexpr auto kLadderOffset = Vector (0.0f, 0.0f, 16.0f);
m_pathOrigin = m_path->origin + kLadderOffset;
@ -973,7 +950,7 @@ bool Bot::updateNavigation () {
// special detection if someone is using the ladder (to prevent to have bots-towers on ladders)
for (const auto &client : util.getClients ()) {
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || (client.ent->v.movetype != MOVETYPE_FLY) || client.ent == ent ()) {
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || (client.ent->v.movetype != MOVETYPE_FLY) || client.team != m_team || client.ent == ent ()) {
continue;
}
TraceResult tr {};
@ -981,60 +958,23 @@ bool Bot::updateNavigation () {
int previousNode = 0;
// more than likely someone is already using our ladder...
if (client.ent->v.origin.distanceSq (m_path->origin) < cr::sqrf (40.0f)) {
if ((client.team != m_team || game.is (GameFlags::FreeForAll)) && !cv_ignore_enemies.bool_ ()) {
game.testLine (getEyesPos (), client.ent->v.origin, TraceIgnore::Monsters, ent (), &tr);
// bot found an enemy on his ladder - he should see him...
if (tr.pHit == client.ent) {
m_enemy = client.ent;
m_lastEnemy = client.ent;
m_lastEnemyOrigin = client.ent->v.origin;
m_enemyParts = Visibility::None;
m_enemyParts |= (Visibility::Head | Visibility::Body);
m_states |= Sense::SeeingEnemy;
m_seeEnemyTime = game.time ();
break;
}
}
else {
if (client.ent->v.origin.distanceSq (m_path->origin) < cr::sqrf (48.0f)) {
game.testHull (getEyesPos (), m_pathOrigin, TraceIgnore::Monsters, isDucking () ? head_hull : human_hull, ent (), &tr);
// someone is above or below us and is using the ladder already
if (tr.pHit == client.ent && cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f && (client.ent->v.movetype == MOVETYPE_FLY)) {
if (graph.exists (m_previousNodes[0])) {
if (!(graph[m_previousNodes[0]].flags & NodeFlag::Ladder)) {
const auto numPreviousNode = rg.get (0, 2);
for (int i = 0; i < numPreviousNode; ++i) {
if (graph.exists (m_previousNodes[i]) && (graph[m_previousNodes[i]].flags & NodeFlag::Ladder)) {
foundGround = true;
previousNode = m_previousNodes[0];
}
else if (graph.exists (m_previousNodes[1])) {
if (!(graph[m_previousNodes[1]].flags & NodeFlag::Ladder)) {
foundGround = true;
previousNode = m_previousNodes[1];
}
else if (graph.exists (m_previousNodes[2])) {
if (!(graph[m_previousNodes[2]].flags & NodeFlag::Ladder)) {
foundGround = true;
previousNode = m_previousNodes[2];
}
else if (graph.exists (m_previousNodes[3])) {
if (!(graph[m_previousNodes[3]].flags & NodeFlag::Ladder)) {
foundGround = true;
previousNode = m_previousNodes[3];
}
}
}
previousNode = m_previousNodes[i];
break;
}
}
if (foundGround) {
if (getCurrentTaskId () != Task::MoveToPosition || !cr::fequal (getTask ()->desire, TaskPri::PlantBomb)) {
changeNodeIndex (m_previousNodes[0]);
startTask (Task::MoveToPosition, TaskPri::PlantBomb, previousNode, 0.0f, true);
}
break;
}
findPath (m_previousNodes[0], previousNode, m_pathType);
}
}
}
@ -2528,7 +2468,7 @@ bool Bot::canStrafeLeft (TraceResult *tr) {
pev->v_angle.angleVectors (&forward, &right, nullptr);
Vector src = pev->origin;
Vector dest = src - right * -40.0f;
Vector dest = src - right * 40.0f;
// trace from the bot's waist straight left...
game.testLine (src, dest, TraceIgnore::Monsters, ent (), tr);
@ -2888,66 +2828,6 @@ bool Bot::isDeadlyMove (const Vector &to) {
return false;
}
void Bot::changePitch (float speed) {
// this function turns a bot towards its ideal_pitch
const float idealPitch = cr::wrapAngle (pev->idealpitch);
const float curent = cr::wrapAngle (pev->v_angle.x);
// turn from the current v_angle pitch to the idealpitch by selecting
// the quickest way to turn to face that direction
// find the difference in the curent and ideal angle
float normalizePitch = cr::wrapAngle (idealPitch - curent);
if (normalizePitch > 0.0f) {
if (normalizePitch > speed) {
normalizePitch = speed;
}
}
else {
if (normalizePitch < -speed) {
normalizePitch = -speed;
}
}
pev->v_angle.x = cr::wrapAngle (curent + normalizePitch);
if (pev->v_angle.x > 89.9f) {
pev->v_angle.x = 89.9f;
}
if (pev->v_angle.x < -89.9f) {
pev->v_angle.x = -89.9f;
}
pev->angles.x = -pev->v_angle.x / 3;
}
void Bot::changeYaw (float speed) {
// this function turns a bot towards its ideal_yaw
const float idealPitch = cr::wrapAngle (pev->ideal_yaw);
const float curent = cr::wrapAngle (pev->v_angle.y);
// turn from the current v_angle yaw to the ideal_yaw by selecting
// the quickest way to turn to face that direction
// find the difference in the curent and ideal angle
float normalizePitch = cr::wrapAngle (idealPitch - curent);
if (normalizePitch > 0.0f) {
if (normalizePitch > speed) {
normalizePitch = speed;
}
}
else {
if (normalizePitch < -speed) {
normalizePitch = -speed;
}
}
pev->v_angle.y = cr::wrapAngle (curent + normalizePitch);
pev->angles.y = pev->v_angle.y;
}
int Bot::getRandomCampDir () {
// find a good node to look at when camping

View file

@ -277,6 +277,66 @@ void Bot::checkDarkness () {
m_checkDarkTime = game.time () + rg.get (2.0f, 4.0f);
}
void Bot::changePitch (float speed) {
// this function turns a bot towards its ideal_pitch
const float idealPitch = cr::wrapAngle (pev->idealpitch);
const float curent = cr::wrapAngle (pev->v_angle.x);
// turn from the current v_angle pitch to the idealpitch by selecting
// the quickest way to turn to face that direction
// find the difference in the curent and ideal angle
float normalizePitch = cr::wrapAngle (idealPitch - curent);
if (normalizePitch > 0.0f) {
if (normalizePitch > speed) {
normalizePitch = speed;
}
}
else {
if (normalizePitch < -speed) {
normalizePitch = -speed;
}
}
pev->v_angle.x = cr::wrapAngle (curent + normalizePitch);
if (pev->v_angle.x > 89.9f) {
pev->v_angle.x = 89.9f;
}
if (pev->v_angle.x < -89.9f) {
pev->v_angle.x = -89.9f;
}
pev->angles.x = -pev->v_angle.x / 3;
}
void Bot::changeYaw (float speed) {
// this function turns a bot towards its ideal_yaw
const float idealPitch = cr::wrapAngle (pev->ideal_yaw);
const float curent = cr::wrapAngle (pev->v_angle.y);
// turn from the current v_angle yaw to the ideal_yaw by selecting
// the quickest way to turn to face that direction
// find the difference in the curent and ideal angle
float normalizePitch = cr::wrapAngle (idealPitch - curent);
if (normalizePitch > 0.0f) {
if (normalizePitch > speed) {
normalizePitch = speed;
}
}
else {
if (normalizePitch < -speed) {
normalizePitch = -speed;
}
}
pev->v_angle.y = cr::wrapAngle (curent + normalizePitch);
pev->angles.y = pev->v_angle.y;
}
void Bot::updateBodyAngles () {
// set the body angles to point the gun correctly
pev->angles.x = -pev->v_angle.x * (1.0f / 3.0f);