From 286debd0d1a8739fcb92b2220db818d40fcc2dfb Mon Sep 17 00:00:00 2001 From: EfeDursun125 <39811406+EfeDursun125@users.noreply.github.com> Date: Tue, 9 Aug 2022 19:12:25 +0300 Subject: [PATCH] Add files via upload --- source/basecode.cpp | 108 +- source/combat.cpp | 3869 +++++++++++++++++++++--------------------- source/control.cpp | 28 +- source/engine.cpp | 44 +- source/globals.cpp | 8 +- source/interface.cpp | 16 - source/navigate.cpp | 288 +--- source/support.cpp | 31 +- source/waypoint.cpp | 2 +- 9 files changed, 2136 insertions(+), 2258 deletions(-) diff --git a/source/basecode.cpp b/source/basecode.cpp index 770696ab..bc1227a8 100644 --- a/source/basecode.cpp +++ b/source/basecode.cpp @@ -26,21 +26,21 @@ // console variables ConVar ebot_debug("ebot_debug", "0"); -ConVar ebot_debuggoal("ebot_debuggoal", "-1"); +ConVar ebot_debuggoal("ebot_debug_goal", "-1"); ConVar ebot_gamemod("ebot_gamemode", "0"); -ConVar ebot_followuser("ebot_followuser_max", "1"); -ConVar ebot_knifemode("ebot_knifemode", "0"); -ConVar ebot_walkallow("ebot_walkallow", "1"); -ConVar ebot_stopbots("ebot_stopbots", "0"); -ConVar ebot_spraypaints("ebot_spraypaints", "1"); -ConVar ebot_restrictweapons("ebot_restrictweapons", ""); +ConVar ebot_followuser("ebot_follow_user_max", "1"); +ConVar ebot_knifemode("ebot_knife_mode", "0"); +ConVar ebot_walkallow("ebot_walk_allow", "1"); +ConVar ebot_stopbots("ebot_stop_bots", "0"); +ConVar ebot_spraypaints("ebot_spray_paints", "1"); +ConVar ebot_restrictweapons("ebot_restrict_weapons", ""); ConVar ebot_camp_min("ebot_camp_time_min", "16"); ConVar ebot_camp_max("ebot_camp_time_max", "48"); ConVar ebot_use_radio("ebot_use_radio", "1"); ConVar ebot_anti_block("ebot_anti_block", "0"); ConVar ebot_zm_dark_mode("ebot_zm_dark_mode", "0"); -ConVar ebot_zm_fov("ebot_zm_fov", "90"); +ConVar ebot_zm_fov("ebot_zm_mode_fov", "90"); ConVar ebot_force_flashlight("ebot_force_flashlight", "0"); ConVar ebot_use_flare("ebot_zombie_mode_use_flares", "1"); ConVar ebot_chat_percent("ebot_chat_percent", "20"); @@ -1139,7 +1139,6 @@ void Bot::CheckMessageQueue(void) { m_buyPending = true; m_buyingFinished = true; - break; } @@ -1163,25 +1162,24 @@ void Bot::CheckMessageQueue(void) if (*(INFOKEY_VALUE(GET_INFOKEYBUFFER(GetEntity()), "model")) == 'v') { m_isVIP = true; - m_buyState = 6; - m_pathType = 1; + m_buyState = 7; } } // prevent terrorists from buying on es maps if ((g_mapType & MAP_ES) && m_team == TEAM_TERRORIST) - m_buyState = 6; + m_buyState = 76; // prevent teams from buying on fun maps if (g_mapType & (MAP_KA | MAP_FY | MAP_AWP)) { - m_buyState = 6; + m_buyState = 7; if (g_mapType & MAP_KA) ebot_knifemode.SetInt(1); } - if (m_buyState > 5) + if (m_buyState > 6) { m_buyingFinished = true; return; @@ -1559,27 +1557,52 @@ void Bot::PerformWeaponPurchase(void) break; case 3: - if (engine->RandomInt(1, 100) < g_grenadeBuyPrecent[0] && m_moneyAmount >= g_grenadeBuyMoney[0] && !IsRestricted(WEAPON_HEGRENADE)) + if (!HasPrimaryWeapon() && !ChanceOf(m_skill) && !IsRestricted(WEAPON_SHIELDGUN)) + { + FakeClientCommand(GetEntity(), "buyequip"); + FakeClientCommand(GetEntity(), "menuselect 8"); + } + + if (engine->RandomInt(1, 2) == 1) + { + FakeClientCommand(GetEntity(), "buy;menuselect 1"); + + if (engine->RandomInt(1, 2) == 1) + FakeClientCommand(GetEntity(), "menuselect 4"); + else + FakeClientCommand(GetEntity(), "menuselect 5"); + } + + break; + + case 4: + if (ChanceOf(m_skill) && m_moneyAmount >= g_grenadeBuyMoney[0] && !IsRestricted(WEAPON_HEGRENADE)) { FakeClientCommand(GetEntity(), "buyequip"); FakeClientCommand(GetEntity(), "menuselect 4"); } - if (engine->RandomInt(1, 100) < g_grenadeBuyPrecent[1] && m_moneyAmount >= g_grenadeBuyMoney[1] && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_FBGRENADE)) + if (ChanceOf(m_skill) && m_moneyAmount >= g_grenadeBuyMoney[1] && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_FBGRENADE)) + { + FakeClientCommand(GetEntity(), "buyequip"); + FakeClientCommand(GetEntity(), "menuselect 3"); + } + + if (ChanceOf(m_skill) && m_moneyAmount >= g_grenadeBuyMoney[1] && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_FBGRENADE)) { FakeClientCommand(GetEntity(), "buyequip"); FakeClientCommand(GetEntity(), "menuselect 3"); } - if (engine->RandomInt(1, 100) < g_grenadeBuyPrecent[2] && m_moneyAmount >= g_grenadeBuyMoney[2] && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_SMGRENADE)) + if (ChanceOf(m_skill) && m_moneyAmount >= g_grenadeBuyMoney[2] && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_SMGRENADE)) { FakeClientCommand(GetEntity(), "buyequip"); FakeClientCommand(GetEntity(), "menuselect 5"); } break; - case 4: - if ((g_mapType & MAP_DE) && m_team == TEAM_COUNTER && engine->RandomInt(1, 100) < 80 && m_moneyAmount > 200 && !IsRestricted(WEAPON_DEFUSER)) + case 5: + if ((g_mapType & MAP_DE) && m_team == TEAM_COUNTER && ChanceOf(m_skill) && m_moneyAmount > 200 && !IsRestricted(WEAPON_DEFUSER)) { if (g_gameVersion == CSVER_VERYOLD) FakeClientCommand(GetEntity(), "buyequip;menuselect 6"); @@ -1589,19 +1612,20 @@ void Bot::PerformWeaponPurchase(void) break; - case 5: + case 6: for (int i = 0; i <= 5; i++) FakeClientCommand(GetEntity(), "buyammo%d", engine->RandomInt(1, 2)); // simulate human - if (HasPrimaryWeapon()) + if (ChanceOf(m_skill)) FakeClientCommand(GetEntity(), "buy;menuselect 7"); - - FakeClientCommand(GetEntity(), "buy;menuselect 6"); + else + FakeClientCommand(GetEntity(), "buy;menuselect 6"); if (m_reloadState != RSTATE_PRIMARY) m_reloadState = RSTATE_SECONDARY; break; + } m_buyState++; @@ -3659,6 +3683,7 @@ void Bot::Think(void) if (!m_buyingFinished) ResetCollideState(); + pev->flags |= FL_FAKECLIENT; pev->button = 0; m_moveSpeed = 0.0f; m_strafeSpeed = 0.0f; @@ -3751,11 +3776,11 @@ void Bot::Think(void) else if (m_buyingFinished && !(pev->maxspeed < 10.0f && GetCurrentTask()->taskID != TASK_PLANTBOMB && GetCurrentTask()->taskID != TASK_DEFUSEBOMB) && !ebot_stopbots.GetBool()) botMovement = true; - if (m_randomattacktimer < engine->GetTime() && !engine->IsFriendlyFireOn() && !HasHostage()) // ebot 1.50 - simulate players with random knife attacks + if (m_randomattacktimer < engine->GetTime() && !engine->IsFriendlyFireOn() && !HasHostage()) // simulate players with random knife attacks { if (m_currentWeapon == WEAPON_KNIFE) { - if (ChanceOf(65)) + if (engine->RandomInt(1, 3) == 1) pev->button |= IN_ATTACK; else pev->button |= IN_ATTACK2; @@ -3798,9 +3823,8 @@ void Bot::SecondThink(void) if (ebot_use_flare.GetInt() == 1 && !m_isReloading && !m_isZombieBot && GetGameMod() == MODE_ZP && FNullEnt(m_enemy) && !FNullEnt(m_lastEnemy)) { - if (ChanceOf(50)) - if (pev->weapons & (1 << WEAPON_SMGRENADE)) - PushTask(TASK_THROWFLARE, TASKPRI_THROWGRENADE, -1, engine->RandomFloat(0.6f, 0.9f), false); + if (pev->weapons & (1 << WEAPON_SMGRENADE) && ChanceOf(50)) + PushTask(TASK_THROWFLARE, TASKPRI_THROWGRENADE, -1, engine->RandomFloat(0.6f, 0.9f), false); } // force flashlight support @@ -4148,12 +4172,7 @@ void Bot::RunTask(void) // do pathfinding if it's not the current waypoint if (destIndex != m_currentWaypointIndex && IsValidWaypoint(destIndex)) - { - if ((g_bombPlanted && m_team == TEAM_COUNTER) || (!g_bombPlanted && m_isBomber)) - FindPath(m_currentWaypointIndex, destIndex); - else - FindPath(m_currentWaypointIndex, destIndex, m_pathType); - } + FindPath(m_currentWaypointIndex, destIndex); } else { @@ -4275,7 +4294,7 @@ void Bot::RunTask(void) m_tasks->data = destIndex; if (destIndex != m_currentWaypointIndex && IsValidWaypoint(destIndex)) - FindPath(m_currentWaypointIndex, destIndex, m_pathType); + FindPath(m_currentWaypointIndex, destIndex); } // bots skill higher than 50? @@ -4325,7 +4344,6 @@ void Bot::RunTask(void) TaskComplete(); m_prevGoalIndex = -1; - m_pathType = 1; // start hide task PushTask(TASK_HIDE, TASKPRI_HIDE, -1, engine->GetTime() + engine->RandomFloat(5.0f, 15.0f), false); @@ -4382,7 +4400,7 @@ void Bot::RunTask(void) m_tasks->data = destIndex; if (destIndex != m_currentWaypointIndex && IsValidWaypoint(destIndex)) - FindPath(m_currentWaypointIndex, destIndex, 2); + FindPath(m_currentWaypointIndex, destIndex); } break; @@ -4539,8 +4557,7 @@ void Bot::RunTask(void) { m_prevGoalIndex = destIndex; m_tasks->data = destIndex; - - FindPath(m_currentWaypointIndex, destIndex, m_pathType); + FindPath(m_currentWaypointIndex, destIndex); } else TaskComplete(); @@ -4635,7 +4652,7 @@ void Bot::RunTask(void) } // find a visible waypoint to this direction... - // i know this is ugly hack, but i just don't want to break compatiability :) + // i know this is ugly hack, but i just don't want to break compatiability int numFoundPoints = 0; int foundPoints[3]; int distanceTab[3]; @@ -4822,7 +4839,7 @@ void Bot::RunTask(void) m_prevGoalIndex = forcedestIndex; GetCurrentTask()->data = forcedestIndex; - FindPath(m_currentWaypointIndex, forcedestIndex, m_pathType); + FindPath(m_currentWaypointIndex, forcedestIndex); } else TaskComplete(); @@ -5112,7 +5129,7 @@ void Bot::RunTask(void) m_prevGoalIndex = destIndex; m_tasks->data = destIndex; - FindPath(m_currentWaypointIndex, destIndex, m_pathType); + FindPath(m_currentWaypointIndex, destIndex); } } @@ -6938,7 +6955,6 @@ void Bot::TakeDamage(edict_t* inflictor, int /*damage*/, int /*armor*/, int bits m_lastDamageOrigin = GetPlayerHeadOrigin(inflictor); m_damageTime = engine->GetTime() + 1.0f; - m_aimstoptime = engine->GetTime(); if (GetTeam(inflictor) == m_team) return; @@ -7201,12 +7217,12 @@ void Bot::MoveToVector(Vector to) int index = g_waypoint->FindNearest(pev->origin, 9999.0f, -1, GetEntity()); if(IsValidWaypoint(index)) - FindPath(index, g_waypoint->FindNearest(to), 2); + FindPath(index, g_waypoint->FindNearest(to)); return; } - FindPath(m_currentWaypointIndex, g_waypoint->FindNearest(to), 2); + FindPath(m_currentWaypointIndex, g_waypoint->FindNearest(to)); } void Bot::RunPlayerMovement(void) @@ -7320,7 +7336,7 @@ float Bot::GetEstimatedReachTime(void) if (longTermReachability) estimatedTime *= 2.0f; - estimatedTime = engine->Clamp(estimatedTime, 2.0f, longTermReachability ? 8.0f : 5.0f); + estimatedTime = Clamp(estimatedTime, 2.0f, longTermReachability ? 8.0f : 5.0f); } return estimatedTime; diff --git a/source/combat.cpp b/source/combat.cpp index f1965036..b3691af3 100644 --- a/source/combat.cpp +++ b/source/combat.cpp @@ -1,1942 +1,1941 @@ -// -// Copyright (c) 2003-2009, by Yet Another POD-Bot Development Team. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -// $Id:$ -// - -#include - -ConVar ebot_escape("ebot_zombie_escape_mode", "0"); -ConVar ebot_zp_use_grenade_percent("ebot_zp_use_grenade_percent", "40"); - -int Bot::GetNearbyFriendsNearPosition(Vector origin, int radius) -{ - if (GetGameMod() == MODE_DM) - return 0; - - int count = 0; - for (const auto& client : g_clients) - { - if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team != m_team || client.ent == GetEntity()) - continue; - - if ((client.origin - origin).GetLength() <= radius) - count++; - } - - return count; -} - -int Bot::GetNearbyEnemiesNearPosition(Vector origin, int radius) -{ - int count = 0; - for (const auto& client : g_clients) - { - if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team == m_team) - continue; - - if ((client.origin - origin).GetLength() <= radius) - count++; - } - - return count; -} - -float Bot::GetEntityDistance(edict_t* entity) -{ - if (FNullEnt(entity)) - return 9999.0f; - - float distance = (pev->origin - GetEntityOrigin(entity)).GetLength(); - if (distance <= 128.0f) - return distance; - - int srcIndex, destIndex; - if (m_isZombieBot || !IsZombieEntity(entity) || (m_currentWeapon == WEAPON_KNIFE && !FNullEnt(m_moveTargetEntity))) - { - srcIndex = m_currentWaypointIndex; - destIndex = GetEntityWaypoint(entity); - } - else - { - srcIndex = GetEntityWaypoint(entity); - destIndex = m_currentWaypointIndex; - } - - if (!IsValidWaypoint(srcIndex) || !IsValidWaypoint(destIndex < 0) || srcIndex == destIndex) - return distance; - - Path* path = g_waypoint->GetPath(srcIndex); - for (int j = 0; j < Const_MaxPathIndex; j++) - { - if (path->index[j] != destIndex) - continue; - - if (path->connectionFlags[j] & PATHFLAG_JUMP) - return distance * 1.25f; - - return distance; - } - - float wpDistance = g_waypoint->GetPathDistanceFloat(srcIndex, destIndex); - if (wpDistance < distance) - return distance; - - return wpDistance; -} - -bool Bot::LookupEnemy(void) -{ - m_visibility = 0; - m_enemyOrigin = nullvec; - - if (m_blindTime > engine->GetTime()) - return false; - - if (!FNullEnt(m_lastEnemy)) - { - if (IsNotAttackLab(m_lastEnemy) || !IsAlive(m_lastEnemy) || (GetTeam(m_lastEnemy) == m_team)) - SetLastEnemy(null); - } - - if (!FNullEnt(m_lastVictim)) - { - if (!IsValidPlayer(m_lastVictim) || !IsAlive(m_lastVictim) || (GetTeam(m_lastVictim) == m_team)) - m_lastVictim = null; - } - - int i; - edict_t* entity = null, * targetEntity = null; - float enemy_distance = 9999.0f; - - edict_t* oneTimeCheckEntity = null; - - if (m_enemyAPI != null) - { - if (m_blockCheckEnemyTime <= engine->GetTime() || !IsAlive(m_enemyAPI) || m_team == GetTeam(m_enemyAPI) || IsNotAttackLab(m_enemyAPI)) - { - m_enemyAPI = null; - m_blockCheckEnemyTime = engine->GetTime(); - } - } - else - m_blockCheckEnemyTime = engine->GetTime(); - - if (!FNullEnt(m_enemy)) - { - if ((!FNullEnt(m_enemyAPI) && m_enemyAPI != m_enemy) || m_team == GetTeam(m_enemy) || IsNotAttackLab(m_enemy) || !IsAlive(m_enemy)) - { - SetEnemy(null); - SetLastEnemy(null); - m_enemyUpdateTime = 0.0f; - } - - if ((m_enemyUpdateTime > engine->GetTime())) - { - if (IsEnemyViewable(m_enemy, true, true) || IsShootableThruObstacle(m_enemy)) - { - m_aimFlags |= AIM_ENEMY; - return true; - } - - oneTimeCheckEntity = m_enemy; - } - - targetEntity = m_enemy; - enemy_distance = GetEntityDistance(m_enemy); - } - else if (!FNullEnt(m_moveTargetEntity)) - { - if ((!FNullEnt(m_enemyAPI) && m_enemyAPI != m_moveTargetEntity) || m_team == GetTeam(m_moveTargetEntity) || !IsAlive(m_moveTargetEntity) || GetEntityOrigin(m_moveTargetEntity) == nullvec) - SetMoveTarget(null); - - targetEntity = m_moveTargetEntity; - enemy_distance = GetEntityDistance(m_moveTargetEntity); - } - - if (!FNullEnt(m_enemyAPI)) - { - enemy_distance = GetEntityDistance(m_enemyAPI); - targetEntity = m_enemyAPI; - - if (!IsEnemyViewable(targetEntity, true, true)) - { - g_botsCanPause = false; - - SetMoveTarget(targetEntity); - return false; - } - - oneTimeCheckEntity = targetEntity; - } - else - { - int allEnemy = 0; - for (i = 0; i < checkEnemyNum; i++) - { - m_allEnemyId[i] = -1; - m_allEnemyDistance[i] = 9999.9f; - - m_enemyEntityId[i] = -1; - m_enemyEntityDistance[i] = 9999.9f; - } - - for (i = 0; i < engine->GetMaxClients(); i++) - { - entity = INDEXENT(i + 1); - - if (!IsAlive(entity) || GetTeam(entity) == m_team || GetEntity() == entity) - continue; - - m_allEnemyId[allEnemy] = i + 1; - m_allEnemyDistance[allEnemy] = GetEntityDistance(entity); - allEnemy++; - } - - for (i = 0; i < entityNum; i++) - { - if (g_entityId[i] == -1 || g_entityAction[i] != 1) - continue; - - if (m_team == g_entityTeam[i]) - continue; - - entity = INDEXENT(g_entityId[i]); - if (FNullEnt(entity) || !IsAlive(entity)) - continue; - - if (entity->v.effects & EF_NODRAW || entity->v.takedamage == DAMAGE_NO) - continue; - - m_allEnemyId[allEnemy] = g_entityId[i]; - m_allEnemyDistance[allEnemy] = GetEntityDistance(entity); - allEnemy++; - } - - for (i = 0; i < allEnemy; i++) - { - for (int y = 0; y < checkEnemyNum; y++) - { - if (m_allEnemyDistance[i] > m_enemyEntityDistance[y]) - continue; - - for (int z = allEnemy - 1; z >= y; z--) - { - if (z == allEnemy - 1 || m_enemyEntityId[z] == -1) - continue; - - m_enemyEntityId[z + 1] = m_enemyEntityId[z]; - m_enemyEntityDistance[z + 1] = m_enemyEntityDistance[z]; - } - - m_enemyEntityId[y] = m_allEnemyId[i]; - m_enemyEntityDistance[y] = m_allEnemyDistance[i]; - - break; - } - } - - bool allCheck = false; - if ((m_isZombieBot || (m_currentWaypointIndex == WEAPON_KNIFE && targetEntity == m_moveTargetEntity)) && FNullEnt(m_enemy) && !FNullEnt(m_moveTargetEntity)) - { - if (!IsEnemyViewable(m_moveTargetEntity, false, true, true)) - allCheck = true; - } - - for (i = 0; i < checkEnemyNum; i++) - { - if (m_enemyEntityId[i] == -1) - continue; - - entity = INDEXENT(m_enemyEntityId[i]); - if (entity == oneTimeCheckEntity) - continue; - - if (m_blindRecognizeTime < engine->GetTime() && IsBehindSmokeClouds(entity)) - m_blindRecognizeTime = engine->GetTime() + engine->RandomFloat(2.0f, 3.0f); - - if (m_blindRecognizeTime >= engine->GetTime()) - continue; - - if (IsValidPlayer(entity) && IsEnemyProtectedByShield(entity)) - continue; - - if (IsEnemyViewable(entity, true, allCheck, true)) - { - enemy_distance = m_enemyEntityDistance[i]; - targetEntity = entity; - oneTimeCheckEntity = entity; - - break; - } - } - } - - if (!FNullEnt(m_moveTargetEntity) && m_moveTargetEntity != targetEntity) - { - if (m_currentWaypointIndex != GetEntityWaypoint(targetEntity)) - { - float distance = GetEntityDistance(m_moveTargetEntity); - if (distance <= enemy_distance + 400.0f) - { - int targetWpIndex = GetEntityWaypoint(targetEntity); - bool shortDistance = false; - - Path* path = g_waypoint->GetPath(m_currentWaypointIndex); - for (int j = 0; j < Const_MaxPathIndex; j++) - { - if (path->index[j] != targetWpIndex) - continue; - - if (path->connectionFlags[j] & PATHFLAG_JUMP) - break; - - shortDistance = true; - } - - if (shortDistance == false) - { - enemy_distance = distance; - targetEntity = null; - } - } - } - } - - if (!FNullEnt(targetEntity)) // Last Checking - { - enemy_distance = GetEntityDistance(targetEntity); - if (oneTimeCheckEntity != targetEntity && !IsEnemyViewable(targetEntity, true, true)) - targetEntity = null; - } - - if (!FNullEnt(m_enemy) && FNullEnt(targetEntity)) - { - if (m_isZombieBot || (m_currentWaypointIndex == WEAPON_KNIFE && targetEntity == m_moveTargetEntity)) - { - g_botsCanPause = false; - - SetMoveTarget(m_enemy); - return false; - } - else if (IsShootableThruObstacle(m_enemy)) - { - m_enemyOrigin = GetEntityOrigin(m_enemy); - m_visibility = VISIBILITY_BODY; - return true; - } - } - - if (!FNullEnt(targetEntity)) - { - if (m_isZombieBot || m_currentWeapon == WEAPON_KNIFE) - { - bool moveTotarget = true; - int movePoint = 0; - int srcIndex = GetEntityWaypoint(GetEntity()); - int destIndex = GetEntityWaypoint(targetEntity); - if ((m_currentTravelFlags & PATHFLAG_JUMP)) - movePoint = 10; - else if (srcIndex == destIndex || m_currentWaypointIndex == destIndex) - moveTotarget = false; - else - { - Path* path; - while (srcIndex != destIndex && movePoint <= 3 && srcIndex >= 0 && destIndex >= 0) - { - path = g_waypoint->GetPath(srcIndex); - srcIndex = *(g_waypoint->m_pathMatrix + (srcIndex * g_numWaypoints) + destIndex); - if (srcIndex < 0) - continue; - - movePoint++; - for (int j = 0; j < Const_MaxPathIndex; j++) - { - if (path->index[j] == srcIndex && - path->connectionFlags[j] & PATHFLAG_JUMP) - { - movePoint += 3; - break; - } - } - } - } - - enemy_distance = (GetEntityOrigin(targetEntity) - pev->origin).GetLength(); - if ((enemy_distance <= 150.0f && movePoint <= 1) || - (targetEntity == m_moveTargetEntity && movePoint <= 2)) - { - moveTotarget = false; - if (targetEntity == m_moveTargetEntity && movePoint <= 1) - m_enemyUpdateTime = engine->GetTime() + 4.0f; - } - - if (moveTotarget) - { - if (IsOnAttackDistance(targetEntity, 80.0f)) - KnifeAttack(); - - if (targetEntity != m_moveTargetEntity) - { - g_botsCanPause = false; - - m_targetEntity = null; - SetMoveTarget(targetEntity); - } - - return false; - } - - if (m_enemyUpdateTime < engine->GetTime() + 3.0f) - m_enemyUpdateTime = engine->GetTime() + 2.5f; - } - - g_botsCanPause = true; - m_aimFlags |= AIM_ENEMY; - - if (targetEntity == m_enemy) - { - m_seeEnemyTime = engine->GetTime(); - - m_actualReactionTime = 0.0f; - SetLastEnemy(targetEntity); - - return true; - } - - if (m_seeEnemyTime + 3.0f < engine->GetTime() && (pev->weapons & (1 << WEAPON_C4) || HasHostage() || !FNullEnt(m_targetEntity))) - RadioMessage(Radio_EnemySpotted); - - m_targetEntity = null; - - if (engine->RandomInt(0, 100) < m_skill) - m_enemySurpriseTime = engine->GetTime() + (m_actualReactionTime / 3); - else - m_enemySurpriseTime = engine->GetTime() + m_actualReactionTime; - - m_actualReactionTime = 0.0f; - - SetEnemy(targetEntity); - SetLastEnemy(m_enemy); - m_seeEnemyTime = engine->GetTime(); - - if (!m_isZombieBot) - m_enemyUpdateTime = engine->GetTime() + 1.0f; - - return true; - } - - if ((m_aimFlags <= AIM_PREDICTENEMY && m_seeEnemyTime + 4.0f < engine->GetTime() && !(m_states & (STATE_SEEINGENEMY | STATE_HEARENEMY)) && FNullEnt(m_lastEnemy) && FNullEnt(m_enemy) && GetCurrentTask()->taskID != TASK_DESTROYBREAKABLE && GetCurrentTask()->taskID != TASK_PLANTBOMB && GetCurrentTask()->taskID != TASK_DEFUSEBOMB) || g_roundEnded) - { - if (!m_reloadState) - m_reloadState = RSTATE_PRIMARY; - } - - if ((UsesSniper() || UsesZoomableRifle()) && m_zoomCheckTime + 1.0f < engine->GetTime()) - { - if (pev->fov < 90) - pev->button |= IN_ATTACK2; - else - m_zoomCheckTime = 0.0f; - } - - return false; -} - -Vector Bot::GetAimPosition(void) -{ - Vector enemyOrigin = GetEntityOrigin(m_enemy); - if (enemyOrigin == nullvec) - return m_enemyOrigin = m_lastEnemyOrigin; - - if (!(m_states & STATE_SEEINGENEMY)) - { - if (!IsValidPlayer(m_enemy)) - return m_enemyOrigin = enemyOrigin; - - enemyOrigin.x += engine->RandomFloat(m_enemy->v.mins.x, m_enemy->v.maxs.x); - enemyOrigin.y += engine->RandomFloat(m_enemy->v.mins.y, m_enemy->v.maxs.y); - enemyOrigin.z += engine->RandomFloat(m_enemy->v.mins.z, m_enemy->v.maxs.z); - - return m_enemyOrigin = enemyOrigin; - } - - if (!IsValidPlayer(m_enemy)) - return m_enemyOrigin = m_lastEnemyOrigin = enemyOrigin; - - if ((m_visibility & (VISIBILITY_HEAD | VISIBILITY_BODY))) - { - if (GetGameMod() == MODE_ZP || ((m_skill >= 80 || m_skill >= engine->RandomInt(0, 100)) && (m_currentWeapon != WEAPON_AWP || m_enemy->v.health >= 100))) - enemyOrigin = GetPlayerHeadOrigin(m_enemy); - } - else if (m_visibility & VISIBILITY_HEAD) - enemyOrigin = GetPlayerHeadOrigin(m_enemy); - else if (m_visibility & VISIBILITY_OTHER) - enemyOrigin = m_enemyOrigin; - else - enemyOrigin = m_lastEnemyOrigin; - - if ((GetGameMod() == MODE_BASE || IsDeathmatchMode()) && m_skill <= engine->RandomInt(30, 60)) - { - enemyOrigin.x += engine->RandomFloat(m_enemy->v.mins.x, m_enemy->v.maxs.x); - enemyOrigin.y += engine->RandomFloat(m_enemy->v.mins.y, m_enemy->v.maxs.y); - enemyOrigin.z += engine->RandomFloat(m_enemy->v.mins.z, m_enemy->v.maxs.z); - } - - return m_enemyOrigin = m_lastEnemyOrigin = enemyOrigin; -} - -// bot can't hurt teammates, if friendly fire is not enabled... -bool Bot::IsFriendInLineOfFire(float distance) -{ - if (!engine->IsFriendlyFireOn() || GetGameMod() == MODE_DM) - return false; - - MakeVectors(pev->v_angle); - - TraceResult tr; - TraceLine(EyePosition(), EyePosition() + pev->v_angle.Normalize() * distance, false, false, GetEntity(), &tr); - - int i; - if (!FNullEnt(tr.pHit)) - { - if (IsAlive(tr.pHit) && m_team == GetTeam(tr.pHit)) - { - if (IsValidPlayer(tr.pHit)) - return true; - - int entityIndex = ENTINDEX(tr.pHit); - for (i = 0; i < entityNum; i++) - { - if (g_entityId[i] == -1 || g_entityAction[i] != 1) - continue; - - if (g_entityId[i] == entityIndex) - return true; - } - } - } - - edict_t* entity = null; - for (i = 0; i < engine->GetMaxClients(); i++) - { - entity = INDEXENT(i + 1); - - if (FNullEnt(entity) || !IsAlive(entity) || GetTeam(entity) != m_team || GetEntity() == entity) - continue; - - float friendDistance = (GetEntityOrigin(entity) - pev->origin).GetLength(); - float squareDistance = sse_rsqrt(1089.0f + (friendDistance * friendDistance)); - - if (friendDistance <= distance) - { - Vector entOrigin = GetEntityOrigin(entity); - if (GetShootingConeDeviation(GetEntity(), &entOrigin) > - ((friendDistance * friendDistance) / (squareDistance * squareDistance))) - return true; - } - } - - return false; -} - -int CorrectGun(int weaponID) -{ - if (GetGameMod() != MODE_BASE) - return 0; - - if (weaponID == WEAPON_AUG || weaponID == WEAPON_M4A1 || weaponID == WEAPON_SG552 || weaponID == WEAPON_AK47 || weaponID == WEAPON_FAMAS || weaponID == WEAPON_GALIL) - return 2; - else if (weaponID == WEAPON_SG552 || weaponID == WEAPON_G3SG1) - return 3; - - return 0; -} - -bool Bot::IsShootableThruObstacle(edict_t* entity) -{ - if (FNullEnt(entity) || !IsValidPlayer(entity) || IsZombieEntity(entity)) - return false; - - if (entity->v.health >= 60.0f) - return false; - - int currentWeaponPenetrationPower = CorrectGun(m_currentWeapon); - if (currentWeaponPenetrationPower == 0) - return false; - - TraceResult tr; - Vector dest = GetEntityOrigin(entity); - - float obstacleDistance = 0.0f; - - TraceLine(EyePosition(), dest, true, GetEntity(), &tr); - - if (tr.fStartSolid) - { - Vector source = tr.vecEndPos; - - TraceLine(dest, source, true, GetEntity(), &tr); - if (tr.flFraction != 1.0f) - { - if ((tr.vecEndPos - dest).GetLength() > 800.0f) - return false; - - if (tr.vecEndPos.z >= dest.z + 200.0f) - return false; - - if (dest.z >= tr.vecEndPos.z + 200.0f) - return false; - - obstacleDistance = (tr.vecEndPos - source).GetLength(); - } - } - - if (obstacleDistance > 0.0) - { - while (currentWeaponPenetrationPower > 0) - { - if (obstacleDistance > 75.0) - { - obstacleDistance -= 75.0f; - currentWeaponPenetrationPower--; - continue; - } - - return true; - } - } - - return false; -} - -bool Bot::DoFirePause(float distance)//, FireDelay *fireDelay) -{ - if (m_firePause > engine->GetTime()) - return true; - - if ((m_aimFlags & AIM_ENEMY) && m_enemyOrigin != nullvec) - { - if (IsEnemyProtectedByShield(m_enemy) && GetShootingConeDeviation(GetEntity(), &m_enemyOrigin) > 0.92f) - return true; - } - - float angle = (fabsf(pev->punchangle.y) + fabsf(pev->punchangle.x)) * Math::MATH_PI / 360.0f; - - // check if we need to compensate recoil - if (tanf(angle) * (distance + (distance / 4)) > g_skillTab[m_skill / 20].recoilAmount) - { - if (m_firePause < (engine->GetTime() - 0.4)) - m_firePause = engine->GetTime() + engine->RandomFloat(0.4f, 0.4f + 1.2f * ((100 - m_skill) / 100.0f)); - - return true; - } - - if (UsesSniper()) - { - if (!(m_currentTravelFlags & PATHFLAG_JUMP)) - pev->button &= ~IN_JUMP; - - m_moveSpeed = 0.0f; - m_strafeSpeed = 0.0f; - - if (pev->speed >= pev->maxspeed && GetGameMod() != MODE_ZP) - { - m_firePause = engine->GetTime() + 0.1f; - return true; - } - } - - return false; -} - - -void Bot::FireWeapon(void) -{ - // this function will return true if weapon was fired, false otherwise - float distance = (m_lookAt - EyePosition()).GetLength(); // how far away is the enemy? - - // if using grenade stop this - if (m_isUsingGrenade) - { - m_shootTime = engine->GetTime() + 0.2f; - return; - } - - // or if friend in line of fire, stop this too but do not update shoot time - if (!FNullEnt(m_enemy) && IsFriendInLineOfFire(distance)) - return; - - FireDelay* delay = &g_fireDelay[0]; - WeaponSelect* selectTab = &g_weaponSelect[0]; - - edict_t* enemy = m_enemy; - - int selectId = WEAPON_KNIFE, selectIndex = 0, chosenWeaponIndex = 0; - int weapons = pev->weapons; - - - if (m_isZombieBot || ebot_knifemode.GetBool()) - goto WeaponSelectEnd; - else if (!FNullEnt(enemy) && m_skill >= 80 && !IsZombieEntity(enemy) && IsOnAttackDistance(enemy, 120.0f) && - (enemy->v.health <= 30 || pev->health > enemy->v.health) && !IsOnLadder() && !IsGroupOfEnemies(pev->origin)) - goto WeaponSelectEnd; - - // loop through all the weapons until terminator is found... - while (selectTab[selectIndex].id) - { - // is the bot carrying this weapon? - if (weapons & (1 << selectTab[selectIndex].id)) - { - // is enough ammo available to fire AND check is better to use pistol in our current situation... - if ((m_ammoInClip[selectTab[selectIndex].id] > 0) && !IsWeaponBadInDistance(selectIndex, distance)) - chosenWeaponIndex = selectIndex; - } - selectIndex++; - } - selectId = selectTab[chosenWeaponIndex].id; - - // if no available weapon... - if (chosenWeaponIndex == 0) - { - selectIndex = 0; - - // loop through all the weapons until terminator is found... - while (selectTab[selectIndex].id) - { - int id = selectTab[selectIndex].id; - - // is the bot carrying this weapon? - if (weapons & (1 << id)) - { - if (g_weaponDefs[id].ammo1 != -1 && m_ammo[g_weaponDefs[id].ammo1] >= selectTab[selectIndex].minPrimaryAmmo) - { - // available ammo found, reload weapon - if (m_reloadState == RSTATE_NONE || m_reloadCheckTime > engine->GetTime() || GetCurrentTask()->taskID != TASK_ESCAPEFROMBOMB) - { - m_isReloading = true; - m_reloadState = RSTATE_PRIMARY; - m_reloadCheckTime = engine->GetTime(); - m_fearLevel = 1.0f; - - RadioMessage(Radio_NeedBackup); - } - return; - } - } - selectIndex++; - } - selectId = WEAPON_KNIFE; // no available ammo, use knife! - } - -WeaponSelectEnd: - // we want to fire weapon, don't reload now - if (!m_isReloading) - { - m_reloadState = RSTATE_NONE; - m_reloadCheckTime = engine->GetTime() + 5.0f; - } - - if (m_currentWeapon == WEAPON_KNIFE && selectId != WEAPON_KNIFE && GetGameMod() == MODE_ZP && !m_isZombieBot) - { - m_reloadState = RSTATE_PRIMARY; - m_reloadCheckTime = engine->GetTime() + 2.5f; - - return; - } - - if (m_currentWeapon != selectId) - { - SelectWeaponByName(g_weaponDefs[selectId].className); - - // reset burst fire variables - m_firePause = 0.0f; - m_timeLastFired = 0.0f; - - return; - } - - if (delay[chosenWeaponIndex].weaponIndex != selectId) - return; - - if (selectTab[chosenWeaponIndex].id != selectId) - { - chosenWeaponIndex = 0; - - // loop through all the weapons until terminator is found... - while (selectTab[chosenWeaponIndex].id) - { - if (selectTab[chosenWeaponIndex].id == selectId) - break; - - chosenWeaponIndex++; - } - } - - // if we're have a glock or famas vary burst fire mode - CheckBurstMode(distance); - - if (HasShield() && m_shieldCheckTime < engine->GetTime() && GetCurrentTask()->taskID != TASK_CAMP) // better shield gun usage - { - if ((distance > 750.0f) && !IsShieldDrawn()) - pev->button |= IN_ATTACK2; // draw the shield - else if (IsShieldDrawn() || (!FNullEnt(enemy) && (enemy->v.button & IN_RELOAD))) - pev->button |= IN_ATTACK2; // draw out the shield - - m_shieldCheckTime = engine->GetTime() + 2.0f; - } - - if (UsesSniper() && m_zoomCheckTime < engine->GetTime()) // is the bot holding a sniper rifle? - { - if (distance > 1500.0f && pev->fov >= 40.0f) // should the bot switch to the long-range zoom? - pev->button |= IN_ATTACK2; - - else if (distance > 150.0f && pev->fov >= 90.0f) // else should the bot switch to the close-range zoom ? - pev->button |= IN_ATTACK2; - - else if (distance <= 150.0f && pev->fov < 90.0f) // else should the bot restore the normal view ? - pev->button |= IN_ATTACK2; - - m_zoomCheckTime = engine->GetTime(); - } - else if (UsesZoomableRifle() && m_zoomCheckTime < engine->GetTime() && m_skill < 90) // else is the bot holding a zoomable rifle? - { - if (distance > 800.0f && pev->fov >= 90.0f) // should the bot switch to zoomed mode? - pev->button |= IN_ATTACK2; - - else if (distance <= 800.0f && pev->fov < 90.0f) // else should the bot restore the normal view? - pev->button |= IN_ATTACK2; - - m_zoomCheckTime = engine->GetTime(); - } - - // need to care for burst fire? - if (distance < 256.0f || m_blindTime > engine->GetTime()) - { - if (selectId == WEAPON_KNIFE) - KnifeAttack(); - else - { - if (selectTab[chosenWeaponIndex].primaryFireHold) // if automatic weapon, just press attack - pev->button |= IN_ATTACK; - else // if not, toggle buttons - { - if ((pev->oldbuttons & IN_ATTACK) == 0) - pev->button |= IN_ATTACK; - } - } - - if (pev->button & IN_ATTACK) - m_shootTime = engine->GetTime(); - } - else - { - const float baseDelay = delay[chosenWeaponIndex].primaryBaseDelay; - const float minDelay = delay[chosenWeaponIndex].primaryMinDelay[abs((m_skill / 20) - 5)]; - const float maxDelay = delay[chosenWeaponIndex].primaryMaxDelay[abs((m_skill / 20) - 5)]; - - if (DoFirePause(distance))//, &delay[chosenWeaponIndex])) - return; - - // don't attack with knife over long distance - if (selectId == WEAPON_KNIFE) - { - KnifeAttack(); - return; - } - - float delayTime = 0.0f; - if (selectTab[chosenWeaponIndex].primaryFireHold) - { - m_zoomCheckTime = engine->GetTime(); - pev->button |= IN_ATTACK; // use primary attack - } - else - { - pev->button |= IN_ATTACK; // use primary attack - delayTime = baseDelay + engine->RandomFloat(minDelay, maxDelay); - m_zoomCheckTime = engine->GetTime(); - } - - if (!FNullEnt(enemy) && distance >= 1200.0f) - { - if (m_visibility & (VISIBILITY_HEAD | VISIBILITY_BODY)) - delayTime -= (delayTime == 0.0f) ? 0.0f : 0.02f; - else if (m_visibility & VISIBILITY_HEAD) - { - if (distance >= 2400.0f) - delayTime += (delayTime == 0.0f) ? 0.15f : 0.10f; - else - delayTime += (delayTime == 0.0f) ? 0.10f : 0.05f; - } - else if (m_visibility & VISIBILITY_BODY) - { - if (distance >= 2400.f) - delayTime += (delayTime == 0.0f) ? 0.12f : 0.08f; - else - delayTime += (delayTime == 0.0f) ? 0.08f : 0.0f; - } - else - { - if (distance >= 2400.0f) - delayTime += (delayTime == 0.0f) ? 0.18f : 0.15f; - else - delayTime += (delayTime == 0.0f) ? 0.15f : 0.10f; - } - } - m_shootTime = engine->GetTime() + delayTime; - } -} - -bool Bot::KnifeAttack(float attackDistance) -{ - edict_t* entity = null; - float distance = 9999.0f; - if (!FNullEnt(m_enemy)) - { - entity = m_enemy; - distance = (pev->origin - GetEntityOrigin(m_enemy)).GetLength(); - } - - if (!FNullEnt(m_breakableEntity)) - { - if (m_breakable == nullvec) - m_breakable = GetEntityOrigin(m_breakableEntity); - - if ((pev->origin - m_breakable).GetLength() < distance) - { - entity = m_breakableEntity; - distance = (pev->origin - m_breakable).GetLength(); - } - } - - if (FNullEnt(entity)) - return false; - - float kad1 = (m_knifeDistance1API <= 0) ? 64.0f : m_knifeDistance1API;; // Knife Attack Distance (API) - float kad2 = (m_knifeDistance2API <= 0) ? 64.0f : m_knifeDistance2API; - - if (attackDistance != 0.0f) - kad1 = attackDistance; - - int kaMode = 0; - if (IsOnAttackDistance(entity, kad1)) - kaMode = 1; - if (IsOnAttackDistance(entity, kad2)) - kaMode += 2; - - if (kaMode > 0) - { - float distanceSkipZ = (pev->origin - GetEntityOrigin(entity)).GetLength2D(); - - if (pev->origin.z > GetEntityOrigin(entity).z && distanceSkipZ < 64.0f) - { - pev->button |= IN_DUCK; - m_campButtons |= IN_DUCK; - pev->button &= ~IN_JUMP; - } - else - { - pev->button &= ~IN_DUCK; - m_campButtons &= ~IN_DUCK; - - if (pev->origin.z + 150.0f < GetEntityOrigin(entity).z && distanceSkipZ < 300.0f) - pev->button |= IN_JUMP; - } - - if (m_isZombieBot) - { - if (kaMode != 2) - pev->button |= IN_ATTACK; - else - pev->button |= IN_ATTACK2; - } - else - { - if (kaMode == 1) - pev->button |= IN_ATTACK; - else if (kaMode == 2) - pev->button |= IN_ATTACK2; - else if (engine->RandomInt(1, 10) < 3 || HasShield()) - pev->button |= IN_ATTACK; - else - pev->button |= IN_ATTACK2; - } - - return true; - } - - return false; -} - -bool Bot::IsWeaponBadInDistance(int weaponIndex, float distance) -{ - // this function checks, is it better to use pistol instead of current primary weapon - // to attack our enemy, since current weapon is not very good in this situation. - - int weaponID = g_weaponSelect[weaponIndex].id; - - if (weaponID == WEAPON_KNIFE) - return false; - - // check is ammo available for secondary weapon - if (m_ammoInClip[g_weaponSelect[GetBestSecondaryWeaponCarried()].id] >= 1) - return false; - - if (m_gunMinDistanceAPI > 0 || m_gunMaxDistanceAPI > 0) - { - if (m_gunMinDistanceAPI > 0 && m_gunMaxDistanceAPI > 0) - { - if (distance < m_gunMinDistanceAPI || distance > m_gunMaxDistanceAPI) - return true; - } - else if (m_gunMinDistanceAPI > 0) - { - if (distance < m_gunMinDistanceAPI) - return true; - } - else if (m_gunMaxDistanceAPI > 0) - { - if (distance > m_gunMaxDistanceAPI) - return true; - } - return false; - } - - // shotguns is too inaccurate at long distances, so weapon is bad - if ((weaponID == WEAPON_M3 || weaponID == WEAPON_XM1014) && distance > 750.0f) - return true; - - if (GetGameMod() == MODE_BASE) - { - if ((weaponID == WEAPON_SCOUT || weaponID == WEAPON_AWP || weaponID == WEAPON_G3SG1 || weaponID == WEAPON_SG550) && distance < 300.0f) - return true; - } - - return false; -} - -void Bot::FocusEnemy(void) -{ - // aim for the head and/or body - m_lookAt = GetAimPosition(); - - if (m_enemySurpriseTime > engine->GetTime()) - return; - - float distance = (m_lookAt - EyePosition()).GetLength2D(); // how far away is the enemy scum? - - if (distance < 128) - { - if (m_currentWeapon == WEAPON_KNIFE) - { - if (IsOnAttackDistance(m_enemy, (m_knifeDistance1API <= 0) ? 64.0f : m_knifeDistance1API)) - m_wantsToFire = true; - } - else - m_wantsToFire = true; - } - else - { - if (m_currentWeapon == WEAPON_KNIFE) - m_wantsToFire = true; - else - { - float dot = GetShootingConeDeviation(GetEntity(), &m_enemyOrigin); - - if (dot < 0.90f) - m_wantsToFire = false; - else - { - float enemyDot = GetShootingConeDeviation(m_enemy, &pev->origin); - - // enemy faces bot? - if (enemyDot >= 0.90f) - m_wantsToFire = true; - else - { - if (dot > 0.99f) - m_wantsToFire = true; - else - m_wantsToFire = false; - } - } - } - } -} - -void Bot::CombatFight(void) -{ - // our enemy can change teams in fun modes - if (!FNullEnt(m_enemy) && m_team == GetTeam(m_enemy)) - SetEnemy(null); - - // our last enemy can change teams in fun modes - if (!FNullEnt(m_lastEnemy) && m_team == GetTeam(m_lastEnemy)) - SetLastEnemy(m_enemy); - - if ((m_moveSpeed != 0.0f || m_strafeSpeed != 0.0f) && IsValidWaypoint(m_currentWaypointIndex) && g_waypoint->GetPath(m_currentWaypointIndex)->flags & WAYPOINT_CROUCH && (pev->velocity.GetLength() < 2.0f)) - pev->button |= IN_DUCK; - - if (m_isZombieBot) // zombie ai - { - DeleteSearchNodes(); - m_moveToGoal = false; - m_destOrigin = GetEntityOrigin(m_enemy); - m_moveSpeed = pev->maxspeed; - if (m_isSlowThink && pev->speed >= pev->maxspeed) - { - if (engine->RandomInt(1, 2) == 1) - pev->button |= IN_JUMP; - else - pev->button |= IN_DUCK; - } - - const float targetdist = 128.0f; - if ((pev->origin - m_destOrigin).GetLength() <= targetdist) - pev->button |= IN_ATTACK; - - return; - } - else if (IsZombieMode()) // human ai - { - m_timeWaypointMove = 0.0f; - - if (m_timeWaypointMove + m_frameInterval < engine->GetTime()) - { - const Vector enemyOrigin = GetEntityOrigin(m_enemy); - - const bool NPCEnemy = !IsValidPlayer(m_enemy); - const bool enemyIsZombie = IsZombieEntity(m_enemy); - float baseDistance = (fabsf(m_enemy->v.speed) + 400.0f); - - if (NPCEnemy || enemyIsZombie) - { - if (m_currentWeapon == WEAPON_KNIFE) - { - if (::IsInViewCone(pev->origin, m_enemy) && !NPCEnemy) - baseDistance = (fabsf(m_enemy->v.speed) + 400.0f); - else - baseDistance = -1.0f; - } - - const float distance = (pev->origin - enemyOrigin).GetLength(); - if (m_isSlowThink && distance <= 1024.0f && !FNullEnt(m_lastEnemy) && m_lastEnemyOrigin != nullvec && engine->RandomInt(1, 1000) <= ebot_zp_use_grenade_percent.GetInt()) - { - if (engine->RandomInt(1, 2) == 1) - ThrowFrostNade(); - else - ThrowFireNade(); - } - - float lastEnemyDistance = 0.0f; - float baseDistanceLastEnemy = -1.0f; - Vector lastEnemyOrigin = nullvec; - +// +// Copyright (c) 2003-2009, by Yet Another POD-Bot Development Team. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// $Id:$ +// + +#include + +ConVar ebot_escape("ebot_zombie_escape_mode", "0"); +ConVar ebot_zp_use_grenade_percent("ebot_zp_use_grenade_percent", "40"); + +int Bot::GetNearbyFriendsNearPosition(Vector origin, int radius) +{ + if (GetGameMod() == MODE_DM) + return 0; + + int count = 0; + for (const auto& client : g_clients) + { + if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team != m_team || client.ent == GetEntity()) + continue; + + if ((client.origin - origin).GetLength() <= radius) + count++; + } + + return count; +} + +int Bot::GetNearbyEnemiesNearPosition(Vector origin, int radius) +{ + int count = 0; + for (const auto& client : g_clients) + { + if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team == m_team) + continue; + + if ((client.origin - origin).GetLength() <= radius) + count++; + } + + return count; +} + +float Bot::GetEntityDistance(edict_t* entity) +{ + if (FNullEnt(entity)) + return 9999.0f; + + float distance = (pev->origin - GetEntityOrigin(entity)).GetLength(); + if (distance <= 128.0f) + return distance; + + int srcIndex, destIndex; + if (m_isZombieBot || !IsZombieEntity(entity) || (m_currentWeapon == WEAPON_KNIFE && !FNullEnt(m_moveTargetEntity))) + { + srcIndex = m_currentWaypointIndex; + destIndex = GetEntityWaypoint(entity); + } + else + { + srcIndex = GetEntityWaypoint(entity); + destIndex = m_currentWaypointIndex; + } + + if (!IsValidWaypoint(srcIndex) || !IsValidWaypoint(destIndex < 0) || srcIndex == destIndex) + return distance; + + Path* path = g_waypoint->GetPath(srcIndex); + for (int j = 0; j < Const_MaxPathIndex; j++) + { + if (path->index[j] != destIndex) + continue; + + if (path->connectionFlags[j] & PATHFLAG_JUMP) + return distance * 1.25f; + + return distance; + } + + float wpDistance = g_waypoint->GetPathDistanceFloat(srcIndex, destIndex); + if (wpDistance < distance) + return distance; + + return wpDistance; +} + +bool Bot::LookupEnemy(void) +{ + m_visibility = 0; + m_enemyOrigin = nullvec; + + if (m_blindTime > engine->GetTime()) + return false; + + if (!FNullEnt(m_lastEnemy)) + { + if (IsNotAttackLab(m_lastEnemy) || !IsAlive(m_lastEnemy) || (GetTeam(m_lastEnemy) == m_team)) + SetLastEnemy(null); + } + + if (!FNullEnt(m_lastVictim)) + { + if (!IsValidPlayer(m_lastVictim) || !IsAlive(m_lastVictim) || (GetTeam(m_lastVictim) == m_team)) + m_lastVictim = null; + } + + int i; + edict_t* entity = null, * targetEntity = null; + float enemy_distance = 9999.0f; + + edict_t* oneTimeCheckEntity = null; + + if (m_enemyAPI != null) + { + if (m_blockCheckEnemyTime <= engine->GetTime() || !IsAlive(m_enemyAPI) || m_team == GetTeam(m_enemyAPI) || IsNotAttackLab(m_enemyAPI)) + { + m_enemyAPI = null; + m_blockCheckEnemyTime = engine->GetTime(); + } + } + else + m_blockCheckEnemyTime = engine->GetTime(); + + if (!FNullEnt(m_enemy)) + { + if ((!FNullEnt(m_enemyAPI) && m_enemyAPI != m_enemy) || m_team == GetTeam(m_enemy) || IsNotAttackLab(m_enemy) || !IsAlive(m_enemy)) + { + SetEnemy(null); + SetLastEnemy(null); + m_enemyUpdateTime = 0.0f; + } + + if ((m_enemyUpdateTime > engine->GetTime())) + { + if (IsEnemyViewable(m_enemy, true, true) || IsShootableThruObstacle(m_enemy)) + { + m_aimFlags |= AIM_ENEMY; + return true; + } + + oneTimeCheckEntity = m_enemy; + } + + targetEntity = m_enemy; + enemy_distance = GetEntityDistance(m_enemy); + } + else if (!FNullEnt(m_moveTargetEntity)) + { + if ((!FNullEnt(m_enemyAPI) && m_enemyAPI != m_moveTargetEntity) || m_team == GetTeam(m_moveTargetEntity) || !IsAlive(m_moveTargetEntity) || GetEntityOrigin(m_moveTargetEntity) == nullvec) + SetMoveTarget(null); + + targetEntity = m_moveTargetEntity; + enemy_distance = GetEntityDistance(m_moveTargetEntity); + } + + if (!FNullEnt(m_enemyAPI)) + { + enemy_distance = GetEntityDistance(m_enemyAPI); + targetEntity = m_enemyAPI; + + if (!IsEnemyViewable(targetEntity, true, true)) + { + g_botsCanPause = false; + + SetMoveTarget(targetEntity); + return false; + } + + oneTimeCheckEntity = targetEntity; + } + else + { + int allEnemy = 0; + for (i = 0; i < checkEnemyNum; i++) + { + m_allEnemyId[i] = -1; + m_allEnemyDistance[i] = 9999.9f; + + m_enemyEntityId[i] = -1; + m_enemyEntityDistance[i] = 9999.9f; + } + + for (i = 0; i < engine->GetMaxClients(); i++) + { + entity = INDEXENT(i + 1); + + if (!IsAlive(entity) || GetTeam(entity) == m_team || GetEntity() == entity) + continue; + + m_allEnemyId[allEnemy] = i + 1; + m_allEnemyDistance[allEnemy] = GetEntityDistance(entity); + allEnemy++; + } + + for (i = 0; i < entityNum; i++) + { + if (g_entityId[i] == -1 || g_entityAction[i] != 1) + continue; + + if (m_team == g_entityTeam[i]) + continue; + + entity = INDEXENT(g_entityId[i]); + if (FNullEnt(entity) || !IsAlive(entity)) + continue; + + if (entity->v.effects & EF_NODRAW || entity->v.takedamage == DAMAGE_NO) + continue; + + m_allEnemyId[allEnemy] = g_entityId[i]; + m_allEnemyDistance[allEnemy] = GetEntityDistance(entity); + allEnemy++; + } + + for (i = 0; i < allEnemy; i++) + { + for (int y = 0; y < checkEnemyNum; y++) + { + if (m_allEnemyDistance[i] > m_enemyEntityDistance[y]) + continue; + + for (int z = allEnemy - 1; z >= y; z--) + { + if (z == allEnemy - 1 || m_enemyEntityId[z] == -1) + continue; + + m_enemyEntityId[z + 1] = m_enemyEntityId[z]; + m_enemyEntityDistance[z + 1] = m_enemyEntityDistance[z]; + } + + m_enemyEntityId[y] = m_allEnemyId[i]; + m_enemyEntityDistance[y] = m_allEnemyDistance[i]; + + break; + } + } + + bool allCheck = false; + if ((m_isZombieBot || (m_currentWaypointIndex == WEAPON_KNIFE && targetEntity == m_moveTargetEntity)) && FNullEnt(m_enemy) && !FNullEnt(m_moveTargetEntity)) + { + if (!IsEnemyViewable(m_moveTargetEntity, false, true, true)) + allCheck = true; + } + + for (i = 0; i < checkEnemyNum; i++) + { + if (m_enemyEntityId[i] == -1) + continue; + + entity = INDEXENT(m_enemyEntityId[i]); + if (entity == oneTimeCheckEntity) + continue; + + if (m_blindRecognizeTime < engine->GetTime() && IsBehindSmokeClouds(entity)) + m_blindRecognizeTime = engine->GetTime() + engine->RandomFloat(2.0f, 3.0f); + + if (m_blindRecognizeTime >= engine->GetTime()) + continue; + + if (IsValidPlayer(entity) && IsEnemyProtectedByShield(entity)) + continue; + + if (IsEnemyViewable(entity, true, allCheck, true)) + { + enemy_distance = m_enemyEntityDistance[i]; + targetEntity = entity; + oneTimeCheckEntity = entity; + + break; + } + } + } + + if (!FNullEnt(m_moveTargetEntity) && m_moveTargetEntity != targetEntity) + { + if (m_currentWaypointIndex != GetEntityWaypoint(targetEntity)) + { + float distance = GetEntityDistance(m_moveTargetEntity); + if (distance <= enemy_distance + 400.0f) + { + int targetWpIndex = GetEntityWaypoint(targetEntity); + bool shortDistance = false; + + Path* path = g_waypoint->GetPath(m_currentWaypointIndex); + for (int j = 0; j < Const_MaxPathIndex; j++) + { + if (path->index[j] != targetWpIndex) + continue; + + if (path->connectionFlags[j] & PATHFLAG_JUMP) + break; + + shortDistance = true; + } + + if (shortDistance == false) + { + enemy_distance = distance; + targetEntity = null; + } + } + } + } + + if (!FNullEnt(targetEntity)) // Last Checking + { + enemy_distance = GetEntityDistance(targetEntity); + if (oneTimeCheckEntity != targetEntity && !IsEnemyViewable(targetEntity, true, true)) + targetEntity = null; + } + + if (!FNullEnt(m_enemy) && FNullEnt(targetEntity)) + { + if (m_isZombieBot || (m_currentWaypointIndex == WEAPON_KNIFE && targetEntity == m_moveTargetEntity)) + { + g_botsCanPause = false; + + SetMoveTarget(m_enemy); + return false; + } + else if (IsShootableThruObstacle(m_enemy)) + { + m_enemyOrigin = GetEntityOrigin(m_enemy); + m_visibility = VISIBILITY_BODY; + return true; + } + } + + if (!FNullEnt(targetEntity)) + { + if (m_isZombieBot || m_currentWeapon == WEAPON_KNIFE) + { + bool moveTotarget = true; + int movePoint = 0; + int srcIndex = GetEntityWaypoint(GetEntity()); + int destIndex = GetEntityWaypoint(targetEntity); + if ((m_currentTravelFlags & PATHFLAG_JUMP)) + movePoint = 10; + else if (srcIndex == destIndex || m_currentWaypointIndex == destIndex) + moveTotarget = false; + else + { + Path* path; + while (srcIndex != destIndex && movePoint <= 3 && srcIndex >= 0 && destIndex >= 0) + { + path = g_waypoint->GetPath(srcIndex); + srcIndex = *(g_waypoint->m_pathMatrix + (srcIndex * g_numWaypoints) + destIndex); + if (srcIndex < 0) + continue; + + movePoint++; + for (int j = 0; j < Const_MaxPathIndex; j++) + { + if (path->index[j] == srcIndex && + path->connectionFlags[j] & PATHFLAG_JUMP) + { + movePoint += 3; + break; + } + } + } + } + + enemy_distance = (GetEntityOrigin(targetEntity) - pev->origin).GetLength(); + if ((enemy_distance <= 150.0f && movePoint <= 1) || + (targetEntity == m_moveTargetEntity && movePoint <= 2)) + { + moveTotarget = false; + if (targetEntity == m_moveTargetEntity && movePoint <= 1) + m_enemyUpdateTime = engine->GetTime() + 4.0f; + } + + if (moveTotarget) + { + if (IsOnAttackDistance(targetEntity, 80.0f)) + KnifeAttack(); + + if (targetEntity != m_moveTargetEntity) + { + g_botsCanPause = false; + + m_targetEntity = null; + SetMoveTarget(targetEntity); + } + + return false; + } + + if (m_enemyUpdateTime < engine->GetTime() + 3.0f) + m_enemyUpdateTime = engine->GetTime() + 2.5f; + } + + g_botsCanPause = true; + m_aimFlags |= AIM_ENEMY; + + if (targetEntity == m_enemy) + { + m_seeEnemyTime = engine->GetTime(); + + m_actualReactionTime = 0.0f; + SetLastEnemy(targetEntity); + + return true; + } + + if (m_seeEnemyTime + 3.0f < engine->GetTime() && (pev->weapons & (1 << WEAPON_C4) || HasHostage() || !FNullEnt(m_targetEntity))) + RadioMessage(Radio_EnemySpotted); + + m_targetEntity = null; + + if (ChanceOf(m_skill)) + m_enemySurpriseTime = engine->GetTime() + (m_actualReactionTime / 3); + else + m_enemySurpriseTime = engine->GetTime() + m_actualReactionTime; + + m_actualReactionTime = 0.0f; + + SetEnemy(targetEntity); + SetLastEnemy(m_enemy); + m_seeEnemyTime = engine->GetTime(); + + if (!m_isZombieBot) + m_enemyUpdateTime = engine->GetTime() + 1.0f; + + return true; + } + + if ((m_aimFlags <= AIM_PREDICTENEMY && m_seeEnemyTime + 4.0f < engine->GetTime() && !(m_states & (STATE_SEEINGENEMY | STATE_HEARENEMY)) && FNullEnt(m_lastEnemy) && FNullEnt(m_enemy) && GetCurrentTask()->taskID != TASK_DESTROYBREAKABLE && GetCurrentTask()->taskID != TASK_PLANTBOMB && GetCurrentTask()->taskID != TASK_DEFUSEBOMB) || g_roundEnded) + { + if (!m_reloadState) + m_reloadState = RSTATE_PRIMARY; + } + + if ((UsesSniper() || UsesZoomableRifle()) && m_zoomCheckTime + 1.0f < engine->GetTime()) + { + if (pev->fov < 90) + pev->button |= IN_ATTACK2; + else + m_zoomCheckTime = 0.0f; + } + + return false; +} + +Vector Bot::GetAimPosition(void) +{ + Vector enemyOrigin = GetEntityOrigin(m_enemy); + if (enemyOrigin == nullvec) + return m_enemyOrigin = m_lastEnemyOrigin; + + if (!(m_states & STATE_SEEINGENEMY)) + { + if (!IsValidPlayer(m_enemy)) + return m_enemyOrigin = enemyOrigin; + + enemyOrigin.x += engine->RandomFloat(m_enemy->v.mins.x, m_enemy->v.maxs.x); + enemyOrigin.y += engine->RandomFloat(m_enemy->v.mins.y, m_enemy->v.maxs.y); + enemyOrigin.z += engine->RandomFloat(m_enemy->v.mins.z, m_enemy->v.maxs.z); + + return m_enemyOrigin = enemyOrigin; + } + + if (!IsValidPlayer(m_enemy)) + return m_enemyOrigin = m_lastEnemyOrigin = enemyOrigin; + + if ((m_visibility & (VISIBILITY_HEAD | VISIBILITY_BODY))) + { + if (GetGameMod() == MODE_ZP || ((m_skill >= 80 || !ChanceOf(m_skill)) && (m_currentWeapon != WEAPON_AWP || m_enemy->v.health >= 100))) + enemyOrigin = GetPlayerHeadOrigin(m_enemy); + } + else if (m_visibility & VISIBILITY_HEAD) + enemyOrigin = GetPlayerHeadOrigin(m_enemy); + else if (m_visibility & VISIBILITY_OTHER) + enemyOrigin = m_enemyOrigin; + else + enemyOrigin = m_lastEnemyOrigin; + + if ((GetGameMod() == MODE_BASE || IsDeathmatchMode()) && m_skill <= engine->RandomInt(30, 60)) + { + enemyOrigin.x += engine->RandomFloat(m_enemy->v.mins.x, m_enemy->v.maxs.x); + enemyOrigin.y += engine->RandomFloat(m_enemy->v.mins.y, m_enemy->v.maxs.y); + enemyOrigin.z += engine->RandomFloat(m_enemy->v.mins.z, m_enemy->v.maxs.z); + } + + return m_enemyOrigin = m_lastEnemyOrigin = enemyOrigin; +} + +// bot can't hurt teammates, if friendly fire is not enabled... +bool Bot::IsFriendInLineOfFire(float distance) +{ + if (!engine->IsFriendlyFireOn() || GetGameMod() == MODE_DM) + return false; + + MakeVectors(pev->v_angle); + + TraceResult tr; + TraceLine(EyePosition(), EyePosition() + pev->v_angle.Normalize() * distance, false, false, GetEntity(), &tr); + + int i; + if (!FNullEnt(tr.pHit)) + { + if (IsAlive(tr.pHit) && m_team == GetTeam(tr.pHit)) + { + if (IsValidPlayer(tr.pHit)) + return true; + + int entityIndex = ENTINDEX(tr.pHit); + for (i = 0; i < entityNum; i++) + { + if (g_entityId[i] == -1 || g_entityAction[i] != 1) + continue; + + if (g_entityId[i] == entityIndex) + return true; + } + } + } + + edict_t* entity = null; + for (i = 0; i < engine->GetMaxClients(); i++) + { + entity = INDEXENT(i + 1); + + if (FNullEnt(entity) || !IsAlive(entity) || GetTeam(entity) != m_team || GetEntity() == entity) + continue; + + float friendDistance = (GetEntityOrigin(entity) - pev->origin).GetLength(); + float squareDistance = Q_rsqrt(1089.0f + (friendDistance * friendDistance)); + + if (friendDistance <= distance) + { + Vector entOrigin = GetEntityOrigin(entity); + if (GetShootingConeDeviation(GetEntity(), &entOrigin) > + ((friendDistance * friendDistance) / (squareDistance * squareDistance))) + return true; + } + } + + return false; +} + +int CorrectGun(int weaponID) +{ + if (GetGameMod() != MODE_BASE) + return 0; + + if (weaponID == WEAPON_AUG || weaponID == WEAPON_M4A1 || weaponID == WEAPON_SG552 || weaponID == WEAPON_AK47 || weaponID == WEAPON_FAMAS || weaponID == WEAPON_GALIL) + return 2; + else if (weaponID == WEAPON_SG552 || weaponID == WEAPON_G3SG1) + return 3; + + return 0; +} + +bool Bot::IsShootableThruObstacle(edict_t* entity) +{ + if (FNullEnt(entity) || !IsValidPlayer(entity) || IsZombieEntity(entity)) + return false; + + if (entity->v.health >= 60.0f) + return false; + + int currentWeaponPenetrationPower = CorrectGun(m_currentWeapon); + if (currentWeaponPenetrationPower == 0) + return false; + + TraceResult tr; + Vector dest = GetEntityOrigin(entity); + + float obstacleDistance = 0.0f; + + TraceLine(EyePosition(), dest, true, GetEntity(), &tr); + + if (tr.fStartSolid) + { + Vector source = tr.vecEndPos; + + TraceLine(dest, source, true, GetEntity(), &tr); + if (tr.flFraction != 1.0f) + { + if ((tr.vecEndPos - dest).GetLength() > 800.0f) + return false; + + if (tr.vecEndPos.z >= dest.z + 200.0f) + return false; + + if (dest.z >= tr.vecEndPos.z + 200.0f) + return false; + + obstacleDistance = (tr.vecEndPos - source).GetLength(); + } + } + + if (obstacleDistance > 0.0) + { + while (currentWeaponPenetrationPower > 0) + { + if (obstacleDistance > 75.0) + { + obstacleDistance -= 75.0f; + currentWeaponPenetrationPower--; + continue; + } + + return true; + } + } + + return false; +} + +bool Bot::DoFirePause(float distance)//, FireDelay *fireDelay) +{ + if (m_firePause > engine->GetTime()) + return true; + + if ((m_aimFlags & AIM_ENEMY) && m_enemyOrigin != nullvec) + { + if (IsEnemyProtectedByShield(m_enemy) && GetShootingConeDeviation(GetEntity(), &m_enemyOrigin) > 0.92f) + return true; + } + + float angle = (fabsf(pev->punchangle.y) + fabsf(pev->punchangle.x)) * Math::MATH_PI / 360.0f; + + // check if we need to compensate recoil + if (tanf(angle) * (distance + (distance / 4)) > g_skillTab[m_skill / 20].recoilAmount) + { + if (m_firePause < (engine->GetTime() - 0.4)) + m_firePause = engine->GetTime() + engine->RandomFloat(0.4f, 0.4f + 1.2f * ((100 - m_skill) / 100.0f)); + + return true; + } + + if (UsesSniper()) + { + if (!(m_currentTravelFlags & PATHFLAG_JUMP)) + pev->button &= ~IN_JUMP; + + m_moveSpeed = 0.0f; + m_strafeSpeed = 0.0f; + + if (pev->speed >= pev->maxspeed && GetGameMod() != MODE_ZP) + { + m_firePause = engine->GetTime() + 0.1f; + return true; + } + } + + return false; +} + + +void Bot::FireWeapon(void) +{ + // this function will return true if weapon was fired, false otherwise + float distance = (m_lookAt - EyePosition()).GetLength(); // how far away is the enemy? + + // if using grenade stop this + if (m_isUsingGrenade) + { + m_shootTime = engine->GetTime() + 0.2f; + return; + } + + // or if friend in line of fire, stop this too but do not update shoot time + if (!FNullEnt(m_enemy) && IsFriendInLineOfFire(distance)) + return; + + FireDelay* delay = &g_fireDelay[0]; + WeaponSelect* selectTab = &g_weaponSelect[0]; + + edict_t* enemy = m_enemy; + + int selectId = WEAPON_KNIFE, selectIndex = 0, chosenWeaponIndex = 0; + int weapons = pev->weapons; + + + if (m_isZombieBot || ebot_knifemode.GetBool()) + goto WeaponSelectEnd; + else if (!FNullEnt(enemy) && ChanceOf(m_skill) && !IsZombieEntity(enemy) && IsOnAttackDistance(enemy, 120.0f) && + (enemy->v.health <= 30 || pev->health > enemy->v.health) && !IsOnLadder() && !IsGroupOfEnemies(pev->origin)) + goto WeaponSelectEnd; + + // loop through all the weapons until terminator is found... + while (selectTab[selectIndex].id) + { + // is the bot carrying this weapon? + if (weapons & (1 << selectTab[selectIndex].id)) + { + // is enough ammo available to fire AND check is better to use pistol in our current situation... + if ((m_ammoInClip[selectTab[selectIndex].id] > 0) && !IsWeaponBadInDistance(selectIndex, distance)) + chosenWeaponIndex = selectIndex; + } + selectIndex++; + } + selectId = selectTab[chosenWeaponIndex].id; + + // if no available weapon... + if (chosenWeaponIndex == 0) + { + selectIndex = 0; + + // loop through all the weapons until terminator is found... + while (selectTab[selectIndex].id) + { + int id = selectTab[selectIndex].id; + + // is the bot carrying this weapon? + if (weapons & (1 << id)) + { + if (g_weaponDefs[id].ammo1 != -1 && m_ammo[g_weaponDefs[id].ammo1] >= selectTab[selectIndex].minPrimaryAmmo) + { + // available ammo found, reload weapon + if (m_reloadState == RSTATE_NONE || m_reloadCheckTime > engine->GetTime() || GetCurrentTask()->taskID != TASK_ESCAPEFROMBOMB) + { + m_isReloading = true; + m_reloadState = RSTATE_PRIMARY; + m_reloadCheckTime = engine->GetTime(); + m_fearLevel = 1.0f; + + RadioMessage(Radio_NeedBackup); + } + return; + } + } + selectIndex++; + } + selectId = WEAPON_KNIFE; // no available ammo, use knife! + } + +WeaponSelectEnd: + // we want to fire weapon, don't reload now + if (!m_isReloading) + { + m_reloadState = RSTATE_NONE; + m_reloadCheckTime = engine->GetTime() + 5.0f; + } + + if (m_currentWeapon == WEAPON_KNIFE && selectId != WEAPON_KNIFE && GetGameMod() == MODE_ZP && !m_isZombieBot) + { + m_reloadState = RSTATE_PRIMARY; + m_reloadCheckTime = engine->GetTime() + 2.5f; + + return; + } + + if (m_currentWeapon != selectId) + { + SelectWeaponByName(g_weaponDefs[selectId].className); + + // reset burst fire variables + m_firePause = 0.0f; + m_timeLastFired = 0.0f; + + return; + } + + if (delay[chosenWeaponIndex].weaponIndex != selectId) + return; + + if (selectTab[chosenWeaponIndex].id != selectId) + { + chosenWeaponIndex = 0; + + // loop through all the weapons until terminator is found... + while (selectTab[chosenWeaponIndex].id) + { + if (selectTab[chosenWeaponIndex].id == selectId) + break; + + chosenWeaponIndex++; + } + } + + // if we're have a glock or famas vary burst fire mode + CheckBurstMode(distance); + + if (HasShield() && m_shieldCheckTime < engine->GetTime() && GetCurrentTask()->taskID != TASK_CAMP) // better shield gun usage + { + if ((distance > 750.0f) && !IsShieldDrawn()) + pev->button |= IN_ATTACK2; // draw the shield + else if (IsShieldDrawn() || (!FNullEnt(enemy) && (enemy->v.button & IN_RELOAD))) + pev->button |= IN_ATTACK2; // draw out the shield + + m_shieldCheckTime = engine->GetTime() + 2.0f; + } + + if (UsesSniper() && m_zoomCheckTime < engine->GetTime()) // is the bot holding a sniper rifle? + { + if (distance > 1500.0f && pev->fov >= 40.0f) // should the bot switch to the long-range zoom? + pev->button |= IN_ATTACK2; + + else if (distance > 150.0f && pev->fov >= 90.0f) // else should the bot switch to the close-range zoom ? + pev->button |= IN_ATTACK2; + + else if (distance <= 150.0f && pev->fov < 90.0f) // else should the bot restore the normal view ? + pev->button |= IN_ATTACK2; + + m_zoomCheckTime = engine->GetTime(); + } + else if (UsesZoomableRifle() && m_zoomCheckTime < engine->GetTime() && m_skill < 90) // else is the bot holding a zoomable rifle? + { + if (distance > 800.0f && pev->fov >= 90.0f) // should the bot switch to zoomed mode? + pev->button |= IN_ATTACK2; + + else if (distance <= 800.0f && pev->fov < 90.0f) // else should the bot restore the normal view? + pev->button |= IN_ATTACK2; + + m_zoomCheckTime = engine->GetTime(); + } + + // need to care for burst fire? + if (distance < 256.0f || m_blindTime > engine->GetTime()) + { + if (selectId == WEAPON_KNIFE) + KnifeAttack(); + else + { + if (selectTab[chosenWeaponIndex].primaryFireHold) // if automatic weapon, just press attack + pev->button |= IN_ATTACK; + else // if not, toggle buttons + { + if ((pev->oldbuttons & IN_ATTACK) == 0) + pev->button |= IN_ATTACK; + } + } + + if (pev->button & IN_ATTACK) + m_shootTime = engine->GetTime(); + } + else + { + const float baseDelay = delay[chosenWeaponIndex].primaryBaseDelay; + const float minDelay = delay[chosenWeaponIndex].primaryMinDelay[abs((m_skill / 20) - 5)]; + const float maxDelay = delay[chosenWeaponIndex].primaryMaxDelay[abs((m_skill / 20) - 5)]; + + if (DoFirePause(distance))//, &delay[chosenWeaponIndex])) + return; + + // don't attack with knife over long distance + if (selectId == WEAPON_KNIFE) + { + KnifeAttack(); + return; + } + + float delayTime = 0.0f; + if (selectTab[chosenWeaponIndex].primaryFireHold) + { + m_zoomCheckTime = engine->GetTime(); + pev->button |= IN_ATTACK; // use primary attack + } + else + { + pev->button |= IN_ATTACK; // use primary attack + delayTime = baseDelay + engine->RandomFloat(minDelay, maxDelay); + m_zoomCheckTime = engine->GetTime(); + } + + if (!FNullEnt(enemy) && distance >= 1200.0f) + { + if (m_visibility & (VISIBILITY_HEAD | VISIBILITY_BODY)) + delayTime -= (delayTime == 0.0f) ? 0.0f : 0.02f; + else if (m_visibility & VISIBILITY_HEAD) + { + if (distance >= 2400.0f) + delayTime += (delayTime == 0.0f) ? 0.15f : 0.10f; + else + delayTime += (delayTime == 0.0f) ? 0.10f : 0.05f; + } + else if (m_visibility & VISIBILITY_BODY) + { + if (distance >= 2400.f) + delayTime += (delayTime == 0.0f) ? 0.12f : 0.08f; + else + delayTime += (delayTime == 0.0f) ? 0.08f : 0.0f; + } + else + { + if (distance >= 2400.0f) + delayTime += (delayTime == 0.0f) ? 0.18f : 0.15f; + else + delayTime += (delayTime == 0.0f) ? 0.15f : 0.10f; + } + } + m_shootTime = engine->GetTime() + delayTime; + } +} + +bool Bot::KnifeAttack(float attackDistance) +{ + edict_t* entity = null; + float distance = 9999.0f; + if (!FNullEnt(m_enemy)) + { + entity = m_enemy; + distance = (pev->origin - GetEntityOrigin(m_enemy)).GetLength(); + } + + if (!FNullEnt(m_breakableEntity)) + { + if (m_breakable == nullvec) + m_breakable = GetEntityOrigin(m_breakableEntity); + + if ((pev->origin - m_breakable).GetLength() < distance) + { + entity = m_breakableEntity; + distance = (pev->origin - m_breakable).GetLength(); + } + } + + if (FNullEnt(entity)) + return false; + + float kad1 = (m_knifeDistance1API <= 0) ? 64.0f : m_knifeDistance1API;; // Knife Attack Distance (API) + float kad2 = (m_knifeDistance2API <= 0) ? 64.0f : m_knifeDistance2API; + + if (attackDistance != 0.0f) + kad1 = attackDistance; + + int kaMode = 0; + if (IsOnAttackDistance(entity, kad1)) + kaMode = 1; + if (IsOnAttackDistance(entity, kad2)) + kaMode += 2; + + if (kaMode > 0) + { + float distanceSkipZ = (pev->origin - GetEntityOrigin(entity)).GetLength2D(); + + if (pev->origin.z > GetEntityOrigin(entity).z && distanceSkipZ < 64.0f) + { + pev->button |= IN_DUCK; + m_campButtons |= IN_DUCK; + pev->button &= ~IN_JUMP; + } + else + { + pev->button &= ~IN_DUCK; + m_campButtons &= ~IN_DUCK; + + if (pev->origin.z + 150.0f < GetEntityOrigin(entity).z && distanceSkipZ < 300.0f) + pev->button |= IN_JUMP; + } + + if (m_isZombieBot) + { + if (kaMode != 2) + pev->button |= IN_ATTACK; + else + pev->button |= IN_ATTACK2; + } + else + { + if (kaMode == 1) + pev->button |= IN_ATTACK; + else if (kaMode == 2) + pev->button |= IN_ATTACK2; + else if (engine->RandomInt(1, 10) < 3 || HasShield()) + pev->button |= IN_ATTACK; + else + pev->button |= IN_ATTACK2; + } + + return true; + } + + return false; +} + +bool Bot::IsWeaponBadInDistance(int weaponIndex, float distance) +{ + // this function checks, is it better to use pistol instead of current primary weapon + // to attack our enemy, since current weapon is not very good in this situation. + + int weaponID = g_weaponSelect[weaponIndex].id; + + if (weaponID == WEAPON_KNIFE) + return false; + + // check is ammo available for secondary weapon + if (m_ammoInClip[g_weaponSelect[GetBestSecondaryWeaponCarried()].id] >= 1) + return false; + + if (m_gunMinDistanceAPI > 0 || m_gunMaxDistanceAPI > 0) + { + if (m_gunMinDistanceAPI > 0 && m_gunMaxDistanceAPI > 0) + { + if (distance < m_gunMinDistanceAPI || distance > m_gunMaxDistanceAPI) + return true; + } + else if (m_gunMinDistanceAPI > 0) + { + if (distance < m_gunMinDistanceAPI) + return true; + } + else if (m_gunMaxDistanceAPI > 0) + { + if (distance > m_gunMaxDistanceAPI) + return true; + } + return false; + } + + // shotguns is too inaccurate at long distances, so weapon is bad + if ((weaponID == WEAPON_M3 || weaponID == WEAPON_XM1014) && distance > 750.0f) + return true; + + if (GetGameMod() == MODE_BASE) + { + if ((weaponID == WEAPON_SCOUT || weaponID == WEAPON_AWP || weaponID == WEAPON_G3SG1 || weaponID == WEAPON_SG550) && distance < 300.0f) + return true; + } + + return false; +} + +void Bot::FocusEnemy(void) +{ + // aim for the head and/or body + m_lookAt = GetAimPosition(); + + if (m_enemySurpriseTime > engine->GetTime()) + return; + + float distance = (m_lookAt - EyePosition()).GetLength2D(); // how far away is the enemy scum? + + if (distance < 128) + { + if (m_currentWeapon == WEAPON_KNIFE) + { + if (IsOnAttackDistance(m_enemy, (m_knifeDistance1API <= 0) ? 64.0f : m_knifeDistance1API)) + m_wantsToFire = true; + } + else + m_wantsToFire = true; + } + else + { + if (m_currentWeapon == WEAPON_KNIFE) + m_wantsToFire = true; + else + { + float dot = GetShootingConeDeviation(GetEntity(), &m_enemyOrigin); + + if (dot < 0.90f) + m_wantsToFire = false; + else + { + float enemyDot = GetShootingConeDeviation(m_enemy, &pev->origin); + + // enemy faces bot? + if (enemyDot >= 0.90f) + m_wantsToFire = true; + else + { + if (dot > 0.99f) + m_wantsToFire = true; + else + m_wantsToFire = false; + } + } + } + } +} + +void Bot::CombatFight(void) +{ + // our enemy can change teams in fun modes + if (!FNullEnt(m_enemy) && m_team == GetTeam(m_enemy)) + SetEnemy(null); + + // our last enemy can change teams in fun modes + if (!FNullEnt(m_lastEnemy) && m_team == GetTeam(m_lastEnemy)) + SetLastEnemy(m_enemy); + + if ((m_moveSpeed != 0.0f || m_strafeSpeed != 0.0f) && IsValidWaypoint(m_currentWaypointIndex) && g_waypoint->GetPath(m_currentWaypointIndex)->flags & WAYPOINT_CROUCH && (pev->velocity.GetLength() < 2.0f)) + pev->button |= IN_DUCK; + + if (m_isZombieBot) // zombie ai + { + DeleteSearchNodes(); + m_moveToGoal = false; + m_destOrigin = GetEntityOrigin(m_enemy); + m_moveSpeed = pev->maxspeed; + if (m_isSlowThink && pev->speed >= pev->maxspeed) + { + if (engine->RandomInt(1, 2) == 1) + pev->button |= IN_JUMP; + else + pev->button |= IN_DUCK; + } + + const float targetdist = 128.0f; + if ((pev->origin - m_destOrigin).GetLength() <= targetdist) + pev->button |= IN_ATTACK; + + return; + } + else if (IsZombieMode()) // human ai + { + m_timeWaypointMove = 0.0f; + + if (m_timeWaypointMove + m_frameInterval < engine->GetTime()) + { + const Vector enemyOrigin = GetEntityOrigin(m_enemy); + + const bool NPCEnemy = !IsValidPlayer(m_enemy); + const bool enemyIsZombie = IsZombieEntity(m_enemy); + float baseDistance = (fabsf(m_enemy->v.speed) + 400.0f); + + if (NPCEnemy || enemyIsZombie) + { + if (m_currentWeapon == WEAPON_KNIFE) + { + if (::IsInViewCone(pev->origin, m_enemy) && !NPCEnemy) + baseDistance = (fabsf(m_enemy->v.speed) + 400.0f); + else + baseDistance = -1.0f; + } + + const float distance = (pev->origin - enemyOrigin).GetLength(); + if (m_isSlowThink && distance <= 1024.0f && !FNullEnt(m_lastEnemy) && m_lastEnemyOrigin != nullvec && engine->RandomInt(1, 1000) <= ebot_zp_use_grenade_percent.GetInt()) + { + if (engine->RandomInt(1, 2) == 1) + ThrowFrostNade(); + else + ThrowFireNade(); + } + + float lastEnemyDistance = 0.0f; + float baseDistanceLastEnemy = -1.0f; + Vector lastEnemyOrigin = nullvec; + if (!FNullEnt(m_lastEnemy) && m_enemy != m_lastEnemy) { lastEnemyDistance = (pev->origin - GetEntityOrigin(m_lastEnemy)).GetLength(); baseDistanceLastEnemy = (fabsf(m_lastEnemy->v.speed) + 400.0f); lastEnemyOrigin = GetEntityOrigin(m_lastEnemy); - } - - if (baseDistance != -1.0f) - { - // better human escape ai - if (ebot_escape.GetInt() == 0 && (distance <= baseDistance || lastEnemyDistance <= baseDistanceLastEnemy)) - { - if (lastEnemyDistance > 0.0f) - m_destOrigin = enemyOrigin - lastEnemyOrigin; - else - m_destOrigin = enemyOrigin; - - m_moveSpeed = -pev->maxspeed; - m_checkFall = true; - m_moveToGoal = false; - - Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval); - Vector directionNormal = directionOld.Normalize(); - directionNormal.z = 0.0f; - - SetStrafeSpeed(directionNormal, pev->maxspeed); - - return; - } - else if (ebot_escape.GetInt() == 0 && distance <= (baseDistance + (baseDistance / 10))) - { - m_checkFall = true; - m_moveToGoal = false; + } + + if (baseDistance != -1.0f) + { + // better human escape ai + if (ebot_escape.GetInt() == 0 && (distance <= baseDistance || lastEnemyDistance <= baseDistanceLastEnemy)) + { + if (lastEnemyDistance > 0.0f) + m_destOrigin = enemyOrigin - lastEnemyOrigin; + else + m_destOrigin = enemyOrigin; + + m_moveSpeed = -pev->maxspeed; + m_checkFall = true; + m_moveToGoal = false; + + Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval); + Vector directionNormal = directionOld.Normalize(); + directionNormal.z = 0.0f; + + SetStrafeSpeed(directionNormal, pev->maxspeed); + + return; + } + else if (ebot_escape.GetInt() == 0 && distance <= (baseDistance + (baseDistance / 10))) + { + m_checkFall = true; + m_moveToGoal = false; if (lastEnemyDistance <= baseDistanceLastEnemy) - { - m_destOrigin = lastEnemyOrigin; - m_moveSpeed = -pev->maxspeed; - m_checkFall = true; - m_moveToGoal = false; - - Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval); - Vector directionNormal = directionOld.Normalize(); - directionNormal.z = 0.0f; - - SetStrafeSpeed(directionNormal, pev->maxspeed); - - return; - } - else - m_moveSpeed = 0.0f; - } - else - { - m_moveToGoal = true; - m_moveSpeed = pev->maxspeed; - } - } - else - { - m_moveToGoal = true; - m_moveSpeed = pev->maxspeed; - } - } - } - - return; - } - else if (!IsZombieMode() && GetCurrentTask()->taskID != TASK_CAMP && GetCurrentTask()->taskID != TASK_SEEKCOVER && GetCurrentTask()->taskID != TASK_ESCAPEFROMBOMB) - { - /*if (m_skill >= 50) - { - // 1 tick delay every 1 seconds. - if (m_isSlowThink) - return; - - // higher skill bots have a better movement - if (!ChanceOf(m_skill)) - return; - - float input[3] = {0, 0, 0}; - - input[0] = (pev->velocity.x * pev->health) - (m_enemy->v.velocity.x * m_enemy->v.health); - input[0] /= 1000; // 1 = forward | 2 = back - input[1] = (pev->velocity.y * m_enemy->v.speed) - (m_enemy->v.velocity.y * pev->speed); - input[1] /= 1000; // 1 = right | 2 = left - //input[2] = pev->velocity.z - m_enemy->v.velocity.z; - //input[2] /= 1000; // 1 = jump | 2 = crouch - - int i = GetIndex(); - - if (brain[i]->l[brain[i]->layers - 1].n[0].output < 0.01f || brain[i]->l[brain[i]->layers - 1].n[0].output > 1.99f) - m_moveSpeed = 0.0f; - else if (brain[i]->l[brain[i]->layers - 1].n[0].output <= 1.0f) - m_moveSpeed = -pev->maxspeed; - else if (brain[i]->l[brain[i]->layers - 1].n[0].output <= 2.0f) - m_moveSpeed = pev->maxspeed; - - if (brain[i]->l[brain[i]->layers - 1].n[1].output < 0.2f || brain[i]->l[brain[i]->layers - 1].n[1].output > 1.8f) - m_strafeSpeed = 0.0f; - else if (brain[i]->l[brain[i]->layers - 1].n[1].output <= 1.0f) - m_strafeSpeed = -pev->maxspeed; - else if (brain[i]->l[brain[i]->layers - 1].n[1].output <= 2.0f) - m_strafeSpeed = pev->maxspeed; - - IgnoreCollisionShortly(); - - return; - }*/ - - // little trick for bots - if (m_isReloading && (m_skill > 40 || ChanceOf(5))) - { - const Vector& src = pev->origin - Vector(0, 0, 18.0f); - - extern ConVar ebot_think_fps; - if ((m_visibility & (VISIBILITY_HEAD | VISIBILITY_BODY)) && m_enemy->v.weapons != WEAPON_KNIFE && !IsVisible(src, m_enemy)) - m_duckTime = engine->GetTime() + (engine->RandomFloat(0.9f, 1.1f) / ebot_think_fps.GetFloat()) + 1.0f; - } - - if (m_isSlowThink && (m_isReloading || ((m_isLeader || m_isVIP || m_isBomber) && pev->health <= (pev->max_health / 2)) || m_isUsingGrenade || (m_personality != PERSONALITY_RUSHER && ::IsInViewCone(pev->origin, m_enemy) && (pev->health + m_agressionLevel) < m_enemy->v.health + (m_personality == PERSONALITY_CAREFUL ? 15.0f : 30.0f)))) - { - int seekindex = FindCoverWaypoint(9999.0f); - - if (IsValidWaypoint(seekindex)) - PushTask(TASK_SEEKCOVER, TASKPRI_SEEKCOVER, seekindex, 1.0f, true); - - return; - } - - DeleteSearchNodes(); - SetLastEnemy(m_enemy); - m_destOrigin = GetEntityOrigin(m_enemy); - - float distance = (pev->origin - m_lookAt).GetLength(); // how far away is the enemy scum? - - if (m_currentWeapon != WEAPON_KNIFE && distance <= 256.0f) // get back! - { - m_moveSpeed = -pev->maxspeed; - return; - } - - m_timeWaypointMove = 0.0f; - - if (m_timeWaypointMove < engine->GetTime()) - { - int approach; - - if (m_currentWeapon == WEAPON_KNIFE) // knife? - approach = 100; - else if (!(m_states & STATE_SEEINGENEMY)) // if suspecting enemy stand still - approach = 49; - else if (m_isReloading || m_isVIP) // if reloading or vip back off - approach = 29; - else - { - approach = static_cast (pev->health * m_agressionLevel); - - if (UsesSniper() && approach > 49) - approach = 49; - } - - // only take cover when bomb is not planted and enemy can see the bot or the bot is VIP - if (approach < 30 && !g_bombPlanted && (::IsInViewCone(GetEntityOrigin(m_enemy), GetEntity()) || m_isVIP)) - { - m_moveSpeed = -pev->maxspeed; - - GetCurrentTask()->taskID = TASK_FIGHTENEMY; - GetCurrentTask()->canContinue = true; - GetCurrentTask()->desire = TASKPRI_FIGHTENEMY + 1.0f; - } - else if (!(::IsInViewCone(pev->origin, m_enemy)) && m_currentWeapon != WEAPON_KNIFE) // if enemy cant see us, we never move - m_moveSpeed = 0.0f; - else if (approach >= 50 || UsesBadPrimary() || IsBehindSmokeClouds(m_enemy)) // we lost him? - m_moveSpeed = pev->maxspeed; - else - m_moveSpeed = pev->maxspeed; - - if (UsesSniper()) - { - m_fightStyle = 1; - m_lastFightStyleCheck = engine->GetTime(); - } - else if (UsesRifle() || UsesSubmachineGun()) - { - if (m_lastFightStyleCheck + 0.5f < engine->GetTime()) - { - if (ChanceOf(75)) - { - if (distance < 768.0f) - m_fightStyle = 0; - else if (distance < 1024.0f) - { - if (ChanceOf(UsesSubmachineGun() ? 50 : 30)) - m_fightStyle = 0; - else - m_fightStyle = 1; - } - else - { - if (ChanceOf(UsesSubmachineGun() ? 80 : 93)) - m_fightStyle = 1; - else - m_fightStyle = 0; - } - } - - m_lastFightStyleCheck = engine->GetTime(); - } - } - else - { - if (m_lastFightStyleCheck + 0.5f < engine->GetTime()) - { - if (ChanceOf(75)) - { - if (ChanceOf(50)) - m_fightStyle = 0; - else - m_fightStyle = 1; - } - - m_lastFightStyleCheck = engine->GetTime(); - } - } - - if (m_fightStyle == 0 || ((pev->button & IN_RELOAD) || m_isReloading) || (UsesPistol() && distance < 768.0f) || m_currentWeapon == WEAPON_KNIFE) - { - if (m_strafeSetTime < engine->GetTime()) - { - // to start strafing, we have to first figure out if the target is on the left side or right side - MakeVectors(m_enemy->v.v_angle); - - const Vector& dirToPoint = (pev->origin - m_enemy->v.origin).Normalize2D(); - const Vector& rightSide = g_pGlobals->v_right.Normalize2D(); - - if ((dirToPoint | rightSide) < 0) - m_combatStrafeDir = 1; - else - m_combatStrafeDir = 0; - - if (ChanceOf(30)) - m_combatStrafeDir = (m_combatStrafeDir == 1 ? 0 : 1); - - m_strafeSetTime = engine->GetTime() + engine->RandomFloat(0.5f, 3.0f); - } - - if (m_combatStrafeDir == 0) - { - if (!CheckWallOnLeft()) - m_strafeSpeed = -pev->maxspeed; - else - { - m_combatStrafeDir = 1; - m_strafeSetTime = engine->GetTime() + 1.5f; - } - } - else - { - if (!CheckWallOnRight()) - m_strafeSpeed = pev->maxspeed; - else - { - m_combatStrafeDir = 0; - m_strafeSetTime = engine->GetTime() + 1.5f; - } - } - - if (m_jumpTime + 10.0f < engine->GetTime() && IsOnFloor() && ChanceOf(m_isReloading ? 5 : 2) && pev->velocity.GetLength2D() > float(m_skill + 50.0f) && !UsesSniper()) - pev->button |= IN_JUMP; - - if (m_moveSpeed > 0.0f && distance > 512.0f && m_currentWeapon != WEAPON_KNIFE) - m_moveSpeed = 0.0f; - - if (m_currentWeapon == WEAPON_KNIFE) - m_strafeSpeed = 0.0f; - } - else if (m_fightStyle == 1) - { - const Vector& src = pev->origin - Vector(0, 0, 18.0f); - - extern ConVar ebot_think_fps; - if ((m_visibility & (VISIBILITY_HEAD | VISIBILITY_BODY)) && m_enemy->v.weapons != WEAPON_KNIFE && IsVisible(src, m_enemy)) - m_duckTime = engine->GetTime() + (engine->RandomFloat(0.9f, 1.1f) / ebot_think_fps.GetFloat()) + 0.2f; - - m_moveSpeed = 0.0f; - m_strafeSpeed = 0.0f; - m_navTimeset = engine->GetTime(); - } - } - - if (m_duckTime > engine->GetTime()) - { - m_moveSpeed = 0.0f; - m_strafeSpeed = 0.0f; - } - - if (m_moveSpeed > 0.0f && m_currentWeapon != WEAPON_KNIFE) - m_moveSpeed = GetWalkSpeed(); - - if (m_isReloading) - { - m_moveSpeed = -pev->maxspeed; - m_duckTime = engine->GetTime() - 2.0f; - } - - if (!IsInWater() && !IsOnLadder() && (m_moveSpeed > 0.0f || m_strafeSpeed >= 0.0f)) - { - MakeVectors(pev->v_angle); - - if (IsDeadlyDrop(pev->origin + (g_pGlobals->v_forward * m_moveSpeed * 0.2f) + (g_pGlobals->v_right * m_strafeSpeed * 0.2f) + (pev->velocity * m_frameInterval))) - { - m_strafeSpeed = -m_strafeSpeed; - m_moveSpeed = -m_moveSpeed; - - pev->button &= ~IN_JUMP; - } - } - - IgnoreCollisionShortly(); - } -} - -bool Bot::HasPrimaryWeapon(void) -{ - // this function returns returns true, if bot has a primary weapon - - return (pev->weapons & WeaponBits_Primary) != 0; -} - -bool Bot::HasShield(void) -{ - // this function returns true, if bot has a tactical shield - - return strncmp(STRING(pev->viewmodel), "models/shield/v_shield_", 23) == 0; -} - -bool Bot::IsShieldDrawn(void) -{ - // this function returns true, is the tactical shield is drawn - - if (!HasShield()) - return false; - - return pev->weaponanim == 6 || pev->weaponanim == 7; -} - -bool Bot::IsEnemyProtectedByShield(edict_t* enemy) -{ - // this function returns true, if enemy protected by the shield - - if (FNullEnt(enemy) || (HasShield() && IsShieldDrawn())) - return false; - - // check if enemy has shield and this shield is drawn - if (strncmp(STRING(enemy->v.viewmodel), "models/shield/v_shield_", 23) == 0 && (enemy->v.weaponanim == 6 || enemy->v.weaponanim == 7)) - { - if (::IsInViewCone(pev->origin, enemy)) - return true; - } - return false; -} - -bool Bot::UsesSniper(void) -{ - return m_currentWeapon == WEAPON_AWP || m_currentWeapon == WEAPON_G3SG1 || m_currentWeapon == WEAPON_SCOUT || m_currentWeapon == WEAPON_SG550; -} - -bool Bot::UsesRifle(void) -{ - WeaponSelect* selectTab = &g_weaponSelect[0]; - int count = 0; - - while (selectTab->id) - { - if (m_currentWeapon == selectTab->id) - break; - - selectTab++; - count++; - } - - if (selectTab->id && count > 13) - return true; - - return false; -} - -bool Bot::UsesPistol(void) -{ - WeaponSelect* selectTab = &g_weaponSelect[0]; - int count = 0; - - // loop through all the weapons until terminator is found - while (selectTab->id) - { - if (m_currentWeapon == selectTab->id) - break; - - selectTab++; - count++; - } - - if (selectTab->id && count < 7) - return true; - - return false; -} - -bool Bot::UsesSubmachineGun(void) -{ - return m_currentWeapon == WEAPON_MP5 || m_currentWeapon == WEAPON_TMP || m_currentWeapon == WEAPON_P90 || m_currentWeapon == WEAPON_MAC10 || m_currentWeapon == WEAPON_UMP45; -} - -bool Bot::UsesZoomableRifle(void) -{ - return m_currentWeapon == WEAPON_AUG || m_currentWeapon == WEAPON_SG552; -} - -bool Bot::UsesBadPrimary(void) -{ - return m_currentWeapon == WEAPON_M3 || m_currentWeapon == WEAPON_UMP45 || m_currentWeapon == WEAPON_MAC10 || m_currentWeapon == WEAPON_TMP || m_currentWeapon == WEAPON_P90; -} - -void Bot::ThrowFireNade(void) -{ - if (pev->weapons & (1 << WEAPON_HEGRENADE)) - PushTask(TASK_THROWHEGRENADE, TASKPRI_THROWGRENADE, -1, engine->RandomFloat(0.6f, 0.9f), false); -} - -void Bot::ThrowFrostNade(void) -{ - if (pev->weapons & (1 << WEAPON_FBGRENADE)) - PushTask(TASK_THROWFBGRENADE, TASKPRI_THROWGRENADE, -1, engine->RandomFloat(0.6f, 0.9f), false); -} - -int Bot::CheckGrenades(void) -{ - if (pev->weapons & (1 << WEAPON_HEGRENADE)) - return WEAPON_HEGRENADE; - else if (pev->weapons & (1 << WEAPON_FBGRENADE)) - return WEAPON_FBGRENADE; - else if (pev->weapons & (1 << WEAPON_SMGRENADE)) - return WEAPON_SMGRENADE; - - return -1; -} - -void Bot::SelectBestWeapon(void) -{ - if (!m_isSlowThink) - return; - - // never change weapon while reloading if theres no enemy - if (FNullEnt(m_enemy) && m_isReloading) - return; - - if (m_isZombieBot && IsZombieMode()) - { - SelectWeaponByName("weapon_knife"); - return; - } - - if (!FNullEnt(m_enemy) && (pev->origin - GetEntityOrigin(m_enemy)).GetLength() <= 128.0f) - { - SelectWeaponByName("weapon_knife"); - return; - } - - if (GetCurrentTask()->taskID == TASK_THROWHEGRENADE) - return; - - if (GetCurrentTask()->taskID == TASK_THROWFBGRENADE) - return; - - if (GetCurrentTask()->taskID == TASK_THROWSMGRENADE) - return; - - WeaponSelect* selectTab = &g_weaponSelect[0]; - - int selectIndex = 0; - int chosenWeaponIndex = 0; - - while (selectTab[selectIndex].id) - { - if (!(pev->weapons & (1 << selectTab[selectIndex].id))) - { - selectIndex++; - continue; - } - - int id = selectTab[selectIndex].id; - bool ammoLeft = false; - - if (selectTab[selectIndex].id == m_currentWeapon && (GetAmmoInClip() < 0 || GetAmmoInClip() >= selectTab[selectIndex].minPrimaryAmmo)) - ammoLeft = true; - - if (g_weaponDefs[id].ammo1 < 0 || m_ammo[g_weaponDefs[id].ammo1] >= selectTab[selectIndex].minPrimaryAmmo) - ammoLeft = true; - - if (ammoLeft) - chosenWeaponIndex = selectIndex; - - selectIndex++; - } - - chosenWeaponIndex %= Const_NumWeapons + 1; - selectIndex = chosenWeaponIndex; - - int weaponID = selectTab[selectIndex].id; - if (weaponID == m_currentWeapon) - return; - - //if (m_currentWeapon != weaponID) - SelectWeaponByName(selectTab[selectIndex].weaponName); - - m_isReloading = false; - m_reloadState = RSTATE_NONE; -} - -void Bot::SelectPistol(void) -{ - if (!m_isSlowThink) - return; - - if (m_isReloading) - return; - - int oldWeapons = pev->weapons; - - pev->weapons &= ~WeaponBits_Primary; - SelectBestWeapon(); - - pev->weapons = oldWeapons; -} - -int Bot::GetHighestWeapon(void) -{ - WeaponSelect* selectTab = &g_weaponSelect[0]; - - int weapons = pev->weapons; - int num = 0; - int i = 0; - - // loop through all the weapons until terminator is found... - while (selectTab->id) - { - // is the bot carrying this weapon? - if (weapons & (1 << selectTab->id)) - num = i; - - i++; - selectTab++; - } - - return num; -} - -void Bot::SelectWeaponByName(const char* name) -{ - FakeClientCommand(GetEntity(), name); -} - -void Bot::SelectWeaponbyNumber(int num) -{ - FakeClientCommand(GetEntity(), g_weaponSelect[num].weaponName); -} - -void Bot::CommandTeam(void) -{ - if (GetGameMod() != MODE_BASE && GetGameMod() != MODE_TDM) - return; - - // prevent spamming - if (m_timeTeamOrder > engine->GetTime()) - return; - - bool memberNear = false; - bool memberExists = false; - - // search teammates seen by this bot - for (const auto& client : g_clients) - { - if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team != m_team || client.ent == GetEntity()) - continue; - - memberExists = true; - - if (EntityIsVisible(client.origin)) - { - memberNear = true; - break; - } - } - - if (memberNear && ChanceOf(50)) // has teammates ? - { - if (m_personality == PERSONALITY_RUSHER) - RadioMessage(Radio_StormTheFront); - else if(m_personality == PERSONALITY_NORMAL) - RadioMessage(Radio_StickTogether); - else - RadioMessage(Radio_Fallback); - } - else if (memberExists) - { - if (ChanceOf(25)) - RadioMessage(Radio_NeedBackup); - else if (ChanceOf(25)) - RadioMessage(Radio_EnemySpotted); - else if (ChanceOf(25)) - RadioMessage(Radio_TakingFire); - } - - m_timeTeamOrder = engine->GetTime() + engine->RandomFloat(10.0f, 30.0f); -} - -bool Bot::IsGroupOfEnemies(Vector location, int numEnemies, int radius) -{ - int numPlayers = 0; - - // search the world for enemy players... - for (const auto& client : g_clients) - { - if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.ent == GetEntity()) - continue; - - if ((GetEntityOrigin(client.ent) - location).GetLength() < radius) - { - // don't target our teammates... - if (client.team == m_team) - return false; - - if (numPlayers++ > numEnemies) - return true; - } - } - - return false; -} - -void Bot::CheckReload(void) -{ - // check the reload state - if (GetCurrentTask()->taskID == TASK_ESCAPEFROMBOMB || GetCurrentTask()->taskID == TASK_PLANTBOMB || GetCurrentTask()->taskID == TASK_DEFUSEBOMB || GetCurrentTask()->taskID == TASK_PICKUPITEM || GetCurrentTask()->taskID == TASK_THROWFBGRENADE || GetCurrentTask()->taskID == TASK_THROWSMGRENADE || m_isUsingGrenade) - { - m_reloadState = RSTATE_NONE; - return; - } - - if (m_weaponReloadAPI) - { - m_reloadState = RSTATE_NONE; - return; - } - - m_isReloading = false; // update reloading status - m_reloadCheckTime = engine->GetTime() + 5.0f; - - if (m_reloadState != RSTATE_NONE) - { - int weapons = pev->weapons; - - if (m_reloadState == RSTATE_PRIMARY) - weapons &= WeaponBits_Primary; - else if (m_reloadState == RSTATE_SECONDARY) - weapons &= WeaponBits_Secondary; - - if (weapons == 0) - { - m_reloadState++; - - if (m_reloadState > RSTATE_SECONDARY) - m_reloadState = RSTATE_NONE; - - return; - } - - int weaponIndex = -1; - int maxClip = CheckMaxClip(weapons, &weaponIndex); - - if (m_ammoInClip[weaponIndex] < maxClip * 0.8f && g_weaponDefs[weaponIndex].ammo1 != -1 && - g_weaponDefs[weaponIndex].ammo1 < 32 && m_ammo[g_weaponDefs[weaponIndex].ammo1] > 0) - { - if (m_currentWeapon != weaponIndex) - SelectWeaponByName(g_weaponDefs[weaponIndex].className); - - pev->button &= ~IN_ATTACK; - - if ((pev->oldbuttons & IN_RELOAD) == RSTATE_NONE) - pev->button |= IN_RELOAD; // press reload button - - m_isReloading = true; - } - else - { - // if we have enemy don't reload next weapon - if ((m_states & (STATE_SEEINGENEMY | STATE_HEARENEMY)) || m_seeEnemyTime + 5.0f > engine->GetTime()) - { - m_reloadState = RSTATE_NONE; - return; - } - m_reloadState++; - - if (m_reloadState > RSTATE_SECONDARY) - m_reloadState = RSTATE_NONE; - - return; - } - } -} - -int Bot::CheckMaxClip(int weaponId, int* weaponIndex) -{ - int maxClip = -1; - for (int i = 1; i < Const_MaxWeapons; i++) - { - if (weaponId & (1 << i)) - { - *weaponIndex = i; - break; - } - } - InternalAssert(weaponIndex); - - if (m_weaponClipAPI > 0) - return m_weaponClipAPI; - - switch (*weaponIndex) - { - case WEAPON_M249: - maxClip = 100; - break; - - case WEAPON_P90: - maxClip = 50; - break; - - case WEAPON_GALIL: - maxClip = 35; - break; - - case WEAPON_ELITE: - case WEAPON_MP5: - case WEAPON_TMP: - case WEAPON_MAC10: - case WEAPON_M4A1: - case WEAPON_AK47: - case WEAPON_SG552: - case WEAPON_AUG: - case WEAPON_SG550: - maxClip = 30; - break; - - case WEAPON_UMP45: - case WEAPON_FAMAS: - maxClip = 25; - break; - - case WEAPON_GLOCK18: - case WEAPON_FN57: - case WEAPON_G3SG1: - maxClip = 20; - break; - - case WEAPON_P228: - maxClip = 13; - break; - - case WEAPON_USP: - maxClip = 12; - break; - - case WEAPON_AWP: - case WEAPON_SCOUT: - maxClip = 10; - break; - - case WEAPON_M3: - maxClip = 8; - break; - - case WEAPON_DEAGLE: - case WEAPON_XM1014: - maxClip = 7; - break; - } - - return maxClip; + { + m_destOrigin = lastEnemyOrigin; + m_moveSpeed = -pev->maxspeed; + m_checkFall = true; + m_moveToGoal = false; + + Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval); + Vector directionNormal = directionOld.Normalize(); + directionNormal.z = 0.0f; + + SetStrafeSpeed(directionNormal, pev->maxspeed); + + return; + } + else + m_moveSpeed = 0.0f; + } + else + { + m_moveToGoal = true; + m_moveSpeed = pev->maxspeed; + } + } + else + { + m_moveToGoal = true; + m_moveSpeed = pev->maxspeed; + } + } + } + + return; + } + else if (!IsZombieMode() && GetCurrentTask()->taskID != TASK_CAMP && GetCurrentTask()->taskID != TASK_SEEKCOVER && GetCurrentTask()->taskID != TASK_ESCAPEFROMBOMB) + { + /*if (m_skill >= 50) + { + // 1 tick delay every 1 seconds. + if (m_isSlowThink) + return; + + // higher skill bots have a better movement + if (!ChanceOf(m_skill)) + return; + + float input[3] = {0, 0, 0}; + + input[0] = (pev->velocity.x * pev->health) - (m_enemy->v.velocity.x * m_enemy->v.health); + input[0] /= 1000; // 1 = forward | 2 = back + input[1] = (pev->velocity.y * m_enemy->v.speed) - (m_enemy->v.velocity.y * pev->speed); + input[1] /= 1000; // 1 = right | 2 = left + //input[2] = pev->velocity.z - m_enemy->v.velocity.z; + //input[2] /= 1000; // 1 = jump | 2 = crouch + + int i = GetIndex(); + + if (brain[i]->l[brain[i]->layers - 1].n[0].output < 0.01f || brain[i]->l[brain[i]->layers - 1].n[0].output > 1.99f) + m_moveSpeed = 0.0f; + else if (brain[i]->l[brain[i]->layers - 1].n[0].output <= 1.0f) + m_moveSpeed = -pev->maxspeed; + else if (brain[i]->l[brain[i]->layers - 1].n[0].output <= 2.0f) + m_moveSpeed = pev->maxspeed; + + if (brain[i]->l[brain[i]->layers - 1].n[1].output < 0.2f || brain[i]->l[brain[i]->layers - 1].n[1].output > 1.8f) + m_strafeSpeed = 0.0f; + else if (brain[i]->l[brain[i]->layers - 1].n[1].output <= 1.0f) + m_strafeSpeed = -pev->maxspeed; + else if (brain[i]->l[brain[i]->layers - 1].n[1].output <= 2.0f) + m_strafeSpeed = pev->maxspeed; + + IgnoreCollisionShortly(); + + return; + }*/ + + // little trick for bots + if (m_isReloading && (m_skill > 40 || ChanceOf(5))) + { + const Vector& src = pev->origin - Vector(0, 0, 18.0f); + + extern ConVar ebot_think_fps; + if ((m_visibility & (VISIBILITY_HEAD | VISIBILITY_BODY)) && m_enemy->v.weapons != WEAPON_KNIFE && !IsVisible(src, m_enemy)) + m_duckTime = engine->GetTime() + (engine->RandomFloat(0.9f, 1.1f) / ebot_think_fps.GetFloat()) + 1.0f; + } + + if (m_isSlowThink && (m_isReloading || ((m_isLeader || m_isVIP || m_isBomber) && pev->health <= (pev->max_health / 2)) || m_isUsingGrenade || (m_personality != PERSONALITY_RUSHER && ::IsInViewCone(pev->origin, m_enemy) && (pev->health + m_agressionLevel) < m_enemy->v.health + (m_personality == PERSONALITY_CAREFUL ? 15.0f : 30.0f)))) + { + int seekindex = FindCoverWaypoint(9999.0f); + + if (IsValidWaypoint(seekindex)) + PushTask(TASK_SEEKCOVER, TASKPRI_SEEKCOVER, seekindex, 1.0f, true); + + return; + } + + DeleteSearchNodes(); + SetLastEnemy(m_enemy); + m_destOrigin = GetEntityOrigin(m_enemy); + + float distance = (pev->origin - m_lookAt).GetLength(); // how far away is the enemy scum? + + if (m_currentWeapon != WEAPON_KNIFE && distance <= 256.0f) // get back! + { + m_moveSpeed = -pev->maxspeed; + return; + } + + m_timeWaypointMove = 0.0f; + + if (m_timeWaypointMove < engine->GetTime()) + { + int approach; + if (m_currentWeapon == WEAPON_KNIFE) // knife? + approach = 100; + else if (!(m_states & STATE_SEEINGENEMY)) // if suspecting enemy stand still + approach = 49; + else if (m_isReloading || m_isVIP) // if reloading or vip back off + approach = 29; + else + { + approach = static_cast (pev->health * m_agressionLevel); + + if (UsesSniper() && approach > 49) + approach = 49; + } + + // only take cover when bomb is not planted and enemy can see the bot or the bot is VIP + if (approach < 30 && !g_bombPlanted && (::IsInViewCone(GetEntityOrigin(m_enemy), GetEntity()) || m_isVIP)) + { + m_moveSpeed = -pev->maxspeed; + + GetCurrentTask()->taskID = TASK_FIGHTENEMY; + GetCurrentTask()->canContinue = true; + GetCurrentTask()->desire = TASKPRI_FIGHTENEMY + 1.0f; + } + else if (!(::IsInViewCone(pev->origin, m_enemy)) && m_currentWeapon != WEAPON_KNIFE) // if enemy cant see us, we never move + m_moveSpeed = 0.0f; + else if (approach >= 50 || UsesBadPrimary() || IsBehindSmokeClouds(m_enemy)) // we lost him? + m_moveSpeed = pev->maxspeed; + else + m_moveSpeed = pev->maxspeed; + + if (UsesSniper()) + { + m_fightStyle = 1; + m_lastFightStyleCheck = engine->GetTime(); + } + else if (UsesRifle() || UsesSubmachineGun()) + { + if (m_lastFightStyleCheck + 0.5f < engine->GetTime()) + { + if (ChanceOf(75)) + { + if (distance < 768.0f) + m_fightStyle = 0; + else if (distance < 1024.0f) + { + if (ChanceOf(UsesSubmachineGun() ? 50 : 30)) + m_fightStyle = 0; + else + m_fightStyle = 1; + } + else + { + if (ChanceOf(UsesSubmachineGun() ? 80 : 93)) + m_fightStyle = 1; + else + m_fightStyle = 0; + } + } + + m_lastFightStyleCheck = engine->GetTime(); + } + } + else + { + if (m_lastFightStyleCheck + 0.5f < engine->GetTime()) + { + if (ChanceOf(75)) + { + if (ChanceOf(50)) + m_fightStyle = 0; + else + m_fightStyle = 1; + } + + m_lastFightStyleCheck = engine->GetTime(); + } + } + + if (m_fightStyle == 0 || ((pev->button & IN_RELOAD) || m_isReloading) || (UsesPistol() && distance < 768.0f) || m_currentWeapon == WEAPON_KNIFE) + { + if (m_strafeSetTime < engine->GetTime()) + { + // to start strafing, we have to first figure out if the target is on the left side or right side + MakeVectors(m_enemy->v.v_angle); + + const Vector& dirToPoint = (pev->origin - m_enemy->v.origin).Normalize2D(); + const Vector& rightSide = g_pGlobals->v_right.Normalize2D(); + + if ((dirToPoint | rightSide) < 0) + m_combatStrafeDir = 1; + else + m_combatStrafeDir = 0; + + if (ChanceOf(30)) + m_combatStrafeDir = (m_combatStrafeDir == 1 ? 0 : 1); + + m_strafeSetTime = engine->GetTime() + engine->RandomFloat(0.5f, 3.0f); + } + + if (m_combatStrafeDir == 0) + { + if (!CheckWallOnLeft()) + m_strafeSpeed = -pev->maxspeed; + else + { + m_combatStrafeDir = 1; + m_strafeSetTime = engine->GetTime() + 1.5f; + } + } + else + { + if (!CheckWallOnRight()) + m_strafeSpeed = pev->maxspeed; + else + { + m_combatStrafeDir = 0; + m_strafeSetTime = engine->GetTime() + 1.5f; + } + } + + if (m_jumpTime + 10.0f < engine->GetTime() && IsOnFloor() && ChanceOf(m_isReloading ? 5 : 2) && pev->velocity.GetLength2D() > float(m_skill + 50.0f) && !UsesSniper()) + pev->button |= IN_JUMP; + + if (m_moveSpeed > 0.0f && distance > 512.0f && m_currentWeapon != WEAPON_KNIFE) + m_moveSpeed = 0.0f; + + if (m_currentWeapon == WEAPON_KNIFE) + m_strafeSpeed = 0.0f; + } + else if (m_fightStyle == 1) + { + const Vector& src = pev->origin - Vector(0, 0, 18.0f); + + extern ConVar ebot_think_fps; + if ((m_visibility & (VISIBILITY_HEAD | VISIBILITY_BODY)) && m_enemy->v.weapons != WEAPON_KNIFE && IsVisible(src, m_enemy)) + m_duckTime = engine->GetTime() + (engine->RandomFloat(0.9f, 1.1f) / ebot_think_fps.GetFloat()) + 0.2f; + + m_moveSpeed = 0.0f; + m_strafeSpeed = 0.0f; + m_navTimeset = engine->GetTime(); + } + } + + if (m_duckTime > engine->GetTime()) + { + m_moveSpeed = 0.0f; + m_strafeSpeed = 0.0f; + } + + if (m_moveSpeed > 0.0f && m_currentWeapon != WEAPON_KNIFE) + m_moveSpeed = GetWalkSpeed(); + + if (m_isReloading) + { + m_moveSpeed = -pev->maxspeed; + m_duckTime = engine->GetTime() - 2.0f; + } + + if (!IsInWater() && !IsOnLadder() && (m_moveSpeed > 0.0f || m_strafeSpeed >= 0.0f)) + { + MakeVectors(pev->v_angle); + + if (IsDeadlyDrop(pev->origin + (g_pGlobals->v_forward * m_moveSpeed * 0.2f) + (g_pGlobals->v_right * m_strafeSpeed * 0.2f) + (pev->velocity * m_frameInterval))) + { + m_strafeSpeed = -m_strafeSpeed; + m_moveSpeed = -m_moveSpeed; + + pev->button &= ~IN_JUMP; + } + } + + IgnoreCollisionShortly(); + } +} + +bool Bot::HasPrimaryWeapon(void) +{ + // this function returns returns true, if bot has a primary weapon + + return (pev->weapons & WeaponBits_Primary) != 0; +} + +bool Bot::HasShield(void) +{ + // this function returns true, if bot has a tactical shield + + return strncmp(STRING(pev->viewmodel), "models/shield/v_shield_", 23) == 0; +} + +bool Bot::IsShieldDrawn(void) +{ + // this function returns true, is the tactical shield is drawn + + if (!HasShield()) + return false; + + return pev->weaponanim == 6 || pev->weaponanim == 7; +} + +bool Bot::IsEnemyProtectedByShield(edict_t* enemy) +{ + // this function returns true, if enemy protected by the shield + + if (FNullEnt(enemy) || (HasShield() && IsShieldDrawn())) + return false; + + // check if enemy has shield and this shield is drawn + if (strncmp(STRING(enemy->v.viewmodel), "models/shield/v_shield_", 23) == 0 && (enemy->v.weaponanim == 6 || enemy->v.weaponanim == 7)) + { + if (::IsInViewCone(pev->origin, enemy)) + return true; + } + return false; +} + +bool Bot::UsesSniper(void) +{ + return m_currentWeapon == WEAPON_AWP || m_currentWeapon == WEAPON_G3SG1 || m_currentWeapon == WEAPON_SCOUT || m_currentWeapon == WEAPON_SG550; +} + +bool Bot::UsesRifle(void) +{ + WeaponSelect* selectTab = &g_weaponSelect[0]; + int count = 0; + + while (selectTab->id) + { + if (m_currentWeapon == selectTab->id) + break; + + selectTab++; + count++; + } + + if (selectTab->id && count > 13) + return true; + + return false; +} + +bool Bot::UsesPistol(void) +{ + WeaponSelect* selectTab = &g_weaponSelect[0]; + int count = 0; + + // loop through all the weapons until terminator is found + while (selectTab->id) + { + if (m_currentWeapon == selectTab->id) + break; + + selectTab++; + count++; + } + + if (selectTab->id && count < 7) + return true; + + return false; +} + +bool Bot::UsesSubmachineGun(void) +{ + return m_currentWeapon == WEAPON_MP5 || m_currentWeapon == WEAPON_TMP || m_currentWeapon == WEAPON_P90 || m_currentWeapon == WEAPON_MAC10 || m_currentWeapon == WEAPON_UMP45; +} + +bool Bot::UsesZoomableRifle(void) +{ + return m_currentWeapon == WEAPON_AUG || m_currentWeapon == WEAPON_SG552; +} + +bool Bot::UsesBadPrimary(void) +{ + return m_currentWeapon == WEAPON_M3 || m_currentWeapon == WEAPON_UMP45 || m_currentWeapon == WEAPON_MAC10 || m_currentWeapon == WEAPON_TMP || m_currentWeapon == WEAPON_P90; +} + +void Bot::ThrowFireNade(void) +{ + if (pev->weapons & (1 << WEAPON_HEGRENADE)) + PushTask(TASK_THROWHEGRENADE, TASKPRI_THROWGRENADE, -1, engine->RandomFloat(0.6f, 0.9f), false); +} + +void Bot::ThrowFrostNade(void) +{ + if (pev->weapons & (1 << WEAPON_FBGRENADE)) + PushTask(TASK_THROWFBGRENADE, TASKPRI_THROWGRENADE, -1, engine->RandomFloat(0.6f, 0.9f), false); +} + +int Bot::CheckGrenades(void) +{ + if (pev->weapons & (1 << WEAPON_HEGRENADE)) + return WEAPON_HEGRENADE; + else if (pev->weapons & (1 << WEAPON_FBGRENADE)) + return WEAPON_FBGRENADE; + else if (pev->weapons & (1 << WEAPON_SMGRENADE)) + return WEAPON_SMGRENADE; + + return -1; +} + +void Bot::SelectBestWeapon(void) +{ + if (!m_isSlowThink) + return; + + // never change weapon while reloading if theres no enemy + if (FNullEnt(m_enemy) && m_isReloading) + return; + + if (m_isZombieBot && IsZombieMode()) + { + SelectWeaponByName("weapon_knife"); + return; + } + + if (!FNullEnt(m_enemy) && (pev->origin - GetEntityOrigin(m_enemy)).GetLength() <= 128.0f) + { + SelectWeaponByName("weapon_knife"); + return; + } + + if (GetCurrentTask()->taskID == TASK_THROWHEGRENADE) + return; + + if (GetCurrentTask()->taskID == TASK_THROWFBGRENADE) + return; + + if (GetCurrentTask()->taskID == TASK_THROWSMGRENADE) + return; + + WeaponSelect* selectTab = &g_weaponSelect[0]; + + int selectIndex = 0; + int chosenWeaponIndex = 0; + + while (selectTab[selectIndex].id) + { + if (!(pev->weapons & (1 << selectTab[selectIndex].id))) + { + selectIndex++; + continue; + } + + int id = selectTab[selectIndex].id; + bool ammoLeft = false; + + if (selectTab[selectIndex].id == m_currentWeapon && (GetAmmoInClip() < 0 || GetAmmoInClip() >= selectTab[selectIndex].minPrimaryAmmo)) + ammoLeft = true; + + if (g_weaponDefs[id].ammo1 < 0 || m_ammo[g_weaponDefs[id].ammo1] >= selectTab[selectIndex].minPrimaryAmmo) + ammoLeft = true; + + if (ammoLeft) + chosenWeaponIndex = selectIndex; + + selectIndex++; + } + + chosenWeaponIndex %= Const_NumWeapons + 1; + selectIndex = chosenWeaponIndex; + + int weaponID = selectTab[selectIndex].id; + if (weaponID == m_currentWeapon) + return; + + //if (m_currentWeapon != weaponID) + SelectWeaponByName(selectTab[selectIndex].weaponName); + + m_isReloading = false; + m_reloadState = RSTATE_NONE; +} + +void Bot::SelectPistol(void) +{ + if (!m_isSlowThink) + return; + + if (m_isReloading) + return; + + int oldWeapons = pev->weapons; + + pev->weapons &= ~WeaponBits_Primary; + SelectBestWeapon(); + + pev->weapons = oldWeapons; +} + +int Bot::GetHighestWeapon(void) +{ + WeaponSelect* selectTab = &g_weaponSelect[0]; + + int weapons = pev->weapons; + int num = 0; + int i = 0; + + // loop through all the weapons until terminator is found... + while (selectTab->id) + { + // is the bot carrying this weapon? + if (weapons & (1 << selectTab->id)) + num = i; + + i++; + selectTab++; + } + + return num; +} + +void Bot::SelectWeaponByName(const char* name) +{ + FakeClientCommand(GetEntity(), name); +} + +void Bot::SelectWeaponbyNumber(int num) +{ + FakeClientCommand(GetEntity(), g_weaponSelect[num].weaponName); +} + +void Bot::CommandTeam(void) +{ + if (GetGameMod() != MODE_BASE && GetGameMod() != MODE_TDM) + return; + + // prevent spamming + if (m_timeTeamOrder > engine->GetTime()) + return; + + bool memberNear = false; + bool memberExists = false; + + // search teammates seen by this bot + for (const auto& client : g_clients) + { + if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team != m_team || client.ent == GetEntity()) + continue; + + memberExists = true; + + if (EntityIsVisible(client.origin)) + { + memberNear = true; + break; + } + } + + if (memberNear && ChanceOf(50)) // has teammates ? + { + if (m_personality == PERSONALITY_RUSHER) + RadioMessage(Radio_StormTheFront); + else if(m_personality == PERSONALITY_NORMAL) + RadioMessage(Radio_StickTogether); + else + RadioMessage(Radio_Fallback); + } + else if (memberExists) + { + if (ChanceOf(25)) + RadioMessage(Radio_NeedBackup); + else if (ChanceOf(25)) + RadioMessage(Radio_EnemySpotted); + else if (ChanceOf(25)) + RadioMessage(Radio_TakingFire); + } + + m_timeTeamOrder = engine->GetTime() + engine->RandomFloat(10.0f, 30.0f); +} + +bool Bot::IsGroupOfEnemies(Vector location, int numEnemies, int radius) +{ + int numPlayers = 0; + + // search the world for enemy players... + for (const auto& client : g_clients) + { + if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.ent == GetEntity()) + continue; + + if ((GetEntityOrigin(client.ent) - location).GetLength() < radius) + { + // don't target our teammates... + if (client.team == m_team) + return false; + + if (numPlayers++ > numEnemies) + return true; + } + } + + return false; +} + +void Bot::CheckReload(void) +{ + // check the reload state + if (GetCurrentTask()->taskID == TASK_ESCAPEFROMBOMB || GetCurrentTask()->taskID == TASK_PLANTBOMB || GetCurrentTask()->taskID == TASK_DEFUSEBOMB || GetCurrentTask()->taskID == TASK_PICKUPITEM || GetCurrentTask()->taskID == TASK_THROWFBGRENADE || GetCurrentTask()->taskID == TASK_THROWSMGRENADE || m_isUsingGrenade) + { + m_reloadState = RSTATE_NONE; + return; + } + + if (m_weaponReloadAPI) + { + m_reloadState = RSTATE_NONE; + return; + } + + m_isReloading = false; // update reloading status + m_reloadCheckTime = engine->GetTime() + 5.0f; + + if (m_reloadState != RSTATE_NONE) + { + int weapons = pev->weapons; + + if (m_reloadState == RSTATE_PRIMARY) + weapons &= WeaponBits_Primary; + else if (m_reloadState == RSTATE_SECONDARY) + weapons &= WeaponBits_Secondary; + + if (weapons == 0) + { + m_reloadState++; + + if (m_reloadState > RSTATE_SECONDARY) + m_reloadState = RSTATE_NONE; + + return; + } + + int weaponIndex = -1; + int maxClip = CheckMaxClip(weapons, &weaponIndex); + + if (m_ammoInClip[weaponIndex] < maxClip * 0.8f && g_weaponDefs[weaponIndex].ammo1 != -1 && + g_weaponDefs[weaponIndex].ammo1 < 32 && m_ammo[g_weaponDefs[weaponIndex].ammo1] > 0) + { + if (m_currentWeapon != weaponIndex) + SelectWeaponByName(g_weaponDefs[weaponIndex].className); + + pev->button &= ~IN_ATTACK; + + if ((pev->oldbuttons & IN_RELOAD) == RSTATE_NONE) + pev->button |= IN_RELOAD; // press reload button + + m_isReloading = true; + } + else + { + // if we have enemy don't reload next weapon + if ((m_states & (STATE_SEEINGENEMY | STATE_HEARENEMY)) || m_seeEnemyTime + 5.0f > engine->GetTime()) + { + m_reloadState = RSTATE_NONE; + return; + } + m_reloadState++; + + if (m_reloadState > RSTATE_SECONDARY) + m_reloadState = RSTATE_NONE; + + return; + } + } +} + +int Bot::CheckMaxClip(int weaponId, int* weaponIndex) +{ + int maxClip = -1; + for (int i = 1; i < Const_MaxWeapons; i++) + { + if (weaponId & (1 << i)) + { + *weaponIndex = i; + break; + } + } + InternalAssert(weaponIndex); + + if (m_weaponClipAPI > 0) + return m_weaponClipAPI; + + switch (*weaponIndex) + { + case WEAPON_M249: + maxClip = 100; + break; + + case WEAPON_P90: + maxClip = 50; + break; + + case WEAPON_GALIL: + maxClip = 35; + break; + + case WEAPON_ELITE: + case WEAPON_MP5: + case WEAPON_TMP: + case WEAPON_MAC10: + case WEAPON_M4A1: + case WEAPON_AK47: + case WEAPON_SG552: + case WEAPON_AUG: + case WEAPON_SG550: + maxClip = 30; + break; + + case WEAPON_UMP45: + case WEAPON_FAMAS: + maxClip = 25; + break; + + case WEAPON_GLOCK18: + case WEAPON_FN57: + case WEAPON_G3SG1: + maxClip = 20; + break; + + case WEAPON_P228: + maxClip = 13; + break; + + case WEAPON_USP: + maxClip = 12; + break; + + case WEAPON_AWP: + case WEAPON_SCOUT: + maxClip = 10; + break; + + case WEAPON_M3: + maxClip = 8; + break; + + case WEAPON_DEAGLE: + case WEAPON_XM1014: + maxClip = 7; + break; + } + + return maxClip; } \ No newline at end of file diff --git a/source/control.cpp b/source/control.cpp index a7972459..132aa01d 100644 --- a/source/control.cpp +++ b/source/control.cpp @@ -304,7 +304,8 @@ void BotControl::Think(void) m_bots[i]->m_thinkTimer = engine->GetTime() + (engine->RandomFloat(0.95f, 1.05f) / ebot_think_fps.GetFloat()); m_bots[i]->Think(); } - else if (!ebot_stopbots.GetBool() && m_bots[i]->m_notKilled && !m_bots[i]->m_isSlowThink) + + if (!ebot_stopbots.GetBool() && m_bots[i]->m_notKilled) m_bots[i]->FacePosition(); m_bots[i]->m_moveAnglesForRunMove = m_bots[i]->m_moveAngles; @@ -442,7 +443,7 @@ void BotControl::CheckBotNum(void) fp2.Close(); } else - ServerPrint("UnKnow Problem - Cannot Save ebot Quota"); + ServerPrint("Unknow Problem - Cannot save ebot quota"); } ebot_quota_save.SetInt(-1); @@ -726,11 +727,9 @@ void BotControl::RemoveRandom(void) for (int i = 0; i < engine->GetMaxClients(); i++) { Bot* bot = g_botManager->GetBot(i); - if (bot != null) // is this slot used? { bot->Kick(); - break; } } @@ -1071,6 +1070,7 @@ void Bot::NewRound(void) // delete all allocated path nodes DeleteSearchNodes(); + m_itaimstart = engine->GetTime(); m_waypointOrigin = nullvec; m_destOrigin = nullvec; m_currentWaypointIndex = -1; @@ -1088,22 +1088,6 @@ void Bot::NewRound(void) m_prevWptIndex[2] = -1; m_navTimeset = engine->GetTime(); - m_aimstoptime = engine->GetTime(); - - switch (m_personality) - { - case PERSONALITY_NORMAL: - m_pathType = engine->RandomInt(0, 1) < m_agressionLevel ? 1 : 0; - break; - - case PERSONALITY_RUSHER: - m_pathType = 0; - break; - - case PERSONALITY_CAREFUL: - m_pathType = 1; - break; - } // clear all states & tasks m_states = 0; @@ -1309,11 +1293,9 @@ void Bot::Kill(void) void Bot::Kick(void) { - if (!(pev->flags & FL_FAKECLIENT) || IsNullString(GetEntityName(GetEntity()))) + if (IsNullString(GetEntityName(GetEntity()))) return; - pev->flags &= ~FL_FAKECLIENT; - ServerCommand("kick \"%s\"", GetEntityName(GetEntity())); CenterPrint("Bot '%s' kicked", GetEntityName(GetEntity())); diff --git a/source/engine.cpp b/source/engine.cpp index 2e1813c4..dea15a28 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -56,15 +56,37 @@ uint32_t Engine::GetRandomBase(void) float Engine::RandomFloat(float low, float high) { if (low >= high) - return low; - return RANDOM_FLOAT(low, high); + { + int random = RANDOM_LONG(1, 2); + switch (random) + { + case 1: + return low; + default: + return high; + } + } + + srand(time(0)); + return (low + 1) + (((float)rand()) / (float)RAND_MAX) * (high - (low + 1)); } int Engine::RandomInt(int low, int high) { if (low >= high) - return low; - return RANDOM_LONG(low, high); + { + int random = RANDOM_LONG(1, 2); + switch (random) + { + case 1: + return low; + default: + return high; + } + } + + srand(time(0)); + return rand() % (high - low + 1) + low; } void Engine::SubtractVectors(Vector first, Vector second, Vector output) @@ -80,20 +102,16 @@ void Engine::SubtractVectors(Vector first, Vector second, Vector output) float Engine::GetVectorDotProduct(Vector first, Vector second) { - Vector product; + int product = 0; for (int i = 0; i < 3; i++) - { - product.x = product.y + first.x * second.x; - product.x = product.y + first.y * second.y; - } - - return ((product.x / 2) - (product.y / 2)); + product = product + first[i] * second[i]; + return product; } void Engine::NormalizeVector(Vector vector, Vector output) { Vector result; - float length = sse_rsqrt((vector.x * vector.x) + (vector.y * vector.y) + (vector.z * vector.z)); + float length = Q_rsqrt((vector.x * vector.x) + (vector.y * vector.y) + (vector.z * vector.z)); result.x = (vector.x / length); result.y = (vector.y / length); @@ -129,7 +147,7 @@ float Engine::AngleDiff(float destAngle, float srcAngle) return AngleNormalize(destAngle - srcAngle); } -float Engine::Clamp(float a, float b, float c) +float Engine::DoClamp(float a, float b, float c) { return (a > c ? c : (a < b ? b : a)); } diff --git a/source/globals.cpp b/source/globals.cpp index 2ea12bc0..314e6d34 100644 --- a/source/globals.cpp +++ b/source/globals.cpp @@ -24,14 +24,13 @@ #include +bool cpuSSESuport = false; + float API_Version; float amxxDLL_Version = -1.0; uint16 amxxDLL_bV16[4]; -// **** - float SwNPC_Version = -1.0; uint16 SwNPC_Build[4]; -// **** bool g_isMetamod = false; bool g_roundEnded = true; @@ -123,9 +122,6 @@ int g_rusherWeaponPrefs[Const_NumWeapons] = int g_carefulWeaponPrefs[Const_NumWeapons] = { 0, 2, 1, 4, 5, 6, 3, 7, 8, 12, 10, 13, 11, 9, 24, 18, 14, 17, 16, 15, 19, 20, 21, 22, 23, 25 }; -int g_grenadeBuyPrecent[Const_NumWeapons - 23] = -{ 95, 85, 40 }; - int g_grenadeBuyMoney[Const_NumWeapons - 23] = { 300, 200, 300 }; SkillDef g_skillTab[6] = diff --git a/source/interface.cpp b/source/interface.cpp index be24cc2b..c6ef0a0b 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -872,14 +872,6 @@ void InitConfig(void) for (int i = 0; i < Const_NumWeapons; i++) g_weaponSelect[i].teamAS = splitted[i]; } - else if (pair[0] == "GrenadePercent") - { - if (splitted.GetElementNumber() != 3) - AddLogEntry(LOG_FATAL, "%s entry in general config is not valid.", &pair[0][0]); - - for (int i = 0; i < 3; i++) - g_grenadeBuyPrecent[i] = splitted[i]; - } else if (pair[0] == "GrenadeMoney") { if (splitted.GetElementNumber() != 3) @@ -2781,14 +2773,6 @@ void StartFrame(void) CheckWelcomeMessage(); } - extern ConVar ebot_dangerfactor; - - if (ebot_dangerfactor.GetFloat() > 1024.0f) - ebot_dangerfactor.SetFloat(1024.0f); - - if (ebot_dangerfactor.GetFloat() < 256.0f) - ebot_dangerfactor.SetFloat(256.0f); - secondTimer = engine->GetTime() + 1.0f; } diff --git a/source/navigate.cpp b/source/navigate.cpp index 0f12e406..787753d9 100644 --- a/source/navigate.cpp +++ b/source/navigate.cpp @@ -24,7 +24,6 @@ #include -ConVar ebot_dangerfactor("ebot_dangerfactor", "400"); ConVar ebot_aimbot("ebot_aimbot", "0"); ConVar ebot_aiming_type("ebot_aiming_type", "1"); @@ -35,7 +34,7 @@ int Bot::FindGoal(void) if (m_waypointGoalAPI != -1) return m_chosenGoalIndex = m_waypointGoalAPI; - // force bot move to bomb. + // force bot move to bomb if (GetGameMod() == MODE_BASE && (g_mapType & MAP_DE) && g_bombPlanted && m_team == TEAM_COUNTER) { if ((pev->origin - g_waypoint->GetBombPosition()).GetLength() <= 1024.0f || m_inBombZone || m_isLeader || g_waypoint->GetPath(m_currentWaypointIndex)->flags & WAYPOINT_GOAL) @@ -347,7 +346,6 @@ int Bot::FindGoal(void) else if (tactic == 4 && !offensiveWpts.IsEmpty()) // offensive goal { int wpIndex = offensiveWpts.GetRandomElement(); - if (IsValidWaypoint(wpIndex)) return m_chosenGoalIndex = wpIndex; } @@ -457,7 +455,6 @@ bool Bot::DoWaypointNav(void) } extern ConVar ebot_think_fps; - m_destOrigin = m_waypointOrigin + pev->view_ofs + g_pGlobals->v_forward + (g_pGlobals->v_forward * (1 / ebot_think_fps.GetFloat())); // this waypoint has additional travel flags - care about them @@ -505,8 +502,8 @@ bool Bot::DoWaypointNav(void) SelectBestWeapon(); } - float waypointDistance = (pev->origin - m_waypointOrigin).GetLengthSquared() + ebot_think_fps.GetFloat(); - float fixedWaypointDistance = sse_rsqrt(waypointDistance); + float waypointDistance = (pev->origin - m_waypointOrigin).GetLengthSquared(); + float fixedWaypointDistance = Q_rsqrt(waypointDistance); if (g_waypoint->GetPath(m_currentWaypointIndex)->flags & WAYPOINT_LADDER) { @@ -596,12 +593,12 @@ bool Bot::DoWaypointNav(void) } } - float desiredDistance = 8.0f; + float desiredDistance = 12.0f; // initialize the radius for a special waypoint type, where the wpt is considered to be reached if (g_waypoint->GetPath(m_currentWaypointIndex)->flags & WAYPOINT_LIFT) desiredDistance = 64.0f; - else if ((pev->flags & FL_DUCKING) || (g_waypoint->GetPath(m_currentWaypointIndex)->flags & WAYPOINT_GOAL)) + else if ((pev->flags & FL_DUCKING)) desiredDistance = 32.0f; else if (g_waypoint->GetPath(m_currentWaypointIndex)->flags & WAYPOINT_LADDER) desiredDistance = 16.0f; @@ -618,9 +615,9 @@ bool Bot::DoWaypointNav(void) } } - if (desiredDistance < 24.0f && waypointDistance < (32.0f * 32.0f) && (pev->origin + (pev->velocity * m_frameInterval) - m_waypointOrigin).GetLengthSquared2D() >= waypointDistance) + if (desiredDistance < 24.0f && fixedWaypointDistance < 32.0f && (pev->origin + (pev->velocity * m_frameInterval) - m_waypointOrigin).GetLengthSquared() >= waypointDistance) desiredDistance = fixedWaypointDistance + 2.0f; - else if (!(m_currentTravelFlags & PATHFLAG_JUMP) && (m_waypointOrigin - pev->origin).GetLengthSquared2D() <= (16.0f * 16.0f) && m_waypointOrigin.z <= pev->origin.z + 32.0f) + else if (!(m_currentTravelFlags & PATHFLAG_JUMP) && (m_waypointOrigin - pev->origin).GetLengthSquared() <= (32.0f * 32.0f) && m_waypointOrigin.z <= pev->origin.z + 32.0f) { if (m_navNode == null || (m_navNode->next != null && g_waypoint->Reachable(GetEntity(), m_navNode->next->index))) desiredDistance = fixedWaypointDistance + 2.0f; @@ -629,9 +626,10 @@ bool Bot::DoWaypointNav(void) if (m_waypointGoalAPI != -1 && m_currentWaypointIndex == m_waypointGoalAPI) m_waypointGoalAPI = -1; - if (waypointDistance <= (desiredDistance * desiredDistance) || ((pev->origin - m_waypointOrigin).GetLengthSquared2D() + (ebot_think_fps.GetFloat() * ebot_think_fps.GetFloat())) <= (desiredDistance * desiredDistance)) + desiredDistance += (m_frameInterval * 4.0f); + if (waypointDistance <= (desiredDistance * desiredDistance) || (pev->origin - m_waypointOrigin).GetLengthSquared2D() <= (desiredDistance * desiredDistance)) { - // Did we reach a destination Waypoint? + // did we reach a destination waypoint? if (GetCurrentTask()->data == m_currentWaypointIndex) { // add goal values @@ -787,84 +785,37 @@ void PriorityQueue::HeapSiftUp(void) } } -inline const float GF_Cost(int index, int parent, int team, float offset) +inline const float GF_CostCareful(int index, int parent, int team) { float baseCost = g_exp.GetAStarValue(index, team, false); - for (int i = 0; i < Const_MaxPathIndex; i++) { int neighbour = g_waypoint->GetPath(index)->index[i]; - if (neighbour != -1) baseCost += g_exp.GetDamage(neighbour, neighbour, team); } - float pathDist = g_waypoint->GetPathDistanceFloat(parent, index); - - if (g_waypoint->GetPath(index)->flags & WAYPOINT_LADDER) - baseCost += pathDist * 2.0f; - return pathDist + (baseCost * (ebot_dangerfactor.GetFloat() * 2.0f / offset)); + return baseCost / g_waypoint->GetPathDistanceFloat(parent, index); } -inline const float GF_CostDist(int index, int parent, int team, float offset) +inline const float GF_CostNormal(int index, int parent, int team) { - float baseCost = g_exp.GetAStarValue(index, team, true); - - for (int i = 0; i < Const_MaxPathIndex; i++) - { - int neighbour = g_waypoint->GetPath(index)->index[i]; - - if (neighbour != -1) - baseCost += g_exp.GetDamage(neighbour, neighbour, team); - } - float pathDist = g_waypoint->GetPathDistanceFloat(parent, index); - - if (g_waypoint->GetPath(index)->flags & WAYPOINT_CROUCH) - baseCost += pathDist * 2.0f; + float baseCost = g_exp.GetAStarValue(index, team, false); + if (g_waypoint->GetPath(index)->flags & WAYPOINT_LADDER) + baseCost *= 3.0f; - return pathDist + (baseCost * (ebot_dangerfactor.GetFloat() * 2.0f / offset)); + return baseCost / g_waypoint->GetPathDistanceFloat(parent, index); } -inline const float GF_CostNoHostage(int index, int parent, int team, float offset) +inline const float GF_CostRusher(int index, int parent, int team) { - Path* path = g_waypoint->GetPath(index); - - if (path->flags & WAYPOINT_CROUCH) - return 65355.0f; - - if (path->flags & WAYPOINT_LADDER) - return 65355.0f; - - if (path->flags & WAYPOINT_AVOID) - return 65355.0f; - - if (path->flags & WAYPOINT_FALLCHECK) - return 65355.0f; - - if (path->flags & WAYPOINT_JUMP) - return 65355.0f; - - if (path->flags & WAYPOINT_DJUMP) - return 65355.0f; - - for (int i = 0; i < Const_MaxPathIndex; i++) - { - int neighbour = g_waypoint->GetPath(index)->index[i]; - - if (IsValidWaypoint(neighbour) && (path->connectionFlags[neighbour] & PATHFLAG_JUMP || path->connectionFlags[neighbour] & PATHFLAG_DOUBLE)) - return 65355.0f; - } - - float baseCost = g_exp.GetDamage(index, index, team); float pathDist = g_waypoint->GetPathDistanceFloat(parent, index); - - if (g_waypoint->GetPath(index)->flags & WAYPOINT_CROUCH && g_waypoint->GetPath(index)->flags & WAYPOINT_CAMP) - baseCost += pathDist * 2.0f; - - return pathDist + (baseCost * (ebot_dangerfactor.GetFloat() * 2.0f / offset)); + if (g_waypoint->GetPath(index)->flags & WAYPOINT_CROUCH) + pathDist *= 3.0f; + return pathDist; } -inline const float GF_CostNoHostageDist(int index, int parent, int team, float offset) +inline const float GF_CostNoHostage(int index, int parent, int team) { Path* path = g_waypoint->GetPath(index); @@ -894,57 +845,13 @@ inline const float GF_CostNoHostageDist(int index, int parent, int team, float o return 65355.0f; } - float baseCost = g_exp.GetAStarValue(index, team, true); + float baseCost = g_exp.GetDamage(index, index, team); float pathDist = g_waypoint->GetPathDistanceFloat(parent, index); if (g_waypoint->GetPath(index)->flags & WAYPOINT_CROUCH && g_waypoint->GetPath(index)->flags & WAYPOINT_CAMP) - baseCost += pathDist * 2.0f; - - return pathDist + (baseCost * (ebot_dangerfactor.GetFloat() * 2.0f / offset)); -} - -inline const float HF_PathDist(int start, int goal) -{ - Path* pathStart = g_waypoint->GetPath(start); - Path* pathGoal = g_waypoint->GetPath(goal); + baseCost *= 2.0f; - return fabsf(pathGoal->origin.x - pathStart->origin.x) + fabsf(pathGoal->origin.y - pathStart->origin.y) + fabsf(pathGoal->origin.z - pathStart->origin.z); -} - -inline const float HF_NumberNodes(int start, int goal) -{ - return HF_PathDist(start, goal) / 128.0f * g_exp.GetKillHistory(); -} - -inline const float HF_None(int start, int goal) -{ - return HF_PathDist(start, goal) / (128.0f * 100.0f); -} - -inline const float GF_CostZB(int index, int parent, int team, float offset) -{ - float baseCost = g_exp.GetAStarValue(index, team, false); - float pathDist = g_waypoint->GetPathDistanceFloat(parent, index); - - if (g_waypoint->GetPath(index)->flags & WAYPOINT_CROUCH) - baseCost += pathDist * 1.5f; - - return pathDist + (baseCost * (ebot_dangerfactor.GetFloat() * 2.3f / offset)); -} - -inline const float HF_ZB(int start, int goal) -{ - Path* pathStart = g_waypoint->GetPath(start); - Path* pathGoal = g_waypoint->GetPath(goal); - - float xDist = fabsf(pathStart->origin.x - pathGoal->origin.x); - float yDist = fabsf(pathStart->origin.y - pathGoal->origin.y); - float zDist = fabsf(pathStart->origin.z - pathGoal->origin.z); - - if (xDist > yDist) - return 1.4f * yDist + (xDist - yDist) + zDist; - - return 1.4f * xDist + (yDist - xDist) + zDist; + return baseCost / pathDist; } inline const float HF_Distance(int start, int goal) @@ -953,7 +860,7 @@ inline const float HF_Distance(int start, int goal) } // this function finds a path from srcIndex to destIndex -void Bot::FindPath(int srcIndex, int destIndex, uint8_t pathType) +void Bot::FindPath(int srcIndex, int destIndex) { if (m_pathtimer + 1.0 > engine->GetTime()) { @@ -991,8 +898,6 @@ void Bot::FindPath(int srcIndex, int destIndex, uint8_t pathType) m_chosenGoalIndex = srcIndex; m_goalValue = 0.0f; - PriorityQueue openList; - for (int i = 0; i < g_numWaypoints; i++) { waypoints[i].g = 0; @@ -1001,36 +906,36 @@ void Bot::FindPath(int srcIndex, int destIndex, uint8_t pathType) waypoints[i].state = State::New; } - const float (*gcalc) (int, int, int, float) = null; + const float (*gcalc) (int, int, int) = null; const float (*hcalc) (int, int) = null; + hcalc = HF_Distance; - float offset = 1.0f; - - if (m_isZombieBot && m_personality != PERSONALITY_CAREFUL) - { - gcalc = GF_CostZB; - hcalc = HF_ZB; - offset = static_cast (m_skill / 20); - } - else if (pathType == 1) + if (pev->weapons & (1 << WEAPON_C4) || (g_bombPlanted && m_inBombZone)) { - gcalc = HasHostage() ? GF_CostNoHostageDist : GF_CostDist; - hcalc = HF_NumberNodes; - offset = static_cast (m_skill / 25); - } + // move faster... + if (g_timeRoundMid <= engine->GetTime()) + gcalc = GF_CostRusher; + else + gcalc = GF_CostCareful; + } + else if (g_bombPlanted && m_team == TEAM_COUNTER) + gcalc = GF_CostRusher; + else if (HasHostage()) + gcalc = GF_CostNoHostage; + else if (m_personality == PERSONALITY_CAREFUL) + gcalc = GF_CostCareful; + else if (m_personality == PERSONALITY_RUSHER) + gcalc = GF_CostRusher; else - { - gcalc = HasHostage() ? GF_CostNoHostage : GF_Cost; - hcalc = HF_PathDist; - offset = static_cast (m_skill / 20); - } + gcalc = GF_CostNormal; // put start node into open list auto srcWaypoint = &waypoints[srcIndex]; - srcWaypoint->g = gcalc(srcIndex, -1, m_team, offset); + srcWaypoint->g = gcalc(srcIndex, -1, m_team); srcWaypoint->f = srcWaypoint->g + hcalc(srcIndex, destIndex); srcWaypoint->state = State::Open; + PriorityQueue openList; openList.Insert(srcIndex, srcWaypoint->f); while (!openList.Empty()) { @@ -1042,6 +947,7 @@ void Bot::FindPath(int srcIndex, int destIndex, uint8_t pathType) { // build the complete path m_navNode = null; + free(&openList); do { @@ -1077,7 +983,7 @@ void Bot::FindPath(int srcIndex, int destIndex, uint8_t pathType) continue; // calculate the F value as F = G + H - float g = currWaypoint->g + gcalc(self, currentIndex, m_team, offset); + float g = currWaypoint->g + gcalc(self, currentIndex, m_team); float h = hcalc(srcIndex, destIndex); float f = g + h; @@ -1091,7 +997,7 @@ void Bot::FindPath(int srcIndex, int destIndex, uint8_t pathType) childWaypoint->g = g; childWaypoint->f = f; - openList.Insert(self, f); + openList.Insert(self, childWaypoint->f); } } } @@ -1411,7 +1317,6 @@ int Bot::FindWaypoint(void) // to be restarted over again. int busy = -1; - float lessDist[3] = {9999.0f, 9999.0f, 9999.0f}; int lessIndex[3] = {-1, -1, -1}; @@ -1421,7 +1326,6 @@ int Bot::FindWaypoint(void) continue; int numToSkip = engine->RandomInt(0, 2); - bool skip = !!(int(g_waypoint->GetPath(at)->index) == m_currentWaypointIndex); // skip the current node, if any @@ -2457,12 +2361,14 @@ bool Bot::CheckCloseAvoidance(const Vector& dirNormal) int index = m_tasks->data; if (index == -1) index = m_chosenGoalIndex; + if (index == -1) index = m_prevGoalIndex; + if (index != -1) { - FindPath(m_currentWaypointIndex, index, 0); - otherBot->FindPath(m_currentWaypointIndex, index, 0); + FindPath(m_currentWaypointIndex, index); + otherBot->FindPath(m_currentWaypointIndex, index); } } } @@ -2545,7 +2451,7 @@ int Bot::GetCampAimingWaypoint(void) OkWaypoints.Push(i); } - int dangerIndex = g_exp.GetDangerIndex(currentWay, currentWay, TEAM_COUNTER); + int dangerIndex = g_exp.GetDangerIndex(currentWay, currentWay, m_team); if (ChanceOf(20) && IsValidWaypoint(dangerIndex) && IsVisible(g_waypoint->GetPath(dangerIndex)->origin, GetEntity())) return dangerIndex; else if (ChanceOf(20) && IsValidWaypoint(DangerWaypoint) && IsVisible(g_waypoint->GetPath(DangerWaypoint)->origin, GetEntity())) @@ -2558,23 +2464,8 @@ int Bot::GetCampAimingWaypoint(void) return g_waypoint->m_otherPoints.GetRandomElement(); } -// more human like aiming void Bot::FacePosition(void) { - if (!FNullEnt(m_enemy) || !FNullEnt(m_enemyAPI)) - { - if (m_aimstoptime + 0.3f > engine->GetTime()) - m_aimstoptime = engine->GetTime(); - - m_aimstopdelay = IsZombieMode() ? 0.05f : engine->RandomFloat(0.1f, 0.3f); - } - else - m_aimstopdelay = engine->RandomFloat(0.5f, 1.25f); - - // humanize aim, also saving cpu power - if (m_aimstoptime > engine->GetTime()) - return; - if (m_lookAtAPI != nullvec) m_lookAt = m_lookAtAPI; @@ -2590,7 +2481,7 @@ void Bot::FacePosition(void) pev->button |= IN_ATTACK; } - if (pev->button & IN_ATTACK && ebot_aimbot.GetInt() == 1) + if (ebot_aimbot.GetInt() == 1 && pev->button & IN_ATTACK) { pev->v_angle = (m_lookAt - EyePosition()).ToAngles() + pev->punchangle; pev->angles.x = -pev->v_angle.x * (1.0f / 3.0f); @@ -2599,54 +2490,38 @@ void Bot::FacePosition(void) return; } - const float delta = engine->Clamp(engine->GetTime() - m_trackingtime, MATH_EQEPSILON, 0.03333333333f); - m_trackingtime = engine->GetTime(); - - // adjust all body and view angles to face an absolute vector - Vector direction = (m_lookAt - EyePosition()).ToAngles() + pev->punchangle; - direction.x *= -1.0f; // invert for engine - - direction.z = 0; - - float accelerate = float(m_skill * 36); - float stiffness = float(m_skill * 3.3); - float damping = float(m_skill / 3); - - m_idealAngles = pev->v_angle; - - float angleDiffPitch = engine->AngleDiff(direction.x, m_idealAngles.x); - float angleDiffYaw = engine->AngleDiff(direction.y, m_idealAngles.y); - - if (angleDiffYaw < 1.0f && angleDiffYaw > -1.0f) + // predict enemy + if (m_aimFlags & AIM_ENEMY && !FNullEnt(m_enemy)) { - m_lookYawVel = 0.0f; - - // help bot for 100% weapon accurate. - if ((m_isSlowThink && ChanceOf(int((m_skill / 5) + 1))) || IsZombieMode() || m_numFriendsLeft == 0 || m_isLeader || m_isVIP || GetCurrentTask()->taskID == TASK_CAMP) - m_idealAngles.y = direction.y; - - m_aimstoptime = engine->GetTime() + m_aimstopdelay; + float time = engine->GetTime() - m_thinkTimer; + Vector enemyVel = m_enemy->v.avelocity; + enemyVel *= -1.0f; + m_lookAt.x += enemyVel.x * time; + m_lookAt.y += enemyVel.y * time; + m_lookAt.z += enemyVel.z * time; } - else - { - float accel = engine->Clamp(stiffness * angleDiffYaw - damping * m_lookYawVel, -accelerate, accelerate); - m_lookYawVel += delta * accel; - m_idealAngles.y += delta * m_lookYawVel; - } + Vector eye_to_target = (m_lookAt - EyePosition()); + Vector ang_to_target = eye_to_target.ToAngles() + pev->punchangle; + ang_to_target.x *= -1.0f; // invert for engine + Vector eye_ang = pev->v_angle; + Vector eye_forward = (m_lookAt + pev->view_ofs); - float accel = engine->Clamp(2.0f * stiffness * angleDiffPitch - damping * m_lookPitchVel, -accelerate, accelerate); + float max_angvel = m_skill * 10.24f; + float cos_error = GetShootingConeDeviation(GetEntity(), &eye_forward); - m_lookPitchVel += delta * accel; - m_idealAngles.x += engine->Clamp(delta * m_lookPitchVel, -89.0f, 89.0f); + if (cos_error > 0.7f) + max_angvel *= sinf((3.14f / 2.0f) * (1.0f + ((-49.0f / 15.0f) * (cos_error - 0.7f)))); - if (m_idealAngles.x < -89.0f) - m_idealAngles.x = -89.0f; - else if (m_idealAngles.x > 89.0f) - m_idealAngles.x = 89.0f; + if (m_itaimstart != -1 && (engine->GetTime() - m_itaimstart < 0.25f)) + max_angvel *= 4.0f * (engine->GetTime() - m_itaimstart); - pev->v_angle = m_idealAngles; - pev->v_angle.z = 0; + Vector new_eye_angle; + new_eye_angle.x = engine->ApproachAngle(ang_to_target.x, eye_ang.x, (max_angvel * g_pGlobals->frametime) * 0.5); + new_eye_angle.y = engine->ApproachAngle(ang_to_target.y, eye_ang.y, (max_angvel * g_pGlobals->frametime)); + + pev->v_angle = new_eye_angle; + pev->v_angle.ClampAngles(); // set the body angles to point the gun correctly pev->angles.x = -pev->v_angle.x * (1.0f / 3.0f); @@ -2735,10 +2610,7 @@ int Bot::FindLoosedBomb(void) { if (strcmp(STRING(bombEntity->v.model) + 9, "backpack.mdl") == 0) { - // ebot 1.55 - find bomb improve - int nearestIndex = g_waypoint->FindNearest(GetEntityOrigin(bombEntity), 9999.0f, -1, bombEntity); - if (IsValidWaypoint(nearestIndex)) return nearestIndex; else diff --git a/source/support.cpp b/source/support.cpp index 4e6d8edb..3c4d184a 100644 --- a/source/support.cpp +++ b/source/support.cpp @@ -676,9 +676,18 @@ void CreatePath(char* path) #endif } +#include +void cpuid(int info[4], int InfoType) { + __cpuid_count(InfoType, 0, info[0], info[1], info[2], info[3]); +} + // this is called at the start of each round void RoundInit(void) { + int cpuInfo[4]; + cpuid(cpuInfo, 1); + cpuSSESuport = (cpuInfo[3] & ((int)1 << 26)) || false; + g_roundEnded = false; if (GetGameMod() == MODE_BASE) @@ -1017,16 +1026,11 @@ int GetGameMod(void) return ebot_gamemod.GetInt(); } -float sse_rsqrt(float number) -{ - float out; - __m128 in = _mm_load_ss(&number); - _mm_store_ss(&out, _mm_rsqrt_ss(in)); - return out; -} - float Q_rsqrt(float number) { + if (cpuSSESuport) + return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&number))) * number; + long i; float x2, y; const float threehalfs = 1.5F; @@ -1039,6 +1043,13 @@ float Q_rsqrt(float number) return y * number; } +float Clamp(float a, float b, float c) +{ + if (cpuSSESuport) + return _mm_cvtss_f32(_mm_min_ss(_mm_max_ss(_mm_load_ss(&a), _mm_load_ss(&b)), _mm_load_ss(&c))); + return engine->DoClamp(a, b, c); +} + // new get team off set, return player true team int GetTeam(edict_t* ent) { @@ -1528,9 +1539,9 @@ void CheckWelcomeMessage(void) if (receiveTime > 0.0f && receiveTime < engine->GetTime()) { int buildVersion[4] = { PRODUCT_VERSION_DWORD }; - uint16 bV16[4] = { (uint16)buildVersion[0], (uint16)buildVersion[1], (uint16)buildVersion[2], (uint16)buildVersion[3] }; + int bV16[4] = { buildVersion[0], buildVersion[1], buildVersion[2], buildVersion[3] }; - ChartPrint("----- [%s %s] by' %s -----", PRODUCT_NAME, PRODUCT_VERSION, PRODUCT_AUTHOR); + ChartPrint("----- [%s %s] by %s -----", PRODUCT_NAME, PRODUCT_VERSION, PRODUCT_AUTHOR); ChartPrint("***** Build: (%u.%u.%u.%u) *****", bV16[0], bV16[1], bV16[2], bV16[3]); // the api diff --git a/source/waypoint.cpp b/source/waypoint.cpp index dff160c2..1c069366 100644 --- a/source/waypoint.cpp +++ b/source/waypoint.cpp @@ -2255,7 +2255,7 @@ void Waypoint::ShowWaypointMsg(void) float distance = (m_paths[i]->origin - GetEntityOrigin(g_hostEntity)).GetLength(); // check if waypoint is whitin a distance, and is visible - if (distance <= 768 && ((::IsVisible(m_paths[i]->origin, g_hostEntity) && IsInViewCone(m_paths[i]->origin, g_hostEntity)) || !IsAlive(g_hostEntity) || distance <= 512)) + if (distance <= 768 && ((::IsVisible(m_paths[i]->origin, g_hostEntity) && IsInViewCone(m_paths[i]->origin, g_hostEntity)) || distance <= 256)) { // check the distance if (distance < nearestDistance)