fix: texts have been corrected. (#477)

task: normal: skip sniper node if no sniper weapon.
task: normal: don't walk if there are no enemies left and they are using knives.
task: attack: get proper function if bots lose close node after attack task.
nav: unnecessary codes cleared.
combat: attack movements reviewed.
bot: enemy hearing is now better. (thanks for the @spodlesniy idea)
desire: increased desire to seek cover by distance. (made for zombie plague mod)
---------
Co-authored-by: jeefo <jeefo@rwsh.ru>
This commit is contained in:
commandcobra7 2023-09-10 11:12:15 +03:00 committed by GitHub
commit ae9beff151
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 92 additions and 84 deletions

View file

@ -38,7 +38,6 @@ ConVar cv_pickup_custom_items ("pickup_custom_items", "0", "Allows or disallows
ConVar cv_pickup_ammo_and_kits ("pickup_ammo_and_kits", "0", "Allows bots pickup mod items like ammo, health kits and suits.");
ConVar cv_pickup_best ("pickup_best", "1", "Allows or disallows bots to pickup best weapons.");
ConVar cv_ignore_objectives ("ignore_objectives", "0", "Allows or disallows bots to do map objectives, i.e. plant/defuse bombs, and saves hostages.");
ConVar cv_random_knife_attacks ("random_knife_attacks", "1", "Allows or disallows the ability for random knife attacks when bot is rushing and no enemy is nearby.");
// game console variables
ConVar mp_c4timer ("mp_c4timer", nullptr, Var::GameRef);
@ -1684,7 +1683,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 (384.0f) && (distanceToLastEnemySq < cr::sqrf (2048.0f) || usesSniper ())) {
if (distanceToLastEnemySq > cr::sqrf (128.0f) && (distanceToLastEnemySq < cr::sqrf (2048.0f) || usesSniper ())) {
m_aimFlags |= AimFlags::PredictPath;
}
const bool denyLastEnemy = pev->velocity.lengthSq2d () > 0.0f && distanceToLastEnemySq < cr::sqrf (256.0f);
@ -1902,6 +1901,9 @@ 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_isCreature) {
ratio = 0.0f;
}
@ -3354,12 +3356,12 @@ void Bot::updatePracticeValue (int damage) {
const auto health = static_cast <int> (m_healthValue);
// max goal value
constexpr int maxGoalValue = PracticeLimit::Goal;
constexpr int kMaxGoalValue = PracticeLimit::Goal;
// only rate goal node if bot died because of the damage
// FIXME: could be done a lot better, however this cares most about damage done by sniping or really deadly weapons
if (health - damage <= 0) {
practice.setValue (m_team, m_chosenGoalIndex, m_prevGoalIndex, cr::clamp (practice.getValue (m_team, m_chosenGoalIndex, m_prevGoalIndex) - health / 20, -maxGoalValue, maxGoalValue));
practice.setValue (m_team, m_chosenGoalIndex, m_prevGoalIndex, cr::clamp (practice.getValue (m_team, m_chosenGoalIndex, m_prevGoalIndex) - health / 20, -kMaxGoalValue, kMaxGoalValue));
}
}
@ -3376,7 +3378,7 @@ void Bot::updatePracticeDamage (edict_t *attacker, int damage) {
if (attackerTeam == victimTeam) {
return;
}
constexpr int maxDamageValue = PracticeLimit::Damage;
constexpr int kMaxDamageValue = PracticeLimit::Damage;
// if these are bots also remember damage to rank destination of the bot
m_goalValue -= static_cast <float> (damage);
@ -3398,13 +3400,13 @@ void Bot::updatePracticeDamage (edict_t *attacker, int damage) {
if (m_healthValue > 20.0f) {
if (victimTeam == Team::Terrorist || victimTeam == Team::CT) {
practice.setDamage (victimIndex, victimIndex, victimIndex, cr::clamp (practice.getDamage (victimTeam, victimIndex, victimIndex), 0, maxDamageValue));
practice.setDamage (victimIndex, victimIndex, victimIndex, cr::clamp (practice.getDamage (victimTeam, victimIndex, victimIndex), 0, kMaxDamageValue));
}
}
const auto updateDamage = util.isFakeClient (attacker) ? 10 : 7;
// store away the damage done
const auto damageValue = cr::clamp (practice.getDamage (m_team, victimIndex, attackerIndex) + damage / updateDamage, 0, maxDamageValue);
const auto damageValue = cr::clamp (practice.getDamage (m_team, victimIndex, attackerIndex) + damage / updateDamage, 0, kMaxDamageValue);
if (damageValue > practice.getHighestDamageForTeam (m_team)) {
practice.setHighestDamageForTeam (m_team, damageValue);
@ -3650,17 +3652,18 @@ bool Bot::isOutOfBombTimer () {
}
void Bot::updateHearing () {
int hearEnemyIndex = kInvalidNodeIndex;
if (game.is (GameFlags::FreeForAll)) {
return;
}
edict_t *hearedEnemy = nullptr;
float nearestDistanceSq = kInfiniteDistance;
// setup potential visibility set from engine
auto set = game.getVisibilitySet (this, false);
// loop through all enemy clients to check for hearable stuff
for (int i = 0; i < game.maxClients (); ++i) {
const auto &client = util.getClient (i);
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.ent == ent () || client.team == m_team || client.noise.last < game.time ()) {
for (const auto &client : util.getClients ()) {
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.ent == ent () || client.team == m_team || !client.ent || client.noise.last < game.time ()) {
continue;
}
@ -3674,18 +3677,13 @@ void Bot::updateHearing () {
}
if (distanceSq < nearestDistanceSq) {
hearEnemyIndex = i;
hearedEnemy = client.ent;
nearestDistanceSq = distanceSq;
}
}
edict_t *player = nullptr;
if (hearEnemyIndex >= 0 && util.getClient (hearEnemyIndex).team != m_team && !game.is (GameFlags::FreeForAll)) {
player = util.getClient (hearEnemyIndex).ent;
}
// did the bot hear someone ?
if (player != nullptr && util.isPlayer (player)) {
if (hearedEnemy != nullptr && util.isPlayer (hearedEnemy)) {
// change to best weapon if heard something
if (m_shootTime < game.time () - 5.0f && isOnFloor () && m_currentWeapon != Weapon::C4 && m_currentWeapon != Weapon::Explosive && m_currentWeapon != Weapon::Smoke && m_currentWeapon != Weapon::Flashbang && !isKnifeMode ()) {
selectBestWeapon ();
@ -3700,26 +3698,26 @@ void Bot::updateHearing () {
// didn't bot already have an enemy ? take this one...
if (m_lastEnemyOrigin.empty () || m_lastEnemy == nullptr) {
m_lastEnemy = player;
m_lastEnemyOrigin = player->v.origin;
m_lastEnemy = hearedEnemy;
m_lastEnemyOrigin = hearedEnemy->v.origin;
}
// bot had an enemy, check if it's the heard one
else {
if (player == m_lastEnemy) {
if (hearedEnemy == m_lastEnemy) {
// bot sees enemy ? then bail out !
if (m_states & Sense::SeeingEnemy) {
return;
}
m_lastEnemyOrigin = player->v.origin;
m_lastEnemyOrigin = hearedEnemy->v.origin;
}
else {
// if bot had an enemy but the heard one is nearer, take it instead
const float distanceSq = m_lastEnemyOrigin.distanceSq (pev->origin);
if (distanceSq > player->v.origin.distanceSq (pev->origin) && m_seeEnemyTime + 2.0f < game.time ()) {
m_lastEnemy = player;
m_lastEnemyOrigin = player->v.origin;
if (distanceSq > hearedEnemy->v.origin.distanceSq (pev->origin) && m_seeEnemyTime + 2.0f < game.time ()) {
m_lastEnemy = hearedEnemy;
m_lastEnemyOrigin = hearedEnemy->v.origin;
}
else {
return;
@ -3728,9 +3726,9 @@ void Bot::updateHearing () {
}
// check if heard enemy can be seen
if (checkBodyParts (player)) {
m_enemy = player;
m_lastEnemy = player;
if (checkBodyParts (hearedEnemy)) {
m_enemy = hearedEnemy;
m_lastEnemy = hearedEnemy;
m_lastEnemyOrigin = m_enemyOrigin;
m_states |= Sense::SeeingEnemy;
@ -3739,11 +3737,11 @@ void Bot::updateHearing () {
// check if heard enemy can be shoot through some obstacle
else {
if (cv_shoots_thru_walls.bool_ () && m_difficulty >= Difficulty::Normal && m_lastEnemy == player && rg.chance (conf.getDifficultyTweaks (m_difficulty)->hearThruPct) && m_seeEnemyTime + 3.0f > game.time () && isPenetrableObstacle (player->v.origin)) {
m_enemy = player;
m_lastEnemy = player;
m_enemyOrigin = player->v.origin;
m_lastEnemyOrigin = player->v.origin;
if (cv_shoots_thru_walls.bool_ () && m_difficulty >= Difficulty::Normal && m_lastEnemy == hearedEnemy && rg.chance (conf.getDifficultyTweaks (m_difficulty)->hearThruPct) && m_seeEnemyTime + 3.0f > game.time () && isPenetrableObstacle (hearedEnemy->v.origin)) {
m_enemy = hearedEnemy;
m_lastEnemy = hearedEnemy;
m_enemyOrigin = hearedEnemy->v.origin;
m_lastEnemyOrigin = hearedEnemy->v.origin;
m_states |= (Sense::SeeingEnemy | Sense::SuspectEnemy);
m_seeEnemyTime = game.time ();
@ -3840,7 +3838,7 @@ bool Bot::isBombDefusing (const Vector &bombOrigin) {
}
float Bot::getShiftSpeed () {
if (getCurrentTaskId () == Task::SeekCover || (m_aimFlags & AimFlags::Enemy) || isDucking () || (pev->button & IN_DUCK) || (m_oldButtons & IN_DUCK) || (m_currentTravelFlags & PathFlag::Jump) || (m_pathFlags & NodeFlag::Ladder) || isOnLadder () || isInWater () || m_isStuck) {
if (getCurrentTaskId () == Task::SeekCover || (m_aimFlags & AimFlags::Enemy) || isDucking () || (pev->button & IN_DUCK) || (m_oldButtons & IN_DUCK) || (m_currentTravelFlags & PathFlag::Jump) || (m_pathFlags & NodeFlag::Ladder) || isOnLadder () || isInWater () || isKnifeMode () || m_isStuck || m_numEnemiesLeft <= 0) {
return pev->maxspeed;
}
return pev->maxspeed * 0.4f;