fix: hostage code (#269)
fix: hostage code add: yb_random_knife_attacks cvar
This commit is contained in:
parent
0b5658c065
commit
f55ac6c5c4
5 changed files with 100 additions and 8 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 ());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue