fix: hostage code (#269)

fix: hostage code
add: yb_random_knife_attacks cvar
This commit is contained in:
godhand897 2022-01-03 07:18:36 +01:00 committed by GitHub
commit f55ac6c5c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 8 deletions

View file

@ -1177,6 +1177,7 @@ extern ConVar cv_shoots_thru_walls;
extern ConVar cv_debug; extern ConVar cv_debug;
extern ConVar cv_debug_goal; extern ConVar cv_debug_goal;
extern ConVar cv_save_bots_names; extern ConVar cv_save_bots_names;
extern ConVar cv_random_knife_attacks;
extern ConVar mp_freezetime; extern ConVar mp_freezetime;
extern ConVar mp_roundtime; extern ConVar mp_roundtime;

View file

@ -35,6 +35,7 @@ ConVar cv_restricted_weapons ("yb_restricted_weapons", "", "Specifies semicolon
ConVar cv_attack_monsters ("yb_attack_monsters", "0", "Allows or disallows bots to attack monsters."); ConVar cv_attack_monsters ("yb_attack_monsters", "0", "Allows or disallows bots to attack monsters.");
ConVar cv_pickup_custom_items ("yb_pickup_custom_items", "0", "Allows or disallows bots to pickup custom items."); ConVar cv_pickup_custom_items ("yb_pickup_custom_items", "0", "Allows or disallows bots to pickup custom items.");
ConVar cv_ignore_objectives ("yb_ignore_objectives", "0", "Allows or disallows bots to do map objectives, i.e. plant/defuse bombs, and saves hostages."); ConVar cv_ignore_objectives ("yb_ignore_objectives", "0", "Allows or disallows bots to do map objectives, i.e. plant/defuse bombs, and saves hostages.");
ConVar cv_random_knife_attacks ("yb_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 // game console variables
ConVar mp_c4timer ("mp_c4timer", nullptr, Var::GameRef); ConVar mp_c4timer ("mp_c4timer", nullptr, Var::GameRef);
@ -95,7 +96,7 @@ bool Bot::seesItem (const Vector &destination, const char *classname) {
game.testLine (getEyesPos (), destination, TraceIgnore::None, ent (), &tr); game.testLine (getEyesPos (), destination, TraceIgnore::None, ent (), &tr);
// check if line of sight to object is not blocked (i.e. visible) // check if line of sight to object is not blocked (i.e. visible)
if (tr.flFraction >= 0.95f && tr.pHit && tr.pHit != game.getStartEntity ()) { if (tr.flFraction < 1.0f && tr.pHit) {
return strcmp (tr.pHit->v.classname.chars (), classname) == 0; return strcmp (tr.pHit->v.classname.chars (), classname) == 0;
} }
return true; return true;
@ -557,7 +558,7 @@ void Bot::updatePickups () {
// check if line of sight to object is not blocked (i.e. visible) // check if line of sight to object is not blocked (i.e. visible)
if (seesItem (origin, classname)) { if (seesItem (origin, classname)) {
if (strncmp ("hostage_entity", classname, 14) == 0) { if (strncmp ("hostage_entity", classname, 14) == 0 || strncmp ("monster_scientist", classname, 17) == 0) {
allowPickup = true; allowPickup = true;
pickupType = Pickup::Hostage; pickupType = Pickup::Hostage;
} }
@ -735,6 +736,17 @@ void Bot::updatePickups () {
} }
} }
} }
// don't steal hostage from human teammate (hack)
if (allowPickup) {
for (auto &client : util.getClients ()) {
if ((client.flags & ClientFlags::Used) && !(client.ent->v.flags & FL_FAKECLIENT) && (client.flags & ClientFlags::Alive) &&
client.team == m_team && client.ent->v.origin.distanceSq (ent->v.origin) <= cr::square (240.0f)) {
allowPickup = false;
break;
}
}
}
} }
} }
else if (pickupType == Pickup::PlantedC4) { else if (pickupType == Pickup::PlantedC4) {
@ -3057,7 +3069,7 @@ 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 (usesKnife () && (game.isNullEntity (m_lastEnemy) || !util.isAlive (m_lastEnemy)) && game.isNullEntity (m_enemy) && m_knifeAttackTime < game.time () && !hasShield () && numFriendsNear (pev->origin, 96.0f) == 0) { if (cv_random_knife_attacks.bool_ () && usesKnife () && (game.isNullEntity (m_lastEnemy) || !util.isAlive (m_lastEnemy)) && game.isNullEntity (m_enemy) && m_knifeAttackTime < game.time () && !hasShield () && numFriendsNear (pev->origin, 96.0f) == 0) {
if (rg.chance (40)) { if (rg.chance (40)) {
pev->button |= IN_ATTACK; pev->button |= IN_ATTACK;
} }
@ -4588,6 +4600,61 @@ void Bot::pickupItem_ () {
} }
m_hostages.push (m_pickupItem); m_hostages.push (m_pickupItem);
m_pickupItem = nullptr; m_pickupItem = nullptr;
completeTask ();
float minDistance = kInfiniteDistance;
int nearestHostageNodeIndex = kInvalidNodeIndex;
// find the nearest 'unused' hostage within the area
game.searchEntities (pev->origin, 768.0f, [&] (edict_t *ent) {
auto classname = ent->v.classname.chars ();
if (strncmp ("hostage_entity", classname, 14) != 0 && strncmp ("monster_scientist", classname, 17) != 0) {
return EntitySearchResult::Continue;
}
// check if hostage is dead
if (game.isNullEntity (ent) || ent->v.health <= 0) {
return EntitySearchResult::Continue;
}
// check if hostage is with a bot
for (const auto &other : bots) {
if (other->m_notKilled) {
for (const auto &hostage : other->m_hostages) {
if (hostage == ent) {
return EntitySearchResult::Continue;
}
}
}
}
// check if hostage is with a human teammate (hack)
for (auto &client : util.getClients ()) {
if ((client.flags & ClientFlags::Used) && !(client.ent->v.flags & FL_FAKECLIENT) && (client.flags & ClientFlags::Alive) &&
client.team == m_team && client.ent->v.origin.distanceSq (ent->v.origin) <= cr::square (240.0f)) {
return EntitySearchResult::Continue;
}
}
int hostageNodeIndex = graph.getNearest (ent->v.origin);
if (graph.exists (hostageNodeIndex)) {
float distance = graph[hostageNodeIndex].origin.distanceSq (pev->origin);
if (distance < minDistance) {
minDistance = distance;
nearestHostageNodeIndex = hostageNodeIndex;
}
}
return EntitySearchResult::Continue;
});
if (nearestHostageNodeIndex != kInvalidNodeIndex) {
clearTask (Task::MoveToPosition); // remove any move tasks
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, nearestHostageNodeIndex, 0.0f, true);
}
} }
ignoreCollision (); // also don't consider being stuck ignoreCollision (); // also don't consider being stuck
} }
@ -5074,7 +5141,7 @@ bool Bot::hasHostage () {
return false; return false;
} }
for (auto hostage : m_hostages) { for (auto &hostage : m_hostages) {
if (!game.isNullEntity (hostage)) { if (!game.isNullEntity (hostage)) {
// don't care about dead hostages // don't care about dead hostages

View file

@ -123,7 +123,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
else if (strcmp (classname, "func_vip_safetyzone") == 0 || strcmp (classname, "info_vip_safetyzone") == 0) { else if (strcmp (classname, "func_vip_safetyzone") == 0 || strcmp (classname, "info_vip_safetyzone") == 0) {
m_mapFlags |= MapFlags::Assassination; // assassination map m_mapFlags |= MapFlags::Assassination; // assassination map
} }
else if (strcmp (classname, "hostage_entity") == 0) { else if (strcmp (classname, "hostage_entity") == 0 || strcmp (classname, "monster_scientist") == 0) {
m_mapFlags |= MapFlags::HostageRescue; // rescue map m_mapFlags |= MapFlags::HostageRescue; // rescue map
} }
else if (strcmp (classname, "func_bomb_target") == 0 || strcmp (classname, "info_bomb_target") == 0) { else if (strcmp (classname, "func_bomb_target") == 0 || strcmp (classname, "info_bomb_target") == 0) {

View file

@ -2751,6 +2751,7 @@ void BotGraph::addBasic () {
autoCreateForEntity (NodeAddFlag::Goal, "func_bomb_target"); // bombspot zone autoCreateForEntity (NodeAddFlag::Goal, "func_bomb_target"); // bombspot zone
autoCreateForEntity (NodeAddFlag::Goal, "info_bomb_target"); // bombspot zone (same as above) autoCreateForEntity (NodeAddFlag::Goal, "info_bomb_target"); // bombspot zone (same as above)
autoCreateForEntity (NodeAddFlag::Goal, "hostage_entity"); // hostage entities autoCreateForEntity (NodeAddFlag::Goal, "hostage_entity"); // hostage entities
autoCreateForEntity (NodeAddFlag::Goal, "monster_scientist"); // hostage entities (same as above)
autoCreateForEntity (NodeAddFlag::Goal, "func_vip_safetyzone"); // vip rescue (safety) zone autoCreateForEntity (NodeAddFlag::Goal, "func_vip_safetyzone"); // vip rescue (safety) zone
autoCreateForEntity (NodeAddFlag::Goal, "func_escapezone"); // terrorist escape zone autoCreateForEntity (NodeAddFlag::Goal, "func_escapezone"); // terrorist escape zone
} }

View file

@ -79,9 +79,7 @@ int Bot::findBestGoal () {
return findGoalPost (tactic, defensiveNodes, offensiveNodes); return findGoalPost (tactic, defensiveNodes, offensiveNodes);
} }
else if (m_team == Team::CT && hasHostage ()) { else if (m_team == Team::CT && hasHostage ()) {
tactic = 2; tactic = 4;
offensiveNodes = &graph.m_rescuePoints;
return findGoalPost (tactic, defensiveNodes, offensiveNodes); return findGoalPost (tactic, defensiveNodes, offensiveNodes);
} }
@ -208,6 +206,31 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive) {
postprocessGoals (graph.m_goalPoints, goalChoices); postprocessGoals (graph.m_goalPoints, goalChoices);
} }
} }
else if (tactic == 4 && !graph.m_rescuePoints.empty ()) // rescue goal
{
// force ct with hostage(s) to select closest rescue goal
float minDist = kInfiniteDistance;
int count = 0;
for (auto &point : graph.m_rescuePoints) {
float distance = graph[point].origin.distanceSq (pev->origin);
if (distance < minDist) {
goalChoices[count] = point;
if (++count > 3) {
count = 0;
}
minDist = distance;
}
}
for (auto &choice : goalChoices) {
if (choice == kInvalidNodeIndex) {
choice = graph.m_rescuePoints.random ();
}
}
}
if (!graph.exists (m_currentNodeIndex)) { if (!graph.exists (m_currentNodeIndex)) {
m_currentNodeIndex = changePointIndex (findNearestNode ()); m_currentNodeIndex = changePointIndex (findNearestNode ());