diff --git a/source/basecode.cpp b/source/basecode.cpp index 78586f7..f6e1e4d 100644 --- a/source/basecode.cpp +++ b/source/basecode.cpp @@ -25,10 +25,14 @@ // #include +#ifdef WIN32 +#include +#else +#include +#endif // console variables ConVar ebot_debug("ebot_debug", "0"); -ConVar ebot_debuggoal("ebot_debug_goal", "-1"); ConVar ebot_gamemod("ebot_gamemode", "0"); ConVar ebot_followuser("ebot_follow_user_max", "2"); @@ -219,7 +223,7 @@ bool Bot::ItemIsVisible(Vector destination, char* itemName)//, bool bomb) TraceResult tr{}; // trace a line from bot's eyes to destination.. - TraceLine(EyePosition(), destination, true, false, GetEntity(), &tr); + TraceLine(EyePosition(), destination, true, false, pev->pContainingEntity, &tr); // check if line of sight to object is not blocked (i.e. visible) if (tr.flFraction < 1.0f) @@ -250,7 +254,7 @@ bool Bot::EntityIsVisible(Vector dest, bool fromBody) TraceResult tr{}; // trace a line from bot's eyes to destination... - TraceLine(fromBody ? pev->origin - Vector(0.0f, 0.0f, 1.0f) : EyePosition(), dest, true, true, GetEntity(), &tr); + TraceLine(fromBody ? pev->origin - Vector(0.0f, 0.0f, 1.0f) : EyePosition(), dest, true, true, pev->pContainingEntity, &tr); // check if line of sight to object is not blocked (i.e. visible) return tr.flFraction >= 1.0f; @@ -269,13 +273,6 @@ void Bot::ZombieModeAi(void) if (!m_isSlowThink) return; - extern ConVar ebot_random_join_quit; - if (ebot_random_join_quit.GetBool() && m_stayTime > 0.0f && m_stayTime < engine->GetTime() && ChanceOf(25)) - { - Kick(); - return; - } - edict_t* entity = nullptr; if (FNullEnt(m_enemy) && FNullEnt(m_moveTargetEntity)) { @@ -319,10 +316,10 @@ void Bot::ZombieModeAi(void) } else { - if (bot->GetEntity() == targetEnt || m_team != GetTeam(entity)) + if (bot->pev->pContainingEntity == targetEnt || m_team != GetTeam(entity)) continue; - entity = bot->GetEntity(); + entity = bot->pev->pContainingEntity; } } @@ -363,7 +360,7 @@ void Bot::ZmCampPointAction(const int mode) if (mode == 1) { - campAction = CRandomFloat(0.75f, 1.5f); + campAction = crandomfloat(0.75f, 1.5f); campPointWaypointIndex = m_myMeshWaypoint; } else @@ -393,7 +390,7 @@ void Bot::ZmCampPointAction(const int mode) m_checkCampPointTime = 0.0f; else if (m_checkCampPointTime == 0.0f && campAction != 1.0f) m_checkCampPointTime = engine->GetTime() + campAction; - else if (m_checkCampPointTime < engine->GetTime() || campAction == 1.0f || (IsValidWaypoint(m_myMeshWaypoint) && (g_waypoint->GetPath(m_myMeshWaypoint)->origin - pev->origin).GetLengthSquared() <= SquaredF(24.0f))) + else if (m_checkCampPointTime < engine->GetTime() || campAction == 1.0f || (IsValidWaypoint(m_myMeshWaypoint) && (g_waypoint->GetPath(m_myMeshWaypoint)->origin - pev->origin).GetLengthSquared() < squaredf(24.0f))) { m_zhCampPointIndex = campPointWaypointIndex; @@ -402,7 +399,7 @@ void Bot::ZmCampPointAction(const int mode) MakeVectors(pev->v_angle); m_timeCamping = engine->GetTime() + 9999.0f; - PushTask(TASK_CAMP, TASKPRI_CAMP, -1, m_timeCamping, true); + PushTask(TASK_CAMP, TASKPRI_CAMP, m_timeCamping, true); m_aimFlags |= AIM_CAMP; m_campDirection = 0; @@ -455,10 +452,15 @@ bool Bot::IsBehindSmokeClouds(edict_t* ent) int Bot::GetBestWeaponCarried(void) { int* ptr = g_weaponPrefs[m_personality]; + if (ptr == nullptr) + return -1; + int weaponIndex = 0; int weapons = pev->weapons; WeaponSelect* weaponTab = &g_weaponSelect[0]; + if (weaponTab == nullptr) + return -1; // take the shield in account if (HasShield()) @@ -480,6 +482,9 @@ int Bot::GetBestWeaponCarried(void) int Bot::GetBestSecondaryWeaponCarried(void) { int* ptr = g_weaponPrefs[m_personality]; + if (ptr == nullptr) + return -1; + int weaponIndex = 0; int weapons = pev->weapons; @@ -488,12 +493,13 @@ int Bot::GetBestSecondaryWeaponCarried(void) weapons |= (1 << WEAPON_SHIELDGUN); WeaponSelect* weaponTab = &g_weaponSelect[0]; + if (weaponTab == nullptr) + return -1; int i; for (i = 0; i < Const_NumWeapons; i++) { const int id = weaponTab[*ptr].id; - if ((weapons & (1 << static_cast(weaponTab[*ptr].id))) && (id == WEAPON_USP || id == WEAPON_GLOCK18 || id == WEAPON_DEAGLE || id == WEAPON_P228 || id == WEAPON_ELITE || id == WEAPON_FN57)) { weaponIndex = i; @@ -512,11 +518,16 @@ bool Bot::RateGroundWeapon(edict_t* ent) if (FNullEnt(ent)) return false; + int* ptr = g_weaponPrefs[m_personality]; + if (ptr == nullptr) + return -1; + int hasWeapon = 0; int groundIndex = 0; - int* ptr = g_weaponPrefs[m_personality]; WeaponSelect* weaponTab = &g_weaponSelect[0]; + if (weaponTab == nullptr) + return -1; int i; for (i = 0; i < Const_NumWeapons; i++) @@ -552,7 +563,7 @@ edict_t* Bot::FindButton(void) { if (cstrncmp("func_button", STRING(searchEntity->v.classname), 11) == 0 || cstrncmp("func_rot_button", STRING(searchEntity->v.classname), 15) == 0) { - float distance = (pev->origin - GetEntityOrigin(searchEntity)).GetLengthSquared(); + const float distance = (pev->origin - GetEntityOrigin(searchEntity)).GetLengthSquared(); if (distance < nearestDistance) { nearestDistance = distance; @@ -624,7 +635,7 @@ void Bot::FindItem(void) PickupType pickupType = PICKTYPE_NONE; - float minDistance = SquaredF(512.0f); + float minDistance = squaredf(512.0f); while (!FNullEnt(ent = FIND_ENTITY_IN_SPHERE(ent, pev->origin, 512.0f))) { @@ -637,7 +648,7 @@ void Bot::FindItem(void) else if (pev->health < pev->max_health && cstrncmp("func_healthcharger", STRING(ent->v.classname), 18) == 0 && ent->v.frame == 0) { auto origin = GetEntityOrigin(ent); - if (!g_isXash && (pev->origin - origin).GetLengthSquared() < SquaredF(100.0f)) + if (!g_isXash && (pev->origin - origin).GetLengthSquared() < squaredf(100.0f)) MDLL_Use(ent, GetEntity()); m_lookAt = origin; @@ -654,7 +665,7 @@ void Bot::FindItem(void) else if (pev->armorvalue < 100 && cstrncmp("func_recharge", STRING(ent->v.classname), 13) == 0 && ent->v.frame == 0) { auto origin = GetEntityOrigin(ent); - if (!g_isXash && (pev->origin - origin).GetLengthSquared() < SquaredF(100.0f)) + if (!g_isXash && (pev->origin - origin).GetLengthSquared() < squaredf(100.0f)) MDLL_Use(ent, GetEntity()); m_lookAt = origin; @@ -738,7 +749,7 @@ void Bot::FindItem(void) if (cstrncmp("grenade", STRING(ent->v.classname), 7) != 0 || cstrcmp(STRING(ent->v.model) + 9, "c4.mdl") != 0) continue; - if (distance > SquaredF(80.0f)) + if (distance > squaredf(80.0f)) continue; } @@ -801,14 +812,17 @@ void Bot::FindItem(void) m_itemIgnore = ent; allowPickup = false; - if (m_skill > 80 && ChanceOf(50) && GetCurrentTaskID() != TASK_GOINGFORCAMP && GetCurrentTaskID() != TASK_CAMP) + if (m_skill > 80 && chanceof(50) && GetCurrentTaskID() != TASK_GOINGFORCAMP && GetCurrentTaskID() != TASK_CAMP) { - int index = FindDefendWaypoint(entityOrigin); - m_campposition = g_waypoint->GetPath(index)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, ebot_camp_max.GetFloat(), true); - m_campButtons |= IN_DUCK; - - return; + const int index = FindDefendWaypoint(entityOrigin); + if (IsValidWaypoint(index)) + { + m_campposition = g_waypoint->GetPath(index)->origin; + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + ebot_camp_max.GetFloat(), true); + m_campButtons |= IN_DUCK; + return; + } } } else if (pickupType == PICKTYPE_PLANTEDC4) @@ -828,8 +842,8 @@ void Bot::FindItem(void) RemoveCertainTask(TASK_GOINGFORCAMP); m_campposition = g_waypoint->GetPath(index)->origin; - - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, engine->GetTime() + ebot_camp_max.GetFloat(), true); + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + ebot_camp_max.GetFloat(), true); m_campButtons |= IN_DUCK; } else @@ -866,15 +880,17 @@ void Bot::FindItem(void) m_itemIgnore = ent; allowPickup = false; - if (m_skill > 80 && CRandomInt(0, 100) < 90) + if (m_skill > 80 && crandomint(0, 100) < 90) { - int index = FindDefendWaypoint(entityOrigin); - - m_campposition = g_waypoint->GetPath(index)->origin; - - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, engine->GetTime() + ebot_camp_max.GetFloat(), false); - m_campButtons |= IN_DUCK; - return; + const int index = FindDefendWaypoint(entityOrigin); + if (IsValidWaypoint(index)) + { + m_campposition = g_waypoint->GetPath(index)->origin; + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + ebot_camp_max.GetFloat(), false); + m_campButtons |= IN_DUCK; + return; + } } } else if (pickupType == PICKTYPE_PLANTEDC4) @@ -888,17 +904,20 @@ void Bot::FindItem(void) allowPickup = !IsBombDefusing(g_waypoint->GetBombPosition()); if (!m_defendedBomb && !allowPickup) { - m_defendedBomb = true; - - int index = FindDefendWaypoint(entityOrigin); - float timeBlowup = g_timeBombPlanted + engine->GetC4TimerTime() - g_waypoint->GetTravelTime(pev->maxspeed, pev->origin, g_waypoint->GetPath(index)->origin); + const int index = FindDefendWaypoint(entityOrigin); + if (IsValidWaypoint(index)) + { + m_defendedBomb = true; + const float timeBlowup = g_timeBombPlanted + engine->GetC4TimerTime() - g_waypoint->GetTravelTime(pev->maxspeed, pev->origin, g_waypoint->GetPath(index)->origin); - RemoveCertainTask(TASK_MOVETOPOSITION); // remove any move tasks - RemoveCertainTask(TASK_GOINGFORCAMP); + RemoveCertainTask(TASK_MOVETOPOSITION); // remove any move tasks + RemoveCertainTask(TASK_GOINGFORCAMP); - m_campposition = g_waypoint->GetPath(index)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, engine->GetTime() + timeBlowup, true); - m_campButtons &= ~IN_DUCK; + m_campposition = g_waypoint->GetPath(index)->origin; + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + timeBlowup, true); + m_campButtons &= ~IN_DUCK; + } } } } @@ -926,7 +945,7 @@ void Bot::FindItem(void) } } - Vector pickupOrigin = GetEntityOrigin(pickupItem); + const Vector pickupOrigin = GetEntityOrigin(pickupItem); if (pickupOrigin.z > EyePosition().z + 12.0f || IsDeadlyDrop(pickupOrigin)) { m_pickupItem = nullptr; @@ -951,9 +970,9 @@ void Bot::GetCampDirection(Vector* dest) // check if the trace hit something... if (tr.flFraction < 1.0f) { - float length = (tr.vecEndPos - src).GetLengthSquared(); + const float length = (tr.vecEndPos - src).GetLengthSquared(); - if (length > SquaredF(10000.0f)) + if (length > squaredf(10000.0f)) return; int i; @@ -966,7 +985,11 @@ void Bot::GetCampDirection(Vector* dest) // find nearest waypoint to bot and position for (i = 0; i < g_numWaypoints; i++) { - distance = (g_waypoint->GetPath(i)->origin - pev->origin).GetLengthSquared(); + const Path* path = g_waypoint->GetPath(i); + if (path == nullptr) + continue; + + distance = (path->origin - pev->origin).GetLengthSquared(); if (distance < minDistance) { @@ -974,7 +997,7 @@ void Bot::GetCampDirection(Vector* dest) tempIndex = i; } - distance = (g_waypoint->GetPath(i)->origin - *dest).GetLengthSquared(); + distance = (path->origin - *dest).GetLengthSquared(); if (distance < maxDistance) { @@ -986,27 +1009,29 @@ void Bot::GetCampDirection(Vector* dest) if (!IsValidWaypoint(tempIndex) || !IsValidWaypoint(enemyIndex)) return; - minDistance = FLT_MAX; - - int lookAtWaypoint = -1; - Path* path = g_waypoint->GetPath(tempIndex); - - for (i = 0; i < Const_MaxPathIndex; i++) + const Path* path = g_waypoint->GetPath(tempIndex); + if (path != nullptr) { - if (path->index[i] == -1) - continue; - - distance = g_waypoint->GetPathDistance(path->index[i], enemyIndex); + minDistance = FLT_MAX; - if (distance < minDistance) + int lookAtWaypoint = -1; + for (i = 0; i < Const_MaxPathIndex; i++) { - minDistance = distance; - lookAtWaypoint = path->index[i]; + if (path->index[i] == -1) + continue; + + distance = g_waypoint->GetPathDistance(path->index[i], enemyIndex); + + if (distance < minDistance) + { + minDistance = distance; + lookAtWaypoint = path->index[i]; + } } - } - if (IsValidWaypoint(lookAtWaypoint)) - *dest = g_waypoint->GetPath(lookAtWaypoint)->origin; + if (IsValidWaypoint(lookAtWaypoint)) + *dest = g_waypoint->GetPath(lookAtWaypoint)->origin; + } } } @@ -1065,7 +1090,7 @@ void Bot::RadioMessage(int message) } PushMessageQueue(CMENU_RADIO); - m_radiotimer = engine->GetTime() + CRandomFloat(m_numFriendsLeft, m_numFriendsLeft * 1.5f); + m_radiotimer = engine->GetTime() + crandomfloat(m_numFriendsLeft, m_numFriendsLeft * 1.5f); } // this function inserts the voice message into the message queue (mostly same as above) @@ -1116,7 +1141,7 @@ void Bot::PlayChatterMessage(ChatterMessage message) m_lastChatterMessage = message; - m_radiotimer = engine->GetTime() + CRandomFloat(m_numFriendsLeft * 0.5f, m_numFriendsLeft * 1.5f); + m_radiotimer = engine->GetTime() + crandomfloat(m_numFriendsLeft * 0.5f, m_numFriendsLeft * 1.5f); PushMessageQueue(CMENU_RADIO); } @@ -1150,17 +1175,17 @@ void Bot::CheckMessageQueue(void) break; } - m_nextBuyTime = engine->GetTime() + CRandomFloat(0.6f, 1.2f); + m_nextBuyTime = engine->GetTime() + crandomfloat(0.6f, 1.2f); // if freezetime is very low do not delay the buy process - if (CVAR_GET_FLOAT("mp_freezetime") <= 1.0f) - m_nextBuyTime = engine->GetTime() + CRandomFloat(0.25f, 0.5f); + if (CVAR_GET_FLOAT("mp_freezetime") < 2.0f) + m_nextBuyTime = engine->GetTime() + crandomfloat(0.25f, 0.5f); // if fun-mode no need to buy if (ebot_knifemode.GetBool() && (ebot_eco_rounds.GetInt() != 1 || HasPrimaryWeapon())) { m_buyState = 6; - if (ChanceOf(m_skill)) + if (chanceof(m_skill)) SelectKnife(); } @@ -1194,7 +1219,7 @@ void Bot::CheckMessageQueue(void) if (m_buyState > 6) { m_buyingFinished = true; - if (ChanceOf(m_skill)) + if (chanceof(m_skill)) SelectKnife(); return; } @@ -1387,7 +1412,7 @@ void Bot::PerformWeaponPurchase(void) if (gunMode <= BuyWeaponMode(likeGunId[0])) { if ((BuyWeaponMode(likeGunId[1]) > BuyWeaponMode(likeGunId[0])) || - (BuyWeaponMode(likeGunId[1]) == BuyWeaponMode(likeGunId[0]) && (CRandomInt(1, 2) == 2))) + (BuyWeaponMode(likeGunId[1]) == BuyWeaponMode(likeGunId[0]) && (crandomint(1, 2) == 2))) likeGunId[1] = likeGunId[0]; likeGunId[0] = selectedWeapon->id; @@ -1410,7 +1435,7 @@ void Bot::PerformWeaponPurchase(void) WeaponSelect* buyWeapon = &g_weaponSelect[0]; int weaponId = likeGunId[0]; if (likeGunId[1] != 0) - weaponId = likeGunId[(CRandomInt(1, 7) > 3) ? 0 : 1]; + weaponId = likeGunId[(crandomint(1, 7) > 3) ? 0 : 1]; int i; for (i = 0; i < Const_NumWeapons; i++) @@ -1438,7 +1463,7 @@ void Bot::PerformWeaponPurchase(void) break; case 1: - if (pev->armorvalue < CRandomInt(50, 80) && (g_botManager->EconomicsValid(m_team) && HasPrimaryWeapon())) + if (pev->armorvalue < crandomint(50, 80) && (g_botManager->EconomicsValid(m_team) && HasPrimaryWeapon())) { if (m_moneyAmount > 1500 && !IsRestricted(WEAPON_KEVHELM)) FakeClientCommand(GetEntity(), "buyequip;menuselect 2"); @@ -1448,7 +1473,7 @@ void Bot::PerformWeaponPurchase(void) break; case 2: - if ((HasPrimaryWeapon() && m_moneyAmount > CRandomInt(6000, 9000))) + if ((HasPrimaryWeapon() && m_moneyAmount > crandomint(6000, 9000))) { int likeGunId = 0; int loadTime = 0; @@ -1523,17 +1548,17 @@ void Bot::PerformWeaponPurchase(void) break; case 3: - if (!HasPrimaryWeapon() && !ChanceOf(m_skill) && !IsRestricted(WEAPON_SHIELDGUN)) + if (!HasPrimaryWeapon() && !chanceof(m_skill) && !IsRestricted(WEAPON_SHIELDGUN)) { FakeClientCommand(GetEntity(), "buyequip"); FakeClientCommand(GetEntity(), "menuselect 8"); } - if (CRandomInt(1, 2) == 1) + if (crandomint(1, 2) == 1) { FakeClientCommand(GetEntity(), "buy;menuselect 1"); - if (CRandomInt(1, 2) == 1) + if (crandomint(1, 2) == 1) FakeClientCommand(GetEntity(), "menuselect 4"); else FakeClientCommand(GetEntity(), "menuselect 5"); @@ -1542,25 +1567,25 @@ void Bot::PerformWeaponPurchase(void) break; case 4: - if (ChanceOf(m_skill) && !IsRestricted(WEAPON_HEGRENADE)) + if (chanceof(m_skill) && !IsRestricted(WEAPON_HEGRENADE)) { FakeClientCommand(GetEntity(), "buyequip"); FakeClientCommand(GetEntity(), "menuselect 4"); } - if (ChanceOf(m_skill) && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_FBGRENADE)) + if (chanceof(m_skill) && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_FBGRENADE)) { FakeClientCommand(GetEntity(), "buyequip"); FakeClientCommand(GetEntity(), "menuselect 3"); } - if (ChanceOf(m_skill) && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_FBGRENADE)) + if (chanceof(m_skill) && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_FBGRENADE)) { FakeClientCommand(GetEntity(), "buyequip"); FakeClientCommand(GetEntity(), "menuselect 3"); } - if (ChanceOf(m_skill) && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_SMGRENADE)) + if (chanceof(m_skill) && g_botManager->EconomicsValid(m_team) && !IsRestricted(WEAPON_SMGRENADE)) { FakeClientCommand(GetEntity(), "buyequip"); FakeClientCommand(GetEntity(), "menuselect 5"); @@ -1569,7 +1594,7 @@ void Bot::PerformWeaponPurchase(void) break; case 5: - if ((g_mapType & MAP_DE) && m_team == TEAM_COUNTER && ChanceOf(m_skill) && m_moneyAmount > 200 && !IsRestricted(WEAPON_DEFUSER)) + 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"); @@ -1584,10 +1609,10 @@ void Bot::PerformWeaponPurchase(void) { int i; for (i = 0; i <= 5; i++) - FakeClientCommand(GetEntity(), "buyammo%d", CRandomInt(1, 2)); // simulate human + FakeClientCommand(GetEntity(), "buyammo%d", crandomint(1, 2)); // simulate human } - if (ChanceOf(m_skill)) + if (chanceof(m_skill)) FakeClientCommand(GetEntity(), "buy;menuselect 7"); else FakeClientCommand(GetEntity(), "buy;menuselect 6"); @@ -1712,7 +1737,7 @@ void Bot::SetConditions(void) { if (m_skill >= 80) { - m_agressionLevel *= 2; + m_agressionLevel *= 2.0f; m_fearLevel *= 0.5f; } @@ -1756,12 +1781,12 @@ void Bot::SetConditions(void) if (GetTeam(m_lastVictim) != m_team) { // add some aggression because we just killed somebody - m_agressionLevel += 0.1f; + m_agressionLevel += m_frameInterval; if (m_agressionLevel > 1.0f) m_agressionLevel = 1.0f; - if (ChanceOf(50)) + if (chanceof(50)) ChatMessage(CHAT_KILL); else RadioMessage(Radio_EnemyDown); @@ -1799,7 +1824,7 @@ void Bot::SetConditions(void) else if (m_heardSoundTime < engine->GetTime()) m_states &= ~STATE_HEARENEMY; - if (FNullEnt(m_enemy) && !FNullEnt(m_lastEnemy) && m_lastEnemyOrigin != nullvec && !IsZombieMode() && (pev->origin - m_lastEnemyOrigin).GetLengthSquared() < SquaredF(1600.0f)) + if (FNullEnt(m_enemy) && !FNullEnt(m_lastEnemy) && m_lastEnemyOrigin != nullvec && !IsZombieMode() && (pev->origin - m_lastEnemyOrigin).GetLengthSquared() < squaredf(1600.0f)) { TraceResult tr{}; TraceLine(EyePosition(), m_lastEnemyOrigin, true, true, GetEntity(), &tr); @@ -1818,17 +1843,24 @@ void Bot::SetConditions(void) if (m_itemCheckTime < engine->GetTime() || !FNullEnt(m_pickupItem)) { FindItem(); - m_itemCheckTime = engine->GetTime() + g_gameVersion == HALFLIFE ? 1.0f : CRandomInt(2.0f, 4.0f); + m_itemCheckTime = engine->GetTime() + g_gameVersion == HALFLIFE ? 1.0f : crandomint(2.0f, 4.0f); } if (m_isSlowThink) - ApplyTaskFilters(); + { +#ifdef WIN32 + thread core(&Bot::ApplyTaskFilters, this); +#else + cthread core([this]() { this->ApplyTaskFilters(); }); +#endif + core.detach(); + } } +// initialize & calculate the desire for all actions based on distances, emotions and other stuff void Bot::ApplyTaskFilters(void) { - // initialize & calculate the desire for all actions based on distances, emotions and other stuff - GetCurrentTask(); + TaskItem* task = GetCurrentTask(); float tempFear = m_fearLevel; float tempAgression = m_agressionLevel; @@ -1850,7 +1882,7 @@ void Bot::ApplyTaskFilters(void) } // bot found some item to use? - if (!FNullEnt(m_pickupItem) && GetCurrentTaskID() != TASK_ESCAPEFROMBOMB) + if (m_pickupItem != nullptr && GetCurrentTaskID() != TASK_ESCAPEFROMBOMB) { m_states |= STATE_PICKUPITEM; @@ -1858,7 +1890,7 @@ void Bot::ApplyTaskFilters(void) g_taskFilters[TASK_PICKUPITEM].desire = 50.0f; // always pickup button else { - float distance = (500.0f - (GetEntityOrigin(m_pickupItem) - pev->origin).GetLength()) * 0.2f; + float distance = (500.0f - (m_pickupItem->v.origin - pev->origin).GetLength()) * 0.2f; if (distance > 50.0f) distance = 50.0f; @@ -1878,9 +1910,9 @@ void Bot::ApplyTaskFilters(void) g_taskFilters[TASK_FIGHTENEMY].desire = 0.0f; // calculate desires to seek cover or hunt - if (!IsZombieMode() && IsValidPlayer(m_lastEnemy) && m_lastEnemyOrigin != nullvec) + if (!IsZombieMode() && m_lastEnemy != nullptr && m_lastEnemyOrigin != nullvec) { - float distance = (m_lastEnemyOrigin - pev->origin).GetLength(); + const float distance = (m_lastEnemyOrigin - pev->origin).GetLengthSquared(); // retreat level depends on bot health float retreatLevel = (100.0f - (pev->health > 100.0f ? 100.0f : pev->health)) * tempFear; @@ -1904,14 +1936,14 @@ void Bot::ApplyTaskFilters(void) else if (m_isVIP || m_isReloading) ratio *= 3.0f; // triple the seek cover desire if bot is VIP or reloading - if (distance > 500.0f) + if (distance > squaredf(512.0f)) g_taskFilters[TASK_SEEKCOVER].desire = retreatLevel * ratio; // if half of the round is over, allow hunting // FIXME: it probably should be also team/map dependant - if (GetCurrentTaskID() != TASK_ESCAPEFROMBOMB && FNullEnt(m_enemy) && g_timeRoundMid < engine->GetTime() && !m_isUsingGrenade && m_currentWaypointIndex != g_waypoint->FindNearestInCircle(m_lastEnemyOrigin) && m_personality != PERSONALITY_CAREFUL) + if (GetCurrentTaskID() != TASK_ESCAPEFROMBOMB && m_enemy != nullptr && g_timeRoundMid < engine->GetTime() && !m_isUsingGrenade && m_currentWaypointIndex != g_waypoint->FindNearestInCircle(m_lastEnemyOrigin) && m_personality != PERSONALITY_CAREFUL) { - float desireLevel = 4096.0f - ((1.0f - tempAgression) * distance); + float desireLevel = 4096.0f - ((1.0f - tempAgression) * csqrtf(distance)); desireLevel = (100.0f * desireLevel) / 4096.0; desireLevel -= retreatLevel; @@ -1975,12 +2007,12 @@ void Bot::ApplyTaskFilters(void) taskOffensive = SubsumeDesire(taskOffensive, taskPickup); // if offensive task, don't allow picking up stuff TaskItem* taskSub = MaxDesire(taskOffensive, def); // default normal & careful tasks against offensive actions - TaskItem* final = SubsumeDesire(&g_taskFilters[TASK_BLINDED], MaxDesire(taskSurvive, taskSub)); // reason about fleeing instead + TaskItem* finalTask = SubsumeDesire(&g_taskFilters[TASK_BLINDED], MaxDesire(taskSurvive, taskSub)); // reason about fleeing instead if (!m_tasks.IsEmpty()) { - final = MaxDesire(final, GetCurrentTask()); - PushTask(final->id, final->desire, final->data, final->time, final->resume); // push the final behavior in our task stack to carry out + finalTask = MaxDesire(finalTask, task); + PushTask(finalTask->id, finalTask->desire, finalTask->time, finalTask->resume); // push the final behavior in our task stack to carry out } } @@ -1988,9 +2020,10 @@ void Bot::ApplyTaskFilters(void) void Bot::ResetTasks(void) { m_tasks.Destroy(); + TaskCache(); } -void Bot::PushTask(BotTask id, float desire, int data, float time, bool resume, bool force) +void Bot::PushTask(const BotTask id, const float desire, const float time, const bool resume, const bool force) { if (g_gameVersion == HALFLIFE) { @@ -2013,7 +2046,6 @@ void Bot::PushTask(BotTask id, float desire, int data, float time, bool resume, if (!m_tasks.IsEmpty()) { TaskItem& item = m_tasks.Last(); - if (item.id == id) { item.desire = desire; @@ -2022,29 +2054,13 @@ void Bot::PushTask(BotTask id, float desire, int data, float time, bool resume, } TaskItem item; - item.id = id; item.desire = desire; - item.data = data; item.time = time; item.resume = resume; - m_tasks.Push(item); - DeleteSearchNodes(); - IgnoreCollisionShortly(); - - // leader bot? - if (m_isLeader && GetCurrentTaskID() == TASK_SEEKCOVER) - CommandTeam(); // reorganize team if fleeing - - if (GetCurrentTaskID() == TASK_CAMP) - SelectBestWeapon(); - - if (ebot_debuggoal.GetInt() != -1) - m_chosenGoalIndex = ebot_debuggoal.GetInt(); - else - m_chosenGoalIndex = GetCurrentTask()->data; + TaskCache(); } TaskItem* Bot::GetCurrentTask(void) @@ -2055,8 +2071,7 @@ TaskItem* Bot::GetCurrentTask(void) TaskItem task; task.id = TASK_NORMAL; task.desire = TASKPRI_NORMAL; - task.data = -1; - task.time = 0.0f; + task.time = 999999999.0f; task.resume = true; m_tasks.Push(task); } @@ -2065,14 +2080,13 @@ TaskItem* Bot::GetCurrentTask(void) } // this function removes one task from the bot task stack -void Bot::RemoveCertainTask(BotTask id) +void Bot::RemoveCertainTask(const BotTask id) { if (m_tasks.IsEmpty() || (!m_tasks.IsEmpty() && GetCurrentTaskID() == TASK_NORMAL)) return; // since normal task can be only once on the stack, don't remove it... if (GetCurrentTaskID() == id) { - DeleteSearchNodes(); m_tasks.Pop(); return; } @@ -2083,7 +2097,7 @@ void Bot::RemoveCertainTask(BotTask id) m_tasks.RemoveAt(i); } - DeleteSearchNodes(); + TaskCache(); } // this function called whenever a task is completed @@ -2097,34 +2111,27 @@ void Bot::TaskComplete(void) m_tasks.Pop(); } while (!m_tasks.IsEmpty() && !m_tasks.Last().resume); - DeleteSearchNodes(); + TaskCache(); } -BotTask Bot::GetCurrentTaskID(void) +void Bot::TaskCache(void) { - const auto task = GetCurrentTask(); - if (!task) - return BotTask(-1); - - return task->id; + const TaskItem* task = GetCurrentTask(); + if (task != nullptr) + { + m_currentTask = task->id; + m_currentTime = task->time; + } } -int Bot::GetCurrentGoalID(void) +BotTask Bot::GetCurrentTaskID(void) { - const auto task = GetCurrentTask(); - if (!task) - return -1; - - return task->data; + return m_currentTask; } float Bot::GetCurrentTaskTime(void) { - const auto task = GetCurrentTask(); - if (!task) - return -1.0f; - - return task->time; + return m_currentTime; } void Bot::CheckGrenadeThrow(void) @@ -2185,7 +2192,7 @@ void Bot::CheckGrenadeThrow(void) distance = FLT_MAX; // just some crazy value // enemy is within a good throwing distance ? - if (distance > (grenadeToThrow == WEAPON_SMGRENADE ? SquaredF(400.0f) : SquaredF(600.0f)) && distance <= SquaredF(800.0f)) + if (distance > (grenadeToThrow == WEAPON_SMGRENADE ? squaredf(400.0f) : squaredf(600.0f)) && distance < squaredf(800.0f)) { bool allowThrowing = true; @@ -2215,7 +2222,7 @@ void Bot::CheckGrenadeThrow(void) m_throw = g_waypoint->GetPath(searchTab[count--])->origin; Vector src = CheckThrow(EyePosition(), m_throw); - if (src.GetLengthSquared() <= SquaredF(100.0f)) + if (src.GetLengthSquared() < squaredf(100.0f)) src = CheckToss(EyePosition(), m_throw); if (src == nullvec) @@ -2242,7 +2249,7 @@ void Bot::CheckGrenadeThrow(void) } } } - else if (grenadeToThrow == WEAPON_FBGRENADE && (targetOrigin - pev->origin).GetLengthSquared() <= SquaredF(800.0f) && !(m_aimFlags & AIM_ENEMY)) + else if (grenadeToThrow == WEAPON_FBGRENADE && (targetOrigin - pev->origin).GetLengthSquared() <= squaredf(800.0f) && !(m_aimFlags & AIM_ENEMY)) { bool allowThrowing = true; Array inRadius; @@ -2257,7 +2264,7 @@ void Bot::CheckGrenadeThrow(void) m_throw = g_waypoint->GetPath(i)->origin; Vector src = CheckThrow(EyePosition(), m_throw); - if (src.GetLengthSquared() <= SquaredF(100.0f)) + if (src.GetLengthSquared() < squaredf(100.0f)) src = CheckToss(EyePosition(), m_throw); if (src == nullvec) @@ -2274,14 +2281,14 @@ void Bot::CheckGrenadeThrow(void) m_states &= ~STATE_THROWFLASH; } - const float randTime = CRandomFloat(2.0f, 4.0f); + const float randTime = engine->GetTime() + crandomfloat(2.0f, 4.0f); if (m_states & STATE_THROWEXPLODE) - PushTask(TASK_THROWHEGRENADE, TASKPRI_THROWGRENADE, -1, randTime, false); + PushTask(TASK_THROWHEGRENADE, TASKPRI_THROWGRENADE, randTime, false); else if (m_states & STATE_THROWFLASH) - PushTask(TASK_THROWFBGRENADE, TASKPRI_THROWGRENADE, -1, randTime, false); + PushTask(TASK_THROWFBGRENADE, TASKPRI_THROWGRENADE, randTime, false); else if (m_states & STATE_THROWSMOKE) - PushTask(TASK_THROWSMGRENADE, TASKPRI_THROWGRENADE, -1, randTime, false); + PushTask(TASK_THROWSMGRENADE, TASKPRI_THROWGRENADE, randTime, false); } bool Bot::IsOnAttackDistance(edict_t* targetEntity, float distance) @@ -2289,7 +2296,7 @@ bool Bot::IsOnAttackDistance(edict_t* targetEntity, float distance) if (FNullEnt(targetEntity)) return false; - if ((pev->origin - GetEntityOrigin(targetEntity)).GetLengthSquared() < SquaredF(distance)) + if ((pev->origin - GetEntityOrigin(targetEntity)).GetLengthSquared() < squaredf(distance)) return true; return false; @@ -2331,7 +2338,7 @@ bool Bot::ReactOnEnemy(void) if (pev->flags & FL_DUCKING) { - if (enemyDistance < SquaredF(32.0f) || m_navNode.IsEmpty()) + if (enemyDistance < squaredf(32.0f) || m_navNode.IsEmpty()) m_isEnemyReachable = true; pev->speed = pev->maxspeed; @@ -2341,9 +2348,9 @@ bool Bot::ReactOnEnemy(void) } // end of the path, before repathing check the distance if we can reach to enemy - if (!m_navNode.HasNext()) + if (m_navNode.IsEmpty()) { - m_isEnemyReachable = enemyDistance < SquaredF(512.0f); + m_isEnemyReachable = enemyDistance < squaredf(768.0f); if (m_isEnemyReachable) goto last; } @@ -2353,7 +2360,7 @@ bool Bot::ReactOnEnemy(void) if (!(currentWaypoint->flags & WAYPOINT_FALLCHECK) && !(currentWaypoint->flags & WAYPOINT_FALLRISK)) radius += currentWaypoint->radius * 4.0f; - if (enemyDistance < SquaredF(radius)) + if (enemyDistance < squaredf(radius)) { TraceResult tr{}; TraceHull(pev->origin, m_enemyOrigin, true, head_hull, GetEntity(), &tr); @@ -2386,7 +2393,7 @@ bool Bot::ReactOnEnemy(void) const float enemyDistance = (myVec - (enemyHead + enemyVel * m_frameInterval)).GetLengthSquared(); extern ConVar ebot_zp_escape_distance; - const float escapeDist = SquaredF(enemySpeed + ebot_zp_escape_distance.GetFloat()); + const float escapeDist = squaredf(enemySpeed + ebot_zp_escape_distance.GetFloat()); if (pev->flags & FL_DUCKING) // danger... { @@ -2443,9 +2450,9 @@ bool Bot::ReactOnEnemy(void) last: if (!m_isEnemyReachable && (m_isZombieBot || GetCurrentTaskID() != TASK_CAMP)) - m_enemyReachableTimer = engine->GetTime() + CRandomFloat(0.15f, 0.35f); + m_enemyReachableTimer = engine->GetTime() + crandomfloat(0.15f, 0.35f); else - m_enemyReachableTimer = engine->GetTime() + CRandomFloat(0.25f, 0.55f); + m_enemyReachableTimer = engine->GetTime() + crandomfloat(0.25f, 0.55f); } if (m_isEnemyReachable) @@ -2486,7 +2493,7 @@ void Bot::CheckRadioCommands(void) // dynamic range :) // less bots = more teamwork required - if (CRandomFloat(1.0f, 100.0f) <= 1.0f * m_numFriendsLeft * 0.33333333333f) + if (crandomfloat(1.0f, 100.0f) <= 1.0f * m_numFriendsLeft * 0.33333333333f) return; float distance = (GetEntityOrigin(m_radioEntity) - pev->origin).GetLengthSquared(); @@ -2522,8 +2529,7 @@ void Bot::CheckRadioCommands(void) if (taskID == TASK_PAUSE || taskID == TASK_CAMP || taskID == TASK_GOINGFORCAMP) TaskComplete(); - DeleteSearchNodes(); - PushTask(TASK_FOLLOWUSER, TASKPRI_FOLLOWUSER, -1, 20.0f, true); + PushTask(TASK_FOLLOWUSER, TASKPRI_FOLLOWUSER, engine->GetTime() + 20.0f, true); } } else @@ -2543,18 +2549,14 @@ void Bot::CheckRadioCommands(void) if (taskID == TASK_PAUSE || taskID == TASK_CAMP || taskID == TASK_HIDE || taskID == TASK_GOINGFORCAMP) TaskComplete(); - DeleteSearchNodes(); - - PushTask(TASK_FOLLOWUSER, TASKPRI_FOLLOWUSER, -1, 20.0f, true); + PushTask(TASK_FOLLOWUSER, TASKPRI_FOLLOWUSER, engine->GetTime() + 20.0f, true); } else if (FNullEnt(m_enemy) && FNullEnt(m_lastEnemy)) { RadioMessage(Radio_Affirmative); m_position = GetEntityOrigin(m_radioEntity); - - DeleteSearchNodes(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, engine->GetTime() + 10.0f, true); } else RadioMessage(Radio_Negative); @@ -2571,14 +2573,12 @@ void Bot::CheckRadioCommands(void) return; const int campindex = FindDefendWaypoint(GetTopOrigin(m_radioEntity)); - if (!IsValidWaypoint(campindex)) return; m_campposition = g_waypoint->GetPath(campindex)->origin; - - DeleteSearchNodes(); - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, campindex, 9999.0f, true); + m_chosenGoalIndex = campindex; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, 99999999.0f, true); } break; @@ -2591,11 +2591,9 @@ void Bot::CheckRadioCommands(void) if (IsValidWaypoint(index)) { RadioMessage(Radio_Affirmative); - + m_chosenGoalIndex = index; m_campposition = g_waypoint->GetPath(index)->origin; - - DeleteSearchNodes(); - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, 9999.0f, true); + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, 99999999.0f, true); } else RadioMessage(Radio_Negative); @@ -2611,7 +2609,7 @@ void Bot::CheckRadioCommands(void) if (FNullEnt(m_enemy) && m_seeEnemyTime + 10.0f < engine->GetTime()) { // decrease fear levels to lower probability of bot seeking cover again - m_fearLevel -= 0.2f; + m_fearLevel -= 2.0f * m_frameInterval; if (m_fearLevel < 0.0f) m_fearLevel = 0.0f; @@ -2619,9 +2617,7 @@ void Bot::CheckRadioCommands(void) RadioMessage(Radio_Affirmative); m_targetEntity = m_radioEntity; m_position = GetEntityOrigin(m_radioEntity); - - DeleteSearchNodes(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 10.0f, true); + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, engine->GetTime() + 10.0f, true); } else RadioMessage(Radio_Negative); @@ -2639,11 +2635,8 @@ void Bot::CheckRadioCommands(void) else m_position = GetEntityOrigin(m_radioEntity); - if (ChanceOf(50)) - { - DeleteSearchNodes(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); - } + if (chanceof(50)) + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, engine->GetTime() + 10.0f, true); else { const int index = FindDefendWaypoint(m_position); @@ -2651,15 +2644,11 @@ void Bot::CheckRadioCommands(void) if (IsValidWaypoint(index) && !IsWaypointOccupied(index)) { m_campposition = g_waypoint->GetPath(index)->origin; - - DeleteSearchNodes(); - PushTask(TASK_GOINGFORCAMP, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_MOVETOPOSITION, engine->GetTime() + 10.0f, true); } else - { - DeleteSearchNodes(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); - } + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, engine->GetTime() + 10.0f, true); } } @@ -2674,26 +2663,22 @@ void Bot::CheckRadioCommands(void) RadioMessage(Radio_Affirmative); m_position = GetEntityOrigin(m_radioEntity); - - DeleteSearchNodes(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, engine->GetTime() + 10.0f, true); } else if (m_waypointFlags & WAYPOINT_GOAL) // he's in goal waypoint, its danger!!! { RadioMessage(Radio_Affirmative); m_position = GetEntityOrigin(m_radioEntity); - - DeleteSearchNodes(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, engine->GetTime() + 10.0f, true); } break; case Radio_NeedBackup: - if ((FNullEnt(m_enemy) && IsVisible(GetPlayerHeadOrigin(m_radioEntity), GetEntity()) || distance <= SquaredF(1536.0f) || !m_moveToC4) && m_seeEnemyTime + 5.0f <= engine->GetTime()) + if ((FNullEnt(m_enemy) && IsVisible(GetPlayerHeadOrigin(m_radioEntity), GetEntity()) || distance < squaredf(1536.0f) || !m_moveToC4) && m_seeEnemyTime + 5.0f < engine->GetTime()) { - m_fearLevel -= 0.1f; + m_fearLevel -= m_frameInterval; if (m_fearLevel < 0.0f) m_fearLevel = 0.0f; @@ -2702,9 +2687,7 @@ void Bot::CheckRadioCommands(void) m_targetEntity = m_radioEntity; m_position = GetEntityOrigin(m_radioEntity); - - DeleteSearchNodes(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 10.0f, true); + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, engine->GetTime() + 10.0f, true); } else RadioMessage(Radio_Negative); @@ -2717,7 +2700,7 @@ void Bot::CheckRadioCommands(void) RadioMessage(Radio_Affirmative); m_targetEntity = nullptr; - m_fearLevel -= 0.2f; + m_fearLevel -= 2.0f * m_frameInterval; if (m_fearLevel < 0.0f) m_fearLevel = 0.0f; @@ -2725,7 +2708,7 @@ void Bot::CheckRadioCommands(void) if (GetCurrentTaskID() == TASK_CAMP || GetCurrentTaskID() == TASK_PAUSE || GetCurrentTaskID() == TASK_HIDE || GetCurrentTaskID() == TASK_GOINGFORCAMP) TaskComplete(); } - else if (FNullEnt(m_enemy) && IsVisible(GetTopOrigin(m_radioEntity), GetEntity()) || distance <= SquaredF(1536.0f)) + else if (FNullEnt(m_enemy) && IsVisible(GetTopOrigin(m_radioEntity), GetEntity()) || distance < squaredf(1536.0f)) { BotTask taskID = GetCurrentTaskID(); @@ -2733,7 +2716,7 @@ void Bot::CheckRadioCommands(void) { TaskComplete(); - m_fearLevel -= 0.2f; + m_fearLevel -= 2.0f * m_frameInterval; if (m_fearLevel < 0.0f) m_fearLevel = 0.0f; @@ -2741,10 +2724,8 @@ void Bot::CheckRadioCommands(void) RadioMessage(Radio_Affirmative); m_targetEntity = nullptr; - m_position = GetTopOrigin(m_radioEntity) + (m_radioEntity->v.v_angle + (g_pGlobals->v_forward * 20)); - - DeleteSearchNodes(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); + m_position = GetTopOrigin(m_radioEntity) + (m_radioEntity->v.v_angle + (g_pGlobals->v_forward * 24.0f)); + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, 1.0f, true); } } else if (!FNullEnt(m_doubleJumpEntity)) @@ -2758,7 +2739,7 @@ void Bot::CheckRadioCommands(void) break; case Radio_ShesGonnaBlow: - if (FNullEnt(m_enemy) && distance <= SquaredF(2048.0f) && g_bombPlanted && m_team == TEAM_TERRORIST) + if (FNullEnt(m_enemy) && distance <= squaredf(2048.0f) && g_bombPlanted && m_team == TEAM_TERRORIST) { RadioMessage(Radio_Affirmative); @@ -2766,7 +2747,7 @@ void Bot::CheckRadioCommands(void) TaskComplete(); m_targetEntity = nullptr; - PushTask(TASK_ESCAPEFROMBOMB, TASKPRI_ESCAPEFROMBOMB, -1, GetBombTimeleft(), true); + PushTask(TASK_ESCAPEFROMBOMB, TASKPRI_ESCAPEFROMBOMB, engine->GetTime() + GetBombTimeleft(), true); } else RadioMessage(Radio_Negative); @@ -2779,10 +2760,8 @@ void Bot::CheckRadioCommands(void) { SelectKnife(); - DeleteSearchNodes(); - m_position = g_waypoint->GetBombPosition(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, 1.0f, true); RadioMessage(Radio_Affirmative); } @@ -2793,10 +2772,8 @@ void Bot::CheckRadioCommands(void) if (!m_isReloading) SelectBestWeapon(); - DeleteSearchNodes(); - m_position = g_waypoint->GetBombPosition(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, 1.0f, true); RadioMessage(Radio_Affirmative); } @@ -2807,11 +2784,8 @@ void Bot::CheckRadioCommands(void) if (!m_isReloading) SelectBestWeapon(); - DeleteSearchNodes(); - m_position = GetEntityOrigin(m_radioEntity); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); - + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, 1.0f, true); RadioMessage(Radio_Affirmative); } else @@ -2820,7 +2794,7 @@ void Bot::CheckRadioCommands(void) break; case Radio_StormTheFront: - if ((FNullEnt(m_enemy) && IsVisible(GetTopOrigin(m_radioEntity), GetEntity())) || distance < SquaredF(1024.0f)) + if ((FNullEnt(m_enemy) && IsVisible(GetTopOrigin(m_radioEntity), GetEntity())) || distance < squaredf(1024.0f)) { RadioMessage(Radio_Affirmative); @@ -2829,17 +2803,15 @@ void Bot::CheckRadioCommands(void) TaskComplete(); m_targetEntity = nullptr; - m_position = GetEntityOrigin(m_radioEntity) + (m_radioEntity->v.v_angle * CRandomFloat(10.0f, 20.0f)); - - DeleteSearchNodes(); - PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, -1, 1.0f, true); + m_position = GetEntityOrigin(m_radioEntity) + (m_radioEntity->v.v_angle * crandomfloat(10.0f, 20.0f)); + PushTask(TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, 1.0f, true); - m_fearLevel -= 0.3f; + m_fearLevel -= 3.0f * m_frameInterval; if (m_fearLevel < 0.0f) m_fearLevel = 0.0f; - m_agressionLevel += 0.3f; + m_agressionLevel += 3.0f * m_frameInterval; if (m_agressionLevel > 1.0f) m_agressionLevel = 1.0f; @@ -2848,14 +2820,14 @@ void Bot::CheckRadioCommands(void) break; case Radio_Fallback: - if ((FNullEnt(m_enemy) && IsVisible(GetPlayerHeadOrigin(m_radioEntity), GetEntity())) || distance <= SquaredF(1024.0f)) + if ((FNullEnt(m_enemy) && IsVisible(GetPlayerHeadOrigin(m_radioEntity), GetEntity())) || distance < squaredf(1024.0f)) { - m_fearLevel += 0.5f; + m_fearLevel += 5.0f * m_frameInterval; if (m_fearLevel > 1.0f) m_fearLevel = 1.0f; - m_agressionLevel -= 0.5f; + m_agressionLevel -= 5.0f * m_frameInterval; if (m_agressionLevel < 0.0f) m_agressionLevel = 0.0f; @@ -2863,7 +2835,7 @@ void Bot::CheckRadioCommands(void) if (GetCurrentTaskID() == TASK_CAMP && !FNullEnt(m_lastEnemy)) { RadioMessage(Radio_Negative); - GetCurrentTask()->time += CRandomFloat(ebot_camp_min.GetFloat(), ebot_camp_min.GetFloat()); + GetCurrentTask()->time += crandomfloat(ebot_camp_min.GetFloat(), ebot_camp_min.GetFloat()); } else { @@ -2907,11 +2879,12 @@ void Bot::CheckRadioCommands(void) { RadioMessage(Radio_Affirmative); - int seekindex = FindCoverWaypoint(9999.0f); + const int seekindex = FindCoverWaypoint(9999.0f); if (IsValidWaypoint(seekindex)) - PushTask(TASK_SEEKCOVER, TASKPRI_SEEKCOVER, seekindex, 3.0f, true); - - DeleteSearchNodes(); + { + m_chosenGoalIndex = seekindex; + PushTask(TASK_SEEKCOVER, TASKPRI_SEEKCOVER, seekindex, engine->GetTime() + 3.0f, true); + } } } } @@ -2922,7 +2895,7 @@ void Bot::CheckRadioCommands(void) switch (GetCurrentTaskID()) { case TASK_NORMAL: - if (IsValidWaypoint(GetCurrentGoalID())) + if (IsValidWaypoint(m_chosenGoalIndex)) { if (!FNullEnt(m_enemy)) { @@ -2988,9 +2961,9 @@ void Bot::CheckRadioCommands(void) break; default: - if (ChanceOf(15)) + if (chanceof(15)) RadioMessage(Radio_ReportingIn); - else if (ChanceOf(15)) + else if (chanceof(15)) RadioMessage(Radio_FollowMe); else if (m_seeEnemyTime + 10.0f > engine->GetTime()) RadioMessage(Radio_EnemySpotted); @@ -3027,20 +3000,7 @@ void Bot::CheckRadioCommands(void) // mark this waypoint as restricted point if (IsValidWaypoint(bombPoint) && !g_waypoint->IsGoalVisited(bombPoint)) - { - // does this bot want to defuse? - if (GetCurrentTaskID() == TASK_NORMAL) - { - // is he approaching this goal? - if (GetCurrentGoalID() == bombPoint) - { - GetCurrentTask()->data = -1; - RadioMessage(Radio_Affirmative); - } - } - g_waypoint->SetGoalVisited(bombPoint); - } g_timeNextBombUpdate = engine->GetTime() + 1.0f; } @@ -3048,12 +3008,12 @@ void Bot::CheckRadioCommands(void) break; case Radio_GetInPosition: - if ((FNullEnt(m_enemy) && IsVisible(GetTopOrigin(m_radioEntity), GetEntity())) || distance <= SquaredF(1024.0f)) + if ((FNullEnt(m_enemy) && IsVisible(GetTopOrigin(m_radioEntity), GetEntity())) || distance < squaredf(1024.0f)) { RadioMessage(Radio_Affirmative); if (GetCurrentTaskID() == TASK_CAMP) - GetCurrentTask()->time = engine->GetTime() + CRandomFloat(ebot_camp_min.GetFloat(), ebot_camp_max.GetFloat()); + GetCurrentTask()->time = engine->GetTime() + crandomfloat(ebot_camp_min.GetFloat(), ebot_camp_max.GetFloat()); else { BotTask taskID = GetCurrentTaskID(); @@ -3090,13 +3050,12 @@ void Bot::CheckRadioCommands(void) } } - DeleteSearchNodes(); - const int index = FindDefendWaypoint(GetTopOrigin(m_radioEntity)); if (IsValidWaypoint(index)) { m_campposition = g_waypoint->GetPath(index)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, engine->GetTime() + 9999.0f, true); + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + 9999.0f, true); m_campButtons |= IN_DUCK; } } @@ -3122,9 +3081,9 @@ void Bot::SelectLeaderEachTeam(int team) { botLeader->m_isLeader = true; - if (ChanceOf(10)) + if (chanceof(10)) botLeader->PlayChatterMessage(ChatterMessage::Happy); - else if (ChanceOf(40)) + else if (chanceof(40)) botLeader->RadioMessage(Radio_FollowMe); } } @@ -3136,9 +3095,9 @@ void Bot::SelectLeaderEachTeam(int team) { botLeader->m_isLeader = true; - if (ChanceOf(10)) + if (chanceof(10)) botLeader->PlayChatterMessage(ChatterMessage::Happy); - else if (ChanceOf(40)) + else if (chanceof(40)) botLeader->RadioMessage(Radio_FollowMe); } } @@ -3181,7 +3140,7 @@ bool Bot::IsNotAttackLab(edict_t* entity) if (renderamt > 160.0f) return false; - return (SquaredF(renderamt) < (GetEntityOrigin(entity) - pev->origin).GetLengthSquared2D()); + return (squaredf(renderamt) < (GetEntityOrigin(entity) - pev->origin).GetLengthSquared2D()); } return false; @@ -3200,25 +3159,20 @@ void Bot::ChooseAimDirection(void) unsigned int flags = m_aimFlags; - if (!IsValidWaypoint(m_currentWaypointIndex)) - GetValidWaypoint(); - else + if (m_waypointFlags & WAYPOINT_USEBUTTON) { - if (m_waypointFlags & WAYPOINT_USEBUTTON) - { - edict_t* button = FindButton(); - m_aimStopTime = 0.0f; - if (button != nullptr) - m_lookAt = GetEntityOrigin(button); - else - m_lookAt = m_destOrigin + pev->view_ofs; - return; - } - else if (m_isZombieBot && !m_navNode.IsEmpty() && m_waypointFlags & WAYPOINT_ZOMBIEPUSH) - { - m_lookAt = pev->flags & FL_DUCKING ? m_waypointOrigin : m_destOrigin + m_moveAngles * m_frameInterval; - return; - } + edict_t* button = FindButton(); + m_aimStopTime = 0.0f; + if (button != nullptr) + m_lookAt = GetEntityOrigin(button); + else + m_lookAt = m_destOrigin + pev->view_ofs; + return; + } + else if (m_isZombieBot && !m_navNode.IsEmpty() && m_waypointFlags & WAYPOINT_ZOMBIEPUSH) + { + m_lookAt = pev->flags & FL_DUCKING ? m_waypointOrigin : m_destOrigin + m_moveAngles * m_frameInterval; + return; } // check if last enemy vector valid @@ -3226,7 +3180,7 @@ void Bot::ChooseAimDirection(void) { if (m_lastEnemyOrigin != nullvec) { - if (FNullEnt(m_enemy) && (pev->origin - m_lastEnemyOrigin).GetLengthSquared() > SquaredF(1600.0f) && m_seeEnemyTime + 7.0f < engine->GetTime()) + if (FNullEnt(m_enemy) && (pev->origin - m_lastEnemyOrigin).GetLengthSquared() > squaredf(1600.0f) && m_seeEnemyTime + 7.0f < engine->GetTime()) { TraceLine(EyePosition(), m_lastEnemyOrigin, true, true, GetEntity(), &tr); if (!UsesSniper() || (tr.flFraction <= 0.2f && tr.pHit == g_hostEntity)) @@ -3282,16 +3236,16 @@ void Bot::ChooseAimDirection(void) { if (m_seeEnemyTime + 2.0f + m_difficulty > engine->GetTime() && m_lastEnemyOrigin != nullvec) m_camp = m_lastEnemyOrigin; - else if (m_lastEnemyOrigin != nullvec && ChanceOf(30)) + else if (m_lastEnemyOrigin != nullvec && chanceof(30)) m_camp = m_lastEnemyOrigin; else { - int aimIndex = GetCampAimingWaypoint(); + const int aimIndex = GetCampAimingWaypoint(); if (IsValidWaypoint(aimIndex)) m_camp = g_waypoint->GetPath(aimIndex)->origin; } - m_nextCampDirTime = engine->GetTime() + CRandomFloat(1.5f, 5.0f); + m_nextCampDirTime = engine->GetTime() + crandomfloat(1.5f, 5.0f); } m_lookAt = m_camp; @@ -3302,7 +3256,7 @@ void Bot::ChooseAimDirection(void) else if (flags & AIM_PREDICTENEMY) { TraceLine(EyePosition(), m_lastEnemyOrigin, true, true, GetEntity(), &tr); - if (((pev->origin - m_lastEnemyOrigin).GetLengthSquared() < SquaredF(1600.0f) || UsesSniper()) && (tr.flFraction >= 0.2f || tr.pHit != g_worldEdict)) + if (((pev->origin - m_lastEnemyOrigin).GetLengthSquared() < squaredf(1600.0f) || UsesSniper()) && (tr.flFraction >= 0.2f || tr.pHit != g_worldEdict)) { bool recalcPath = true; @@ -3341,9 +3295,9 @@ void Bot::ChooseAimDirection(void) { if (m_seeEnemyTime + 2.0f + m_difficulty > engine->GetTime()) m_camp = m_lastEnemyOrigin; - else if (ChanceOf(30) && IsVisible(m_lastEnemyOrigin, GetEntity())) + else if (chanceof(30) && IsVisible(m_lastEnemyOrigin, GetEntity())) m_camp = m_lastEnemyOrigin; - else if (ChanceOf(30) && IsVisible(m_lastDamageOrigin, GetEntity())) + else if (chanceof(30) && IsVisible(m_lastDamageOrigin, GetEntity())) m_camp = m_lastDamageOrigin; else { @@ -3352,12 +3306,12 @@ void Bot::ChooseAimDirection(void) m_camp = g_waypoint->GetPath(aimIndex)->origin; } - m_nextCampDirTime = engine->GetTime() + CRandomFloat(1.5f, 5.0f); + m_nextCampDirTime = engine->GetTime() + crandomfloat(1.5f, 5.0f); } } else if (m_nextCampDirTime < engine->GetTime()) { - if (m_lastDamageOrigin != nullvec && ChanceOf(30) && IsVisible(m_lastDamageOrigin, GetEntity())) + if (m_lastDamageOrigin != nullvec && chanceof(30) && IsVisible(m_lastDamageOrigin, GetEntity())) m_camp = m_lastDamageOrigin; else { @@ -3367,7 +3321,7 @@ void Bot::ChooseAimDirection(void) } - m_nextCampDirTime = engine->GetTime() + CRandomFloat(1.5f, 5.0f); + m_nextCampDirTime = engine->GetTime() + crandomfloat(1.5f, 5.0f); } m_lookAt = m_camp; @@ -3429,7 +3383,7 @@ void Bot::Think(void) { extern ConVar ebot_stay_min; extern ConVar ebot_stay_max; - m_stayTime = engine->GetTime() + CRandomFloat(ebot_stay_min.GetFloat(), ebot_stay_max.GetFloat()); + m_stayTime = engine->GetTime() + crandomfloat(ebot_stay_min.GetFloat(), ebot_stay_max.GetFloat()); } else m_stayTime = engine->GetTime() + 999999.0f; @@ -3463,12 +3417,8 @@ void Bot::Think(void) if (!FNullEnt(m_lastEnemy) && !IsAlive(m_lastEnemy)) m_lastEnemy = nullptr; - // at least walk randomly - if (!IsZombieMode() && !IsValidWaypoint(GetCurrentGoalID())) - m_chosenGoalIndex = CRandomInt(0, g_numWaypoints - 1); - CalculatePing(); - m_slowthinktimer = engine->GetTime() + CRandomInt(0.9f, 1.1f); + m_slowthinktimer = engine->GetTime() + crandomint(0.9f, 1.1f); } // is bot movement enabled @@ -3478,47 +3428,49 @@ void Bot::Think(void) StartGame(); // select team & class else if (!m_isAlive) { - if (g_gameVersion == HALFLIFE && !(pev->oldbuttons & IN_ATTACK)) - pev->button |= IN_ATTACK; - - extern ConVar ebot_chat; - extern ConVar ebot_random_join_quit; - - if (ebot_random_join_quit.GetBool() && m_stayTime > 0.0f && m_stayTime < engine->GetTime()) + if (m_isSlowThink) { - Kick(); - return; - } + if (g_gameVersion == HALFLIFE && !(pev->oldbuttons & IN_ATTACK)) + pev->button |= IN_ATTACK; - if (ebot_chat.GetBool() && !RepliesToPlayer() && m_lastChatTime + 10.0f < engine->GetTime() && g_lastChatTime + 5.0f < engine->GetTime()) // bot chatting turned on? - { - m_lastChatTime = engine->GetTime(); - if (ChanceOf(ebot_chat_percent.GetInt()) && !g_chatFactory[CHAT_DEAD].IsEmpty()) + extern ConVar ebot_random_join_quit; + if (ebot_random_join_quit.GetBool() && m_stayTime > 1.0f && m_stayTime < engine->GetTime()) { - g_lastChatTime = engine->GetTime(); - - char* pickedPhrase = g_chatFactory[CHAT_DEAD].GetRandomElement(); - bool sayBufferExists = false; + Kick(); + return; + } - // search for last messages, sayed - ITERATE_ARRAY(m_sayTextBuffer.lastUsedSentences, i) + extern ConVar ebot_chat; + if (ebot_chat.GetBool() && !RepliesToPlayer() && m_lastChatTime + 10.0f < engine->GetTime() && g_lastChatTime + 5.0f < engine->GetTime()) // bot chatting turned on? + { + m_lastChatTime = engine->GetTime(); + if (chanceof(ebot_chat_percent.GetInt()) && !g_chatFactory[CHAT_DEAD].IsEmpty()) { - if (cstrncmp(m_sayTextBuffer.lastUsedSentences[i], pickedPhrase, m_sayTextBuffer.lastUsedSentences[i].GetLength()) == 0) - sayBufferExists = true; - } + g_lastChatTime = engine->GetTime(); - if (!sayBufferExists) - { - PrepareChatMessage(pickedPhrase); - PushMessageQueue(CMENU_SAY); + char* pickedPhrase = g_chatFactory[CHAT_DEAD].GetRandomElement(); + bool sayBufferExists = false; - // add to ignore list - m_sayTextBuffer.lastUsedSentences.Push(pickedPhrase); - } + // search for last messages, sayed + ITERATE_ARRAY(m_sayTextBuffer.lastUsedSentences, i) + { + if (cstrncmp(m_sayTextBuffer.lastUsedSentences[i], pickedPhrase, m_sayTextBuffer.lastUsedSentences[i].GetLength()) == 0) + sayBufferExists = true; + } + + if (!sayBufferExists) + { + PrepareChatMessage(pickedPhrase); + PushMessageQueue(CMENU_SAY); + + // add to ignore list + m_sayTextBuffer.lastUsedSentences.Push(pickedPhrase); + } - // clear the used line buffer every now and then - if (m_sayTextBuffer.lastUsedSentences.GetElementNumber() > CRandomInt(4, 6)) - m_sayTextBuffer.lastUsedSentences.Destroy(); + // clear the used line buffer every now and then + if (m_sayTextBuffer.lastUsedSentences.GetElementNumber() > crandomint(4, 6)) + m_sayTextBuffer.lastUsedSentences.Destroy(); + } } } } @@ -3557,23 +3509,23 @@ void Bot::Think(void) if (m_personality == PERSONALITY_RUSHER) m_randomattacktimer = 0.0f; else - m_randomattacktimer = engine->GetTime() + CRandomFloat(0.1f, 10.0f); + m_randomattacktimer = engine->GetTime() + crandomfloat(0.1f, 10.0f); } else if (m_personality == PERSONALITY_RUSHER) - m_randomattacktimer = engine->GetTime() + CRandomFloat(0.1f, 30.0f); + m_randomattacktimer = engine->GetTime() + crandomfloat(0.1f, 30.0f); else if (m_personality == PERSONALITY_CAREFUL) - m_randomattacktimer = engine->GetTime() + CRandomFloat(10.0f, 100.0f); + m_randomattacktimer = engine->GetTime() + crandomfloat(10.0f, 100.0f); else - m_randomattacktimer = engine->GetTime() + CRandomFloat(0.15f, 75.0f); + m_randomattacktimer = engine->GetTime() + crandomfloat(0.15f, 75.0f); if (m_currentWeapon == WEAPON_KNIFE) { - if (CRandomInt(1, 3) == 1) + if (crandomint(1, 3) == 1) pev->button |= IN_ATTACK; else pev->button |= IN_ATTACK2; - if (CRandomInt(1, 10) == 1) + if (crandomint(1, 10) == 1) PlayChatterMessage(ChatterMessage::Happy); } } @@ -3600,15 +3552,15 @@ void Bot::SecondThink(void) if (ebot_use_flare.GetBool() && !m_isReloading && !m_isZombieBot && GetGameMode() == MODE_ZP && FNullEnt(m_enemy) && !FNullEnt(m_lastEnemy)) { - if (pev->weapons & (1 << WEAPON_SMGRENADE) && ChanceOf(40)) - PushTask(TASK_THROWFLARE, TASKPRI_THROWGRENADE, -1, CRandomFloat(0.6f, 0.9f), false); + if (pev->weapons & (1 << WEAPON_SMGRENADE) && chanceof(40)) + PushTask(TASK_THROWFLARE, TASKPRI_THROWGRENADE, engine->GetTime() + crandomfloat(0.6f, 0.9f), false); } // zp & biohazard flashlight support if (ebot_force_flashlight.GetBool() && !m_isZombieBot && !(pev->effects & EF_DIMLIGHT)) pev->impulse = 100; - if (g_bombPlanted && m_team == TEAM_COUNTER && (pev->origin - g_waypoint->GetBombPosition()).GetLengthSquared() < SquaredF(768.0f) && !IsBombDefusing(g_waypoint->GetBombPosition())) + if (g_bombPlanted && m_team == TEAM_COUNTER && (pev->origin - g_waypoint->GetBombPosition()).GetLengthSquared() < squaredf(768.0f) && !IsBombDefusing(g_waypoint->GetBombPosition())) ResetTasks(); } else @@ -3651,7 +3603,7 @@ void Bot::CalculatePing(void) PLAYER_CNX_STATS(client.ent, &ping, &loss); if (ping <= 0 || ping > 150) - ping = CRandomInt(5, 50); + ping = crandomint(5, 50); averagePing += ping; } @@ -3659,14 +3611,14 @@ void Bot::CalculatePing(void) if (numHumans > 0) averagePing /= numHumans; else - averagePing = CRandomInt(30, 60); + averagePing = crandomint(30, 60); - int botPing = m_basePingLevel + CRandomInt(averagePing - averagePing * 0.2f, averagePing + averagePing * 0.2f) + CRandomInt(m_difficulty + 3, m_difficulty + 6); + int botPing = m_basePingLevel + crandomint(averagePing - averagePing * 0.2f, averagePing + averagePing * 0.2f) + crandomint(m_difficulty + 3, m_difficulty + 6); if (botPing <= 9) - botPing = CRandomInt(9, 19); + botPing = crandomint(9, 19); else if (botPing > 133) - botPing = CRandomInt(99, 119); + botPing = crandomint(99, 119); int j; for (j = 0; j < 2; j++) @@ -3715,54 +3667,39 @@ void Bot::MoveAction(void) void Bot::TaskNormal(void) { m_aimFlags |= AIM_NAVPOINT; - const bool cwValid = IsValidWaypoint(m_currentWaypointIndex); if (IsZombieMode()) { // we're stuck while trying reach to human camp waypoint? - if (m_isStuck) + if (m_isStuck && IsValidWaypoint(m_zhCampPointIndex)) { - if (IsValidWaypoint(m_zhCampPointIndex) && (g_waypoint->GetPath(m_zhCampPointIndex)->origin - pev->origin).GetLengthSquared() < SquaredF(8.0f + g_waypoint->GetPath(m_zhCampPointIndex)->radius)) + const Path* pointer = g_waypoint->GetPath(m_zhCampPointIndex); + if (pointer != nullptr && (pointer->origin - pev->origin).GetLengthSquared() < squaredi(8 + pointer->radius)) { - TraceResult tr2; - TraceLine(pev->origin, g_waypoint->GetPath(m_zhCampPointIndex)->origin, false, false, GetEntity(), &tr2); + TraceResult tr{}; + TraceLine(pev->origin, pointer->origin, false, false, pev->pContainingEntity, &tr); // nothing blocking visibility, we can camp at here if we're blocked by own teammates - if (tr2.flFraction == 1.0f) - PushTask(TASK_CAMP, TASKPRI_CAMP, m_zhCampPointIndex, engine->GetTime() + 99999.0f, false); + if (tr.flFraction == 1.0f || (!FNullEnt(tr.pHit) && m_team == GetTeam(tr.pHit))) + { + m_chosenGoalIndex = m_zhCampPointIndex; + PushTask(TASK_CAMP, TASKPRI_CAMP, engine->GetTime() + 99999.0f, true); + } } } } - else if (g_gameVersion == HALFLIFE) + else if (g_gameVersion != HALFLIFE) { if (GetGameMode() == MODE_BASE) { - if (cwValid && (m_waypointFlags & WAYPOINT_CAMP || m_waypointFlags & WAYPOINT_GOAL) && !g_bombPlanted && !HasHostage() && !m_isZombieBot && !m_isBomber && !m_isVIP && ChanceOf(m_personality == PERSONALITY_RUSHER ? 7 : m_personality == PERSONALITY_CAREFUL ? 35 : 15)) + if ((m_waypointFlags & WAYPOINT_CAMP || m_waypointFlags & WAYPOINT_GOAL) && !g_bombPlanted && !HasHostage() && !m_isZombieBot && !m_isBomber && !m_isVIP && chanceof(m_personality == PERSONALITY_RUSHER ? 7 : m_personality == PERSONALITY_CAREFUL ? 35 : 15)) { const int index = FindDefendWaypoint(m_waypoint.origin); if (IsValidWaypoint(index)) { m_campposition = g_waypoint->GetPath(index)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, ebot_camp_max.GetFloat(), false); - } - } - - if (m_team == TEAM_COUNTER) - { - if (g_mapType & MAP_CS) - { - const int hostageWptIndex = FindHostage(); - if (IsValidWaypoint(hostageWptIndex) && m_currentWaypointIndex != hostageWptIndex) - GetCurrentTask()->data = hostageWptIndex; - else // no hostage? search goal waypoints - { - const int goalindex = g_waypoint->m_goalPoints.GetRandomElement(); - if (IsValidWaypoint(goalindex)) - { - if (m_isStuck || m_currentWaypointIndex == goalindex) - GetCurrentTask()->data = goalindex; - } - } + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + ebot_camp_max.GetFloat(), true); } } } @@ -3780,49 +3717,27 @@ void Bot::TaskNormal(void) } // bot hasn't seen anything in a long time and is asking his teammates to report in or sector clear - if ((GetGameMode() == MODE_BASE || GetGameMode() == MODE_TDM) && m_seeEnemyTime != 0.0f && m_seeEnemyTime + CRandomFloat(30.0f, 80.0f) < engine->GetTime() && ChanceOf(70) && g_timeRoundStart + 20.0f < engine->GetTime() && m_askCheckTime + CRandomFloat(20.0, 30.0f) < engine->GetTime()) + if ((GetGameMode() == MODE_BASE || GetGameMode() == MODE_TDM) && m_seeEnemyTime != 0.0f && m_seeEnemyTime + crandomfloat(30.0f, 80.0f) < engine->GetTime() && chanceof(70) && g_timeRoundStart + 20.0f < engine->GetTime() && m_askCheckTime + crandomfloat(20.0, 30.0f) < engine->GetTime()) { m_askCheckTime = engine->GetTime(); - if (ChanceOf(40)) + if (chanceof(40)) RadioMessage(Radio_SectorClear); else RadioMessage(Radio_ReportTeam); } } - // user forced a waypoint as a goal? - if (IsValidWaypoint(ebot_debuggoal.GetInt())) - { - // check if we reached it - if (IsVisible(g_waypoint->GetPath(ebot_debuggoal.GetInt())->origin, GetEntity()) && (m_waypoint.origin - pev->origin).GetLengthSquared() < SquaredF(20.0f) && GetCurrentGoalID() == ebot_debuggoal.GetInt()) - { - m_moveSpeed = 0.0f; - m_strafeSpeed = 0.0f; - - m_checkTerrain = false; - m_moveToGoal = false; - - return; // we can safely return here - } - - if (GetCurrentTask()->data != ebot_debuggoal.GetInt()) - { - DeleteSearchNodes(); - GetCurrentTask()->data = ebot_debuggoal.GetInt(); - } - } - // this also checks bot has shield or not ? if (IsShieldDrawn()) pev->button |= IN_ATTACK2; else { - if (m_currentWeapon == WEAPON_KNIFE && !FNullEnt(m_enemy) && (pev->origin - m_enemyOrigin).GetLengthSquared() < SquaredF(198.0f)) + if (m_currentWeapon == WEAPON_KNIFE && !FNullEnt(m_enemy) && (pev->origin - m_enemyOrigin).GetLengthSquared() < squaredf(198.0f)) { if (m_knifeAttackTime < engine->GetTime()) { KnifeAttack(); - m_knifeAttackTime = engine->GetTime() + CRandomFloat(2.6f, 3.8f); + m_knifeAttackTime = engine->GetTime() + crandomfloat(2.6f, 3.8f); } } else if (m_reloadState == RSTATE_NONE && GetAmmo() != 0) @@ -3833,11 +3748,10 @@ void Bot::TaskNormal(void) if (DoWaypointNav()) { TaskComplete(); - m_prevGoalIndex = -1; // spray logo sometimes if allowed to do so - if (m_timeLogoSpray < engine->GetTime() && ebot_spraypaints.GetBool() && ChanceOf(50) && m_moveSpeed > GetWalkSpeed()) - PushTask(TASK_SPRAYLOGO, TASKPRI_SPRAYLOGO, -1, engine->GetTime() + 1.0f, false); + if (m_timeLogoSpray < engine->GetTime() && ebot_spraypaints.GetBool() && chanceof(50) && m_moveSpeed > GetWalkSpeed()) + PushTask(TASK_SPRAYLOGO, TASKPRI_SPRAYLOGO, engine->GetTime() + 1.0f, false); if (GetGameMode() == MODE_ZP && !m_isZombieBot) ZmCampPointAction(1); @@ -3881,13 +3795,13 @@ void Bot::TaskNormal(void) MakeVectors(pev->v_angle); - m_timeCamping = engine->GetTime() + CRandomFloat(g_skillTab[m_skill / 20].campStartDelay, g_skillTab[m_skill / 20].campEndDelay); - PushTask(TASK_CAMP, TASKPRI_CAMP, -1, m_timeCamping, true); + m_timeCamping = engine->GetTime() + crandomfloat(g_skillTab[m_skill / 20].campStartDelay, g_skillTab[m_skill / 20].campEndDelay); + PushTask(TASK_CAMP, TASKPRI_CAMP, m_timeCamping, true); m_aimFlags |= AIM_CAMP; m_campDirection = 0; // tell the world we're camping - if (ChanceOf(90)) + if (chanceof(90)) RadioMessage(Radio_InPosition); m_moveToGoal = false; @@ -3903,45 +3817,42 @@ void Bot::TaskNormal(void) { if (m_team == TEAM_TERRORIST) { - if (m_skill >= 80 || CRandomInt(0, 100) < m_skill) + if (m_skill >= 80 || crandomint(0, 100) < m_skill) { const int index = FindDefendWaypoint(m_waypoint.origin); if (IsValidWaypoint(index)) { m_campposition = g_waypoint->GetPath(index)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, engine->GetTime() + ebot_camp_max.GetFloat(), true); + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + ebot_camp_max.GetFloat(), true); m_campButtons |= IN_DUCK; } } } else if (m_team == TEAM_COUNTER) { - if (HasHostage()) + // and reached a Rescue Point? + if (m_waypointFlags & WAYPOINT_RESCUE) { - // and reached a Rescue Point? - if (m_waypointFlags & WAYPOINT_RESCUE) + for (auto& hostage : m_hostages) { - int i; - for (i = 0; i < Const_MaxHostages; i++) - { - if (FNullEnt(m_hostages[i])) - continue; + if (FNullEnt(hostage)) + continue; - const Vector origin = GetEntityOrigin(m_hostages[i]); - if (origin == nullvec) - continue; + const Vector origin = GetEntityOrigin(hostage); + if (origin == nullvec) + continue; - const int index = g_waypoint->FindNearest(origin); - if (!IsValidWaypoint(index)) - continue; + const int index = g_waypoint->FindNearestInCircle(origin); + if (!IsValidWaypoint(index)) + continue; - const Path* pointer = g_waypoint->GetPath(index); - if (pointer == nullptr) - continue; + const Path* pointer = g_waypoint->GetPath(index); + if (pointer == nullptr) + continue; - if (pointer->flags & WAYPOINT_RESCUE) - m_hostages[i] = nullptr; - } + if (pointer->flags & WAYPOINT_RESCUE) + hostage = nullptr; } } } @@ -3959,22 +3870,24 @@ void Bot::TaskNormal(void) if (IsValidWaypoint(index)) { m_campposition = g_waypoint->GetPath(index)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, engine->GetTime() + ebot_camp_max.GetFloat(), true); + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + ebot_camp_max.GetFloat(), true); } } else - PushTask(TASK_PLANTBOMB, TASKPRI_PLANTBOMB, -1, 0.0, false); + PushTask(TASK_PLANTBOMB, TASKPRI_PLANTBOMB, 1.0f, false); } else if (m_team == TEAM_COUNTER && m_timeCamping + 10.0f < engine->GetTime()) { - if (!g_bombPlanted && ChanceOf(60) && GetNearbyFriendsNearPosition(pev->origin, 250.0f) < 4) + if (!g_bombPlanted && chanceof(60) && GetNearbyFriendsNearPosition(pev->origin, 250.0f) < 4) { const int index = FindDefendWaypoint(m_waypoint.origin); if (IsValidWaypoint(index)) { - m_timeCamping = engine->GetTime() + CRandomFloat(g_skillTab[m_skill / 20].campStartDelay, g_skillTab[m_skill / 20].campEndDelay); + m_timeCamping = engine->GetTime() + crandomfloat(g_skillTab[m_skill / 20].campStartDelay, g_skillTab[m_skill / 20].campEndDelay); m_campposition = g_waypoint->GetPath(index)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, engine->GetTime() + ebot_camp_max.GetFloat(), true); // push camp task on to stack + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + ebot_camp_max.GetFloat(), true); // push camp task on to stack m_campButtons |= IN_DUCK; } } @@ -3982,33 +3895,23 @@ void Bot::TaskNormal(void) } } } - else if (!GoalIsValid()) // no more nodes to follow - search new ones (or we have a momb) + else if (m_navNode.IsEmpty() || !IsValidWaypoint(m_chosenGoalIndex)) // no more nodes to follow - search new ones (or we have a bomb) { - int destIndex; - - m_moveSpeed = pev->maxspeed; - // did we already decide about a goal before? - if (IsValidWaypoint(GetCurrentGoalID()) && !m_isBomber) - destIndex = GetCurrentGoalID(); + if (m_isBomber && m_waypointFlags & WAYPOINT_GOAL) + m_chosenGoalIndex = m_currentWaypointIndex; else - destIndex = FindGoal(); - - m_prevGoalIndex = destIndex; - - // remember index - GetCurrentTask()->data = destIndex; + m_chosenGoalIndex = FindGoal(); // do pathfinding if it's not the current waypoint - if (IsValidWaypoint(destIndex) && m_currentWaypointIndex != destIndex && m_navNode.IsEmpty()) - FindPath(m_currentWaypointIndex, destIndex); + if (IsValidWaypoint(m_chosenGoalIndex)) + FindPath(m_currentWaypointIndex, m_chosenGoalIndex); } } // this is core function that handle task execution void Bot::RunTask(void) { - int destIndex; Vector src, destination; TraceResult tr{}; @@ -4031,7 +3934,7 @@ void Bot::RunTask(void) if (m_timeLogoSpray < engine->GetTime() && GetCurrentTaskTime() > engine->GetTime()) { MakeVectors(pev->v_angle); - Vector sprayOrigin = EyePosition() + (g_pGlobals->v_forward * 128); + Vector sprayOrigin = EyePosition() + (g_pGlobals->v_forward * 128.0f); TraceLine(EyePosition(), sprayOrigin, true, GetEntity(), &tr); @@ -4049,7 +3952,7 @@ void Bot::RunTask(void) // paint the actual logo decal DecalTrace(pev, &tr, m_logotypeIndex); - m_timeLogoSpray = engine->GetTime() + CRandomFloat(30.0f, 45.0f); + m_timeLogoSpray = engine->GetTime() + crandomfloat(30.0f, 60.0f); } } else @@ -4074,40 +3977,24 @@ void Bot::RunTask(void) { // forget about it... TaskComplete(); - m_prevGoalIndex = -1; - SetLastEnemy(nullptr); } else if (GetTeam(m_lastEnemy) == m_team) - { - // don't hunt down our teammate... RemoveCertainTask(TASK_HUNTENEMY); - m_prevGoalIndex = -1; - } else if (DoWaypointNav()) // reached last enemy pos? { // forget about it... TaskComplete(); - m_prevGoalIndex = -1; - SetLastEnemy(nullptr); } else if (!GoalIsValid()) // do we need to calculate a new path? { - DeleteSearchNodes(); - // is there a remembered index? - if (IsValidWaypoint(GetCurrentGoalID())) - destIndex = GetCurrentGoalID(); - else // no. we need to find a new one - destIndex = GetEntityWaypoint(m_lastEnemy); + if (!IsValidWaypoint(m_chosenGoalIndex)) + m_chosenGoalIndex = GetEntityWaypoint(m_lastEnemy); - // remember index - m_prevGoalIndex = destIndex; - GetCurrentTask()->data = destIndex; - - if (destIndex != m_currentWaypointIndex && IsValidWaypoint(destIndex)) - FindPath(m_currentWaypointIndex, destIndex); + if (IsValidWaypoint(m_chosenGoalIndex)) + FindPath(m_currentWaypointIndex, m_chosenGoalIndex); } // bots skill higher than 50? @@ -4122,13 +4009,10 @@ void Bot::RunTask(void) m_currentWeapon != WEAPON_SHIELDGUN && m_currentWeapon != WEAPON_SMGRENADE) { - if (IsValidWaypoint(m_currentWaypointIndex)) - { - if (m_waypoint.radius < 32 && !IsOnLadder() && !IsInWater() && m_seeEnemyTime + 4.0f > engine->GetTime() && m_skill < 80) - pev->button |= IN_DUCK; - } + if (m_waypoint.radius < 32 && !IsOnLadder() && !IsInWater() && m_seeEnemyTime + 4.0f > engine->GetTime() && m_skill < 80) + pev->button |= IN_DUCK; - if (!FNullEnt(m_lastEnemy) && IsAlive(m_lastEnemy) && (m_lastEnemyOrigin - pev->origin).GetLengthSquared() <= SquaredF(768.0f) && !(pev->flags & FL_DUCKING)) + if (!FNullEnt(m_lastEnemy) && IsAlive(m_lastEnemy) && (m_lastEnemyOrigin - pev->origin).GetLengthSquared() < squaredf(768.0f) && !(pev->flags & FL_DUCKING)) { m_moveSpeed = GetWalkSpeed(); if (m_currentWeapon == WEAPON_KNIFE) @@ -4145,7 +4029,6 @@ void Bot::RunTask(void) if (m_isZombieBot) { TaskComplete(); - m_prevGoalIndex = -1; return; } @@ -4154,10 +4037,8 @@ void Bot::RunTask(void) // yep. activate hide behaviour TaskComplete(); - m_prevGoalIndex = -1; - // start hide task - PushTask(TASK_HIDE, TASKPRI_HIDE, -1, engine->GetTime() + CRandomFloat(6.0f, 12.0f), false); + PushTask(TASK_HIDE, TASKPRI_HIDE, engine->GetTime() + crandomfloat(6.0f, 12.0f), false); destination = m_lastEnemyOrigin; // get a valid look direction @@ -4190,31 +4071,24 @@ void Bot::RunTask(void) } else if (!GoalIsValid()) // we didn't choose a cover waypoint yet or lost it due to an attack? { - if (GetGameMode() != MODE_ZP) - DeleteSearchNodes(); - + m_moveSpeed = 0.0f; + m_strafeSpeed = 0.0f; if (GetGameMode() == MODE_ZP && !m_isZombieBot) { if (FNullEnt(m_enemy) && !g_waypoint->m_zmHmPoints.IsEmpty()) - destIndex = FindGoal(); + m_chosenGoalIndex = FindGoal(); else - destIndex = FindCoverWaypoint(2048.0f); + m_chosenGoalIndex = FindCoverWaypoint(2048.0f); } - else if (IsValidWaypoint(GetCurrentGoalID())) - destIndex = GetCurrentGoalID(); - else - destIndex = FindCoverWaypoint(1024.0f); + else if (!IsValidWaypoint(m_chosenGoalIndex)) + m_chosenGoalIndex = FindCoverWaypoint(1024.0f); - if (!IsValidWaypoint(destIndex)) - destIndex = g_waypoint->FindFarest(pev->origin, 512.0f); + if (!IsValidWaypoint(m_chosenGoalIndex)) + m_chosenGoalIndex = g_waypoint->FindFarest(pev->origin, 512.0f); m_campDirection = 0; - m_prevGoalIndex = destIndex; - - GetCurrentTask()->data = destIndex; - - if (destIndex != m_currentWaypointIndex && IsValidWaypoint(destIndex)) - FindPath(m_currentWaypointIndex, destIndex); + if (IsValidWaypoint(m_chosenGoalIndex)) + FindPath(m_currentWaypointIndex, m_chosenGoalIndex); } break; @@ -4239,7 +4113,6 @@ void Bot::RunTask(void) SetEntityWaypoint(GetEntity()); m_currentWaypointIndex = -1; DeleteSearchNodes(); - GetValidWaypoint(); } TaskComplete(); @@ -4254,7 +4127,6 @@ void Bot::RunTask(void) m_moveToGoal = false; m_checkTerrain = false; - m_navTimeset = engine->GetTime(); m_moveSpeed = 0.0f; m_strafeSpeed = 0.0f; @@ -4262,7 +4134,7 @@ void Bot::RunTask(void) pev->button |= m_campButtons; // stop camping if time over or gets hurt by something else than bullets - if (GetCurrentTaskTime() < engine->GetTime() || m_lastDamageType > 0) + if (GetCurrentTaskTime() < engine->GetTime() || m_lastDamageType > 0 || m_damageTime > engine->GetTime()) TaskComplete(); break; @@ -4277,7 +4149,6 @@ void Bot::RunTask(void) m_moveToGoal = false; m_checkTerrain = false; - m_navTimeset = engine->GetTime(); // if bot remembers last enemy position if (m_skill > 70 && m_lastEnemyOrigin != nullvec && IsValidPlayer(m_lastEnemy) && !UsesSniper()) @@ -4295,9 +4166,8 @@ void Bot::RunTask(void) else { m_moveToGoal = true; - DeleteSearchNodes(); m_campposition = g_waypoint->GetPath(m_blindCampPoint)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, -1, engine->GetTime() + ebot_camp_max.GetFloat(), true); + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + ebot_camp_max.GetFloat(), true); m_blindCampPoint = -1; } @@ -4322,34 +4192,31 @@ void Bot::RunTask(void) return; } - if (DoWaypointNav() && (pev->origin - m_campposition).GetLengthSquared() <= SquaredF(20.0f)) // reached destination? + if (m_navNode.IsEmpty()) { - TaskComplete(); - RemoveCertainTask(TASK_GOINGFORCAMP); // we're done - - if (IsZombieMode()) - PushTask(TASK_CAMP, TASKPRI_CAMP, m_currentWaypointIndex, engine->GetTime() + 99999.0f, false); - else - PushTask(TASK_CAMP, TASKPRI_CAMP, m_currentWaypointIndex, engine->GetTime() + CRandomFloat(ebot_camp_min.GetFloat(), ebot_camp_max.GetFloat()), false); - } - else if (!GoalIsValid()) // didn't choose goal waypoint yet? - { - DeleteSearchNodes(); + if ((pev->origin - m_campposition).GetLengthSquared() < squaredf(24.0f)) + { + TaskComplete(); + RemoveCertainTask(TASK_GOINGFORCAMP); // we're done - if (IsValidWaypoint(GetCurrentGoalID())) - destIndex = GetCurrentGoalID(); + if (IsZombieMode()) + PushTask(TASK_CAMP, TASKPRI_CAMP, engine->GetTime() + 99999.0f, true); + else + PushTask(TASK_CAMP, TASKPRI_CAMP, engine->GetTime() + crandomfloat(ebot_camp_min.GetFloat(), ebot_camp_max.GetFloat()), false); + } else - destIndex = g_waypoint->FindNearest(m_campposition); - - if (IsValidWaypoint(destIndex)) { - m_prevGoalIndex = destIndex; - GetCurrentTask()->data = destIndex; - FindPath(m_currentWaypointIndex, destIndex); + if (!IsValidWaypoint(m_chosenGoalIndex)) + m_chosenGoalIndex = g_waypoint->FindNearestInCircle(m_campposition); + + if (IsValidWaypoint(m_chosenGoalIndex)) + FindPath(m_currentWaypointIndex, m_chosenGoalIndex); + else + TaskComplete(); } - else - TaskComplete(); } + else + DoWaypointNav(); break; @@ -4357,29 +4224,36 @@ void Bot::RunTask(void) case TASK_CAMP: if (GetGameMode() == MODE_BASE && (g_mapType & MAP_DE)) { + if (!CampingAllowed()) + { + TaskComplete(); + return; + } + if (OutOfBombTimer()) { TaskComplete(); - PushTask(TASK_ESCAPEFROMBOMB, TASKPRI_ESCAPEFROMBOMB, -1, 2.0f, true); + PushTask(TASK_ESCAPEFROMBOMB, TASKPRI_ESCAPEFROMBOMB, engine->GetTime() + 2.0f, true); return; } - } - if (!CampingAllowed()) - { - TaskComplete(); - return; + if (m_team == TEAM_COUNTER && m_defendedBomb && !IsBombDefusing(g_waypoint->GetBombPosition())) + { + m_defendedBomb = false; + TaskComplete(); + break; + } } if (IsZombieMode()) { - if (m_isSlowThink && CRandomInt(1, 3) == 1) + if (m_isSlowThink && crandomint(1, 3) == 1) SelectBestWeapon(); m_aimFlags |= AIM_CAMP; // standing still - if (!FNullEnt(m_enemy) && m_currentWeapon != WEAPON_KNIFE && m_personality != PERSONALITY_RUSHER && pev->velocity.GetLengthSquared2D() <= 2.0f) + if (!FNullEnt(m_enemy) && m_currentWeapon != WEAPON_KNIFE && m_personality != PERSONALITY_RUSHER && pev->velocity.GetLengthSquared2D() < 4096.0f) { bool crouch = true; if (m_currentWeapon != WEAPON_M3 || @@ -4391,7 +4265,7 @@ void Bot::RunTask(void) m_currentWeapon != WEAPON_SG550) crouch = false; - if (m_personality == PERSONALITY_NORMAL && (pev->origin - m_enemyOrigin).GetLengthSquared() < SquaredF(m_maxhearrange)) + if (m_personality == PERSONALITY_NORMAL && (pev->origin - m_enemyOrigin).GetLengthSquared() < squaredf(m_maxhearrange)) crouch = false; if (crouch) @@ -4408,17 +4282,6 @@ void Bot::RunTask(void) m_aimFlags |= AIM_CAMP; } - // fix - if (GetGameMode() == MODE_BASE && (g_mapType & MAP_DE)) - { - if (m_team == TEAM_COUNTER && m_defendedBomb && !IsBombDefusing(g_waypoint->GetBombPosition()) && !OutOfBombTimer()) - { - m_defendedBomb = false; - TaskComplete(); - break; - } - } - if (m_isSlowThink && m_seeEnemyTime + 6.0f < engine->GetTime()) { extern ConVar ebot_chat; @@ -4428,137 +4291,74 @@ void Bot::RunTask(void) if (IsZombieMode() && IsValidWaypoint(m_zhCampPointIndex)) { - auto zhPath = g_waypoint->GetPath(m_zhCampPointIndex); - float maxRange = zhPath->flags & WAYPOINT_CROUCH ? 100.0f : 230.0f; - if (zhPath->mesh != 0 && ((zhPath->origin - pev->origin).GetLengthSquared2D() > SquaredF(maxRange) || (zhPath->origin.z - 64.0f > pev->origin.z))) - { - m_zhCampPointIndex = -1; - TaskComplete(); - GetValidWaypoint(); - break; - } - - if (!g_waypoint->m_hmMeshPoints.IsEmpty()) + const Path* zhPath = g_waypoint->GetPath(m_zhCampPointIndex); + if (zhPath != nullptr) { - Array MeshWaypoints; - if (GetCurrentTaskTime() > engine->GetTime() + 60.0f) + const float maxRange = zhPath->flags & WAYPOINT_CROUCH ? 100.0f : 230.0f; + if (zhPath->mesh != 0 && ((zhPath->origin - pev->origin).GetLengthSquared2D() > squaredf(maxRange) || (zhPath->origin.z - 64.0f > pev->origin.z))) { - int i; - for (i = 0; i < g_waypoint->m_hmMeshPoints.GetElementNumber(); i++) - { - int index; - if (!g_waypoint->m_hmMeshPoints.GetAt(i, index)) - continue; - - const Path* pointer = g_waypoint->GetPath(index); - if (pointer == nullptr) - continue; - - if (pointer->mesh == 0) - continue; - - if (zhPath->mesh != pointer->mesh) - continue; - - MeshWaypoints.Push(index); - } + m_zhCampPointIndex = -1; + TaskComplete(); + break; + } - if (!MeshWaypoints.IsEmpty()) + if (!g_waypoint->m_hmMeshPoints.IsEmpty()) + { + Array MeshWaypoints; + if (GetCurrentTaskTime() > engine->GetTime() + 60.0f) { - const int myCampPoint = MeshWaypoints.GetRandomElement(); - m_chosenGoalIndex = myCampPoint; - m_prevGoalIndex = myCampPoint; - m_myMeshWaypoint = myCampPoint; - MeshWaypoints.Destroy(); - - float max = 12.0f; - if (!FNullEnt(m_enemy)) + int i; + for (i = 0; i < g_waypoint->m_hmMeshPoints.GetElementNumber(); i++) { - if (m_personality == PERSONALITY_RUSHER) - max = 16.0f; - else if (m_personality != PERSONALITY_CAREFUL) - max = 8.0f; - } - - GetCurrentTask()->time = engine->GetTime() + CRandomFloat(4.0f, max); - FindPath(m_currentWaypointIndex, m_myMeshWaypoint); - } - } - } - - m_escaped = true; - } - - // half the reaction time if camping because you're more aware of enemies if camping - if (IsZombieMode()) - m_idealReactionTime = 0.0f; - else - m_idealReactionTime = (CRandomFloat(g_skillTab[m_skill / 20].minSurpriseTime, g_skillTab[m_skill / 20].maxSurpriseTime)) * 0.5f; - - if (m_nextCampDirTime < engine->GetTime()) - { - m_nextCampDirTime = engine->GetTime() + CRandomFloat(2.5f, 5.0f); + int index; + if (!g_waypoint->m_hmMeshPoints.GetAt(i, index)) + continue; - if (m_waypointFlags & WAYPOINT_SNIPER) - { - // find a visible waypoint to this direction... - // i know this is ugly hack, but i just don't want to break compatiability - int numFoundPoints = 0; - int foundPoints[3]; - int distanceTab[3]; + const Path* pointer = g_waypoint->GetPath(index); + if (pointer == nullptr) + continue; - Vector dotA = (destination - pev->origin).Normalize2D(); - - int i; - for (i = 0; i < g_numWaypoints; i++) - { - // skip invisible waypoints or current waypoint - if (i == m_currentWaypointIndex || !g_waypoint->IsConnected(m_currentWaypointIndex, i)) - continue; + if (pointer->mesh == 0) + continue; - Vector dotB = (g_waypoint->GetPath(i)->origin - pev->origin).Normalize2D(); + if (zhPath->mesh != pointer->mesh) + continue; - if ((dotA | dotB) > 0.9) - { - int distance = static_cast ((pev->origin - g_waypoint->GetPath(i)->origin).GetLengthSquared()); + MeshWaypoints.Push(index); + } - if (numFoundPoints >= 3) + if (!MeshWaypoints.IsEmpty()) { - for (int j = 0; j < 3; j++) - { - if (distance > distanceTab[j]) - { - distanceTab[j] = distance; - foundPoints[j] = i; + const int myCampPoint = MeshWaypoints.GetRandomElement(); + m_chosenGoalIndex = myCampPoint; + m_myMeshWaypoint = myCampPoint; + MeshWaypoints.Destroy(); - break; - } + float max = 12.0f; + if (!FNullEnt(m_enemy)) + { + if (m_personality == PERSONALITY_RUSHER) + max = 16.0f; + else if (m_personality != PERSONALITY_CAREFUL) + max = 8.0f; } - } - else - { - foundPoints[numFoundPoints] = i; - distanceTab[numFoundPoints] = distance; - numFoundPoints++; + GetCurrentTask()->time = engine->GetTime() + crandomfloat(4.0f, max); + FindPath(m_currentWaypointIndex, m_myMeshWaypoint); } } } - if (--numFoundPoints >= 0) - m_camp = g_waypoint->GetPath(foundPoints[CRandomInt(0, numFoundPoints)])->origin; - else - m_camp = g_waypoint->GetPath(GetCampAimingWaypoint())->origin; - } - else - { - if (!FNullEnt(m_lastEnemy) && IsAlive(m_lastEnemy) && CRandomInt(1, 3) == 1 && IsVisible(m_lastEnemyOrigin, GetEntity())) - m_camp = g_waypoint->GetPath(g_waypoint->FindNearest(m_lastEnemyOrigin))->origin; - else - m_camp = g_waypoint->GetPath(GetCampAimingWaypoint())->origin; + m_escaped = true; } } + // half the reaction time if camping because you're more aware of enemies if camping + if (IsZombieMode()) + m_idealReactionTime = 0.0f; + else + m_idealReactionTime = (crandomfloat(g_skillTab[m_skill / 20].minSurpriseTime, g_skillTab[m_skill / 20].maxSurpriseTime)) * 0.5f; + m_checkTerrain = false; m_moveToGoal = false; @@ -4566,19 +4366,17 @@ void Bot::RunTask(void) m_idealReactionTime *= 0.5f; - m_navTimeset = engine->GetTime(); - m_timeCamping = engine->GetTime(); + m_navTimeset = engine->GetTime() + 2.0f; + m_timeCamping = engine->GetTime() + 2.0f; m_moveSpeed = 0.0f; m_strafeSpeed = 0.0f; - GetValidWaypoint(); - // press remembered crouch button pev->button |= IsZombieMode() ? m_campButtons : IN_DUCK; // stop camping if time over or gets hurt by something else than bullets - if (GetCurrentTaskTime() < engine->GetTime() || m_lastDamageType > 0) + if (!IsZombieMode() && (GetCurrentTaskTime() < engine->GetTime() || m_lastDamageType > 0)) TaskComplete(); break; @@ -4596,14 +4394,12 @@ void Bot::RunTask(void) m_moveToGoal = false; // half the reaction time if camping - m_idealReactionTime = (CRandomFloat(g_skillTab[m_skill / 20].minSurpriseTime, g_skillTab[m_skill / 20].maxSurpriseTime)) * 0.5f; + m_idealReactionTime = (crandomfloat(g_skillTab[m_skill / 20].minSurpriseTime, g_skillTab[m_skill / 20].maxSurpriseTime)) * 0.5f; m_navTimeset = engine->GetTime(); m_moveSpeed = 0; m_strafeSpeed = 0.0f; - GetValidWaypoint(); - if (HasShield() && !m_isReloading) { if (!IsShieldDrawn()) @@ -4618,9 +4414,7 @@ void Bot::RunTask(void) if (!(m_waypointFlags & WAYPOINT_CAMP)) { TaskComplete(); - m_campButtons = 0; - m_prevGoalIndex = -1; if (m_seeEnemyTime + 2.0f > engine->GetTime()) CombatFight(); @@ -4631,9 +4425,7 @@ void Bot::RunTask(void) else if (m_lastEnemyOrigin == nullvec) // If we don't have an enemy we're also free to leave { TaskComplete(); - m_campButtons = 0; - m_prevGoalIndex = -1; if (GetCurrentTaskID() == TASK_HIDE) TaskComplete(); @@ -4665,30 +4457,17 @@ void Bot::RunTask(void) // reached destination? if (DoWaypointNav()) - { TaskComplete(); // we're done - m_prevGoalIndex = -1; - } - - // didn't choose goal waypoint yet? else if (!GoalIsValid()) { - DeleteSearchNodes(); - int forcedestIndex = -1; - int goal = GetCurrentGoalID(); - - if (IsValidWaypoint(goal)) - forcedestIndex = goal; + if (IsValidWaypoint(m_chosenGoalIndex)) + forcedestIndex = m_chosenGoalIndex; else if (m_position != nullvec) - forcedestIndex = g_waypoint->FindNearest(m_position); + forcedestIndex = g_waypoint->FindNearestInCircle(m_position); if (IsValidWaypoint(forcedestIndex)) - { - m_prevGoalIndex = forcedestIndex; - GetCurrentTask()->data = forcedestIndex; FindPath(m_currentWaypointIndex, forcedestIndex); - } else TaskComplete(); } @@ -4729,16 +4508,21 @@ void Bot::RunTask(void) if (m_numFriendsLeft > 0 && GetNearbyFriendsNearPosition(pev->origin, 768.0f) <= 1) RadioMessage(Radio_RegroupTeam); - DeleteSearchNodes(); - - int index = FindDefendWaypoint(pev->origin); - float halfTimer = engine->GetTime() + ((engine->GetC4TimerTime() * 0.5f) + (engine->GetC4TimerTime() * 0.25f)); - - // push camp task on to stack - m_campposition = g_waypoint->GetPath(index)->origin; // required for this task - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, index, halfTimer, true); - m_campButtons |= IN_DUCK; + const int index = FindDefendWaypoint(pev->origin); + if (IsValidWaypoint(index)) + { + const float halfTimer = (engine->GetC4TimerTime() * 0.5f) + (engine->GetC4TimerTime() * 0.25f); + if (halfTimer > 0.0f) + { + // push camp task on to stack + m_campposition = g_waypoint->GetPath(index)->origin; // required for this task + m_chosenGoalIndex = index; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + halfTimer, true); + m_campButtons |= IN_DUCK; + } + } } + break; // bomb defusing behaviour @@ -4791,7 +4575,7 @@ void Bot::RunTask(void) if (m_numEnemiesLeft <= 0) SelectKnife(); - if (((m_entity - pev->origin).GetLengthSquared2D()) < SquaredF(60.0f)) + if (((m_entity - pev->origin).GetLengthSquared2D()) < squaredf(60.0f)) { m_moveToGoal = false; m_checkTerrain = false; @@ -4859,7 +4643,7 @@ void Bot::RunTask(void) if (m_reloadState == RSTATE_NONE && GetAmmo() != 0) m_reloadState = RSTATE_PRIMARY; - if (IsZombieMode() || ((GetEntityOrigin(m_targetEntity) - pev->origin).GetLengthSquared() > SquaredF(80.0f))) + if (IsZombieMode() || ((GetEntityOrigin(m_targetEntity) - pev->origin).GetLengthSquared() > squaredf(80.0f))) m_followWaitTime = 0.0f; else { @@ -4891,33 +4675,24 @@ void Bot::RunTask(void) if (IsShieldDrawn()) pev->button |= IN_ATTACK2; - if (DoWaypointNav()) // reached destination? - GetCurrentTask()->data = -1; - - if (!GoalIsValid()) // didn't choose goal waypoint yet? + if (DoWaypointNav() || m_navNode.IsEmpty()) // didn't choose goal waypoint yet? { - DeleteSearchNodes(); - - destIndex = GetEntityWaypoint(m_targetEntity); + m_chosenGoalIndex = GetEntityWaypoint(m_targetEntity); Array points; - g_waypoint->FindInRadius(points, 200, GetEntityOrigin(m_targetEntity)); + g_waypoint->FindInRadius(points, 200.0f, GetEntityOrigin(m_targetEntity)); while (!points.IsEmpty()) { - int newIndex = points.Pop(); + const int newIndex = points.Pop(); // if waypoint not yet used, assign it as dest - if (IsValidWaypoint(newIndex) && !IsWaypointOccupied(newIndex) && (newIndex != m_currentWaypointIndex)) - destIndex = newIndex; + if (IsValidWaypoint(newIndex) && !IsWaypointOccupied(newIndex)) + m_chosenGoalIndex = newIndex; } - if (IsValidWaypoint(destIndex) && destIndex != m_currentWaypointIndex) - { - m_prevGoalIndex = destIndex; - GetCurrentTask()->data = destIndex; - FindPath(m_currentWaypointIndex, destIndex); - } + if (IsValidWaypoint(m_chosenGoalIndex)) + FindPath(m_currentWaypointIndex, m_chosenGoalIndex); else { m_targetEntity = nullptr; @@ -4927,8 +4702,7 @@ void Bot::RunTask(void) break; case TASK_MOVETOTARGET: - m_moveTargetOrigin = GetEntityOrigin(m_moveTargetEntity); - if (FNullEnt(m_moveTargetEntity) || m_moveTargetOrigin == nullvec || m_team == GetTeam(m_moveTargetEntity)) + if (FNullEnt(m_moveTargetEntity) || m_team == GetTeam(m_moveTargetEntity)) { SetMoveTarget(nullptr); break; @@ -4938,36 +4712,34 @@ void Bot::RunTask(void) SelectBestWeapon(); m_aimFlags |= AIM_NAVPOINT; - m_destOrigin = m_moveTargetOrigin; + m_destOrigin = GetEntityOrigin(m_moveTargetEntity); m_moveSpeed = pev->maxspeed; - if (DoWaypointNav()) - DeleteSearchNodes(); - - destIndex = GetEntityWaypoint(m_moveTargetEntity); + DoWaypointNav(); - if (IsValidWaypoint(destIndex)) + if (!(pev->flags & FL_DUCKING) || m_damageTime + 1.0f < engine->GetTime() || m_navNode.IsEmpty()) { - bool needMoveToTarget = false; - if (!GoalIsValid()) - needMoveToTarget = true; - else if (GetCurrentGoalID() != destIndex) + m_chosenGoalIndex = GetEntityWaypoint(m_moveTargetEntity); + + if (IsValidWaypoint(m_chosenGoalIndex)) { - needMoveToTarget = true; - if (!m_navNode.IsEmpty()) + bool needMoveToTarget = false; + if (!GoalIsValid()) + needMoveToTarget = true; + else if (m_chosenGoalIndex != m_chosenGoalIndex) { - if (m_currentWaypointIndex == destIndex) - needMoveToTarget = false; - else if (m_navNode.Last() == destIndex) - needMoveToTarget = false; + needMoveToTarget = true; + if (!m_navNode.IsEmpty()) + { + if (m_currentWaypointIndex == m_chosenGoalIndex) + needMoveToTarget = false; + else if (m_navNode.Last() == m_chosenGoalIndex) + needMoveToTarget = false; + } } - } - if (needMoveToTarget && (!(pev->flags & FL_DUCKING) || m_damageTime + 0.5f < engine->GetTime() || m_navNode.IsEmpty())) - { - m_prevGoalIndex = destIndex; - GetCurrentTask()->data = destIndex; - FindPath(m_currentWaypointIndex, destIndex); + if (needMoveToTarget) + FindPath(m_currentWaypointIndex, m_chosenGoalIndex); } } @@ -4997,7 +4769,7 @@ void Bot::RunTask(void) m_strafeSpeed = 0.0f; } } - else if (((pev->origin + pev->velocity * m_frameInterval) - m_enemyOrigin).GetLengthSquared() <= SquaredF(cabsf(m_enemy->v.speed) + ebot_zp_escape_distance.GetFloat())) + else if (((pev->origin + pev->velocity * m_frameInterval) - m_enemyOrigin).GetLengthSquared() < squaredf(cabsf(m_enemy->v.speed) + ebot_zp_escape_distance.GetFloat())) { destination = m_enemyOrigin; m_destOrigin = destination; @@ -5018,7 +4790,7 @@ void Bot::RunTask(void) m_moveToGoal = false; } - else if (!FNullEnt(m_enemy) || m_enemyOrigin != nullvec) + else if (!FNullEnt(m_enemy) && m_enemyOrigin != nullvec) destination = m_enemyOrigin + (m_enemy->v.velocity.SkipZ() * 0.54f); else m_enemy = m_lastEnemy; @@ -5026,7 +4798,7 @@ void Bot::RunTask(void) m_isUsingGrenade = true; m_checkTerrain = false; - if (!IsZombieMode() && ((pev->origin + pev->velocity * m_frameInterval) - destination).GetLengthSquared() <= SquaredF(400.0f)) + if (!IsZombieMode() && ((pev->origin + pev->velocity * m_frameInterval) - destination).GetLengthSquared() < squaredf(400.0f)) { // heck, I don't wanna blow up myself m_grenadeCheckTime = engine->GetTime() + Const_GrenadeTimer; @@ -5039,10 +4811,10 @@ void Bot::RunTask(void) m_grenade = CheckThrow(EyePosition(), destination); - if (m_grenade.GetLengthSquared() <= SquaredF(100.0f)) + if (m_grenade.GetLengthSquared() < squaredf(100.0f)) m_grenade = CheckToss(EyePosition(), destination); - if (!IsZombieMode() && m_grenade != nullvec && m_grenade.GetLengthSquared() <= SquaredF(100.0f)) + if (!IsZombieMode() && m_grenade != nullvec && m_grenade.GetLengthSquared() < squaredf(100.0f)) { m_grenadeCheckTime = engine->GetTime() + Const_GrenadeTimer; m_grenade = m_lookAt; @@ -5059,7 +4831,7 @@ void Bot::RunTask(void) if (ent->v.owner == GetEntity() && cstrcmp(STRING(ent->v.model) + 9, "hegrenade.mdl") == 0) { // set the correct velocity for the grenade - if (m_grenade != nullvec && m_grenade.GetLengthSquared() >= SquaredF(100.0f)) + if (m_grenade != nullvec && m_grenade.GetLengthSquared() > squaredf(100.0f)) ent->v.velocity = m_grenade; m_grenadeCheckTime = engine->GetTime() + Const_GrenadeTimer; @@ -5113,7 +4885,7 @@ void Bot::RunTask(void) m_strafeSpeed = 0.0f; } } - else if (((pev->origin + pev->velocity * m_frameInterval) - m_enemyOrigin).GetLengthSquared() <= SquaredF(cabsf(m_enemy->v.speed) + ebot_zp_escape_distance.GetFloat())) + else if (((pev->origin + pev->velocity * m_frameInterval) - m_enemyOrigin).GetLengthSquared() < squaredf(cabsf(m_enemy->v.speed) + ebot_zp_escape_distance.GetFloat())) { destination = m_enemyOrigin; m_destOrigin = destination; @@ -5134,7 +4906,7 @@ void Bot::RunTask(void) m_moveToGoal = false; } - else if (!FNullEnt(m_enemy) || m_enemyOrigin != nullvec) + else if (!FNullEnt(m_enemy) && m_enemyOrigin != nullvec) destination = m_enemyOrigin + (m_enemy->v.velocity.SkipZ() * 0.54f); else m_enemy = m_lastEnemy; @@ -5144,10 +4916,10 @@ void Bot::RunTask(void) m_grenade = CheckThrow(EyePosition(), destination); - if (m_grenade.GetLengthSquared() <= SquaredF(100.0f)) + if (m_grenade.GetLengthSquared() < squaredf(100.0f)) m_grenade = CheckToss(pev->origin, destination); - if (!IsZombieMode() && m_grenade != nullvec && m_grenade.GetLengthSquared() <= SquaredF(100.0f)) + if (!IsZombieMode() && m_grenade != nullvec && m_grenade.GetLengthSquared() < squaredf(100.0f)) { m_grenadeCheckTime = engine->GetTime() + Const_GrenadeTimer; m_grenade = m_lookAt; @@ -5163,7 +4935,7 @@ void Bot::RunTask(void) if (ent->v.owner == GetEntity() && cstrcmp(STRING(ent->v.model) + 9, "flashbang.mdl") == 0) { // set the correct velocity for the grenade - if (m_grenade != nullvec && m_grenade.GetLengthSquared() >= SquaredF(100.0f)) + if (m_grenade != nullvec && m_grenade.GetLengthSquared() > squaredf(100.0f)) ent->v.velocity = m_grenade; m_grenadeCheckTime = engine->GetTime() + Const_GrenadeTimer; @@ -5218,7 +4990,7 @@ void Bot::RunTask(void) m_moveToGoal = false; } - else if (((pev->origin + pev->velocity * m_frameInterval) - m_enemyOrigin).GetLengthSquared() <= SquaredF(cabsf(m_enemy->v.speed) + ebot_zp_escape_distance.GetFloat())) + else if (((pev->origin + pev->velocity * m_frameInterval) - m_enemyOrigin).GetLengthSquared() < squaredf(cabsf(m_enemy->v.speed) + ebot_zp_escape_distance.GetFloat())) { destination = m_enemyOrigin; m_destOrigin = destination; @@ -5238,7 +5010,7 @@ void Bot::RunTask(void) m_strafeSpeed = 0.0f; m_moveToGoal = false; } - else if (!FNullEnt(m_enemy) || m_enemyOrigin != nullvec) + else if (!FNullEnt(m_enemy) && m_enemyOrigin != nullvec) destination = m_enemyOrigin + (m_enemy->v.velocity.SkipZ() * 0.54f); else m_enemy = m_lastEnemy; @@ -5248,16 +5020,15 @@ void Bot::RunTask(void) m_grenade = CheckThrow(EyePosition(), destination); - // dammit + // i hate this... { edict_t* ent = nullptr; - while (!FNullEnt(ent = FIND_ENTITY_BY_CLASSNAME(ent, "grenade"))) { if (ent->v.owner == GetEntity() && cstrcmp(STRING(ent->v.model) + 9, "smokegrenade.mdl") == 0) { // set the correct velocity for the grenade - if (m_grenade != nullvec && m_grenade.GetLengthSquared() >= SquaredF(100.0f)) + if (m_grenade != nullvec && m_grenade.GetLengthSquared() > squaredf(100.0f)) ent->v.velocity = m_grenade; m_grenadeCheckTime = engine->GetTime() + Const_GrenadeTimer; @@ -5284,7 +5055,6 @@ void Bot::RunTask(void) } pev->button |= m_campButtons; - break; case TASK_THROWFLARE: @@ -5303,7 +5073,7 @@ void Bot::RunTask(void) m_moveToGoal = false; } - else if (!FNullEnt(m_enemy) || m_enemyOrigin != nullvec) + else if (!FNullEnt(m_enemy) && m_enemyOrigin != nullvec) destination = m_enemyOrigin + (m_enemy->v.velocity.SkipZ() * 0.54f); m_isUsingGrenade = true; @@ -5311,10 +5081,10 @@ void Bot::RunTask(void) m_grenade = CheckThrow(EyePosition(), destination); - if (m_grenade.GetLengthSquared() <= SquaredF(100.0)) + if (m_grenade.GetLengthSquared() < squaredf(100.0f)) m_grenade = CheckToss(EyePosition(), destination); - if (!IsZombieMode() && m_grenade != nullvec && m_grenade.GetLengthSquared() <= SquaredF(100.0)) + if (!IsZombieMode() && m_grenade != nullvec && m_grenade.GetLengthSquared() < squaredf(100.0f)) { m_grenadeCheckTime = engine->GetTime() + Const_GrenadeTimer; m_grenade = m_lookAt; @@ -5331,7 +5101,7 @@ void Bot::RunTask(void) if (ent->v.owner == GetEntity() && cstrcmp(STRING(ent->v.model) + 9, "smokegrenade.mdl") == 0) { // set the correct velocity for the grenade - if (m_grenade != nullvec && m_grenade.GetLengthSquared() >= SquaredF(100.0f)) + if (m_grenade != nullvec && m_grenade.GetLengthSquared() > squaredf(100.0f)) ent->v.velocity = m_grenade; m_grenadeCheckTime = engine->GetTime() + Const_GrenadeTimer; @@ -5396,7 +5166,7 @@ void Bot::RunTask(void) if (trc.flFraction < 1.0f && trc.pHit == m_doubleJumpEntity && inJump) { - m_duckForJump = engine->GetTime() + CRandomFloat(3.0f, 5.0f); + m_duckForJump = engine->GetTime() + crandomfloat(3.0f, 5.0f); GetCurrentTask()->time = engine->GetTime(); } @@ -5413,21 +5183,16 @@ void Bot::RunTask(void) if (m_currentWaypointIndex == m_prevGoalIndex) m_destOrigin = m_doubleJumpOrigin; - if (DoWaypointNav()) - GetCurrentTask()->data = -1; + DoWaypointNav(); // didn't choose goal waypoint yet? if (!GoalIsValid()) { - DeleteSearchNodes(); - - const int boostIndex = g_waypoint->FindNearest(m_doubleJumpOrigin); + const int boostIndex = g_waypoint->FindNearestInCircle(m_doubleJumpOrigin); if (IsValidWaypoint(boostIndex)) { - m_prevGoalIndex = boostIndex; m_travelStartIndex = m_currentWaypointIndex; - GetCurrentTask()->data = boostIndex; // always take the shortest path FindPath(m_currentWaypointIndex, boostIndex); @@ -5455,17 +5220,13 @@ void Bot::RunTask(void) pev->button |= IN_ATTACK2; } - PushTask(TASK_PAUSE, TASKPRI_CAMP, -1, engine->GetTime() + 10.0f, true); + PushTask(TASK_PAUSE, TASKPRI_CAMP, engine->GetTime() + 10.0f, true); } else if (!GoalIsValid()) { if (m_numEnemiesLeft <= 0) SelectKnife(); - destIndex = -1; - - DeleteSearchNodes(); - float safeRadius = 2048.0f, minPathDistance = 4096.0f; int i; for (i = 0; i < g_numWaypoints; i++) @@ -5474,24 +5235,21 @@ void Bot::RunTask(void) if (pointer == nullptr) continue; - if ((pointer->origin - g_waypoint->GetBombPosition()).GetLengthSquared() < SquaredF(safeRadius)) + if ((pointer->origin - g_waypoint->GetBombPosition()).GetLengthSquared() < squaredf(safeRadius)) continue; const float pathDistance = g_waypoint->GetPathDistance(m_currentWaypointIndex, i); if (minPathDistance > pathDistance) { minPathDistance = pathDistance; - destIndex = i; + m_chosenGoalIndex = i; } } - if (IsValidWaypoint(destIndex)) - destIndex = g_waypoint->FindFarest(pev->origin, safeRadius); + if (!IsValidWaypoint(m_chosenGoalIndex)) + m_chosenGoalIndex = g_waypoint->FindFarest(pev->origin, safeRadius); - m_prevGoalIndex = destIndex; - GetCurrentTask()->data = destIndex; - - FindPath(m_currentWaypointIndex, destIndex); + FindPath(m_currentWaypointIndex, m_chosenGoalIndex); } break; @@ -5585,7 +5343,7 @@ void Bot::RunTask(void) m_aimFlags |= AIM_NAVPOINT; // near to weapon? - if (itemDistance < SquaredF(60.0f)) + if (itemDistance < squaredf(60.0f)) { int i; for (i = 0; i < 7; i++) @@ -5632,14 +5390,11 @@ void Bot::RunTask(void) CheckSilencer(); // check the silencer - if (IsValidWaypoint(m_currentWaypointIndex)) + if (itemDistance > squaredf(m_waypoint.radius)) { - if (itemDistance > SquaredF(m_waypoint.radius)) - { - SetEntityWaypoint(GetEntity()); - m_currentWaypointIndex = -1; - GetValidWaypoint(); - } + SetEntityWaypoint(GetEntity()); + m_currentWaypointIndex = -1; + GetValidWaypoint(); } } @@ -5653,7 +5408,7 @@ void Bot::RunTask(void) m_pickupItem = nullptr; break; } - else if (itemDistance < SquaredF(60.0f)) // near to shield? + else if (itemDistance < squaredf(60.0f)) // near to shield? { // get current best weapon to check if it's a primary in need to be dropped const int weaponID = GetHighestWeapon(); @@ -5663,14 +5418,11 @@ void Bot::RunTask(void) SelectWeaponbyNumber(weaponID); FakeClientCommand(GetEntity(), "drop"); - if (IsValidWaypoint(m_currentWaypointIndex)) + if (itemDistance > squaredf(m_waypoint.radius)) { - if (itemDistance > SquaredF(m_waypoint.radius)) - { - SetEntityWaypoint(GetEntity()); - m_currentWaypointIndex = -1; - GetValidWaypoint(); - } + SetEntityWaypoint(GetEntity()); + m_currentWaypointIndex = -1; + GetValidWaypoint(); } } } @@ -5679,10 +5431,10 @@ void Bot::RunTask(void) case PICKTYPE_PLANTEDC4: m_aimFlags |= AIM_ENTITY; - if (m_team == TEAM_COUNTER && itemDistance < SquaredF(80.0f)) + if (m_team == TEAM_COUNTER && itemDistance < squaredf(80.0f)) { // notify team of defusing - if (m_numFriendsLeft >= 1) + if (m_numFriendsLeft > 0) RadioMessage(Radio_CoverMe); m_moveToGoal = false; @@ -5691,7 +5443,7 @@ void Bot::RunTask(void) m_moveSpeed = 0.0f; m_strafeSpeed = 0.0f; - PushTask(TASK_DEFUSEBOMB, TASKPRI_DEFUSEBOMB, -1, 0.0, false); + PushTask(TASK_DEFUSEBOMB, TASKPRI_DEFUSEBOMB, 1.0f, false); } break; @@ -5710,7 +5462,7 @@ void Bot::RunTask(void) break; } - if (itemDistance < SquaredF(60.0f)) + if (itemDistance < squaredf(60.0f)) { // use game dll function to make sure the hostage is correctly 'used' if (g_isXash) @@ -5761,7 +5513,7 @@ void Bot::RunTask(void) src = EyePosition(); const float angleToEntity = InFieldOfView(destination - src); - if (itemDistance < SquaredF(90.0f)) // near to the button? + if (itemDistance < squaredf(90.0f)) // near to the button? { m_moveSpeed = 0.0f; m_strafeSpeed = 0.0f; @@ -5790,25 +5542,24 @@ void Bot::RunTask(void) void Bot::DebugModeMsg(void) { - int debugMode = ebot_debug.GetInt(); + const int debugMode = ebot_debug.GetInt(); if (FNullEnt(g_hostEntity) || debugMode <= 0 || debugMode == 2) return; static float timeDebugUpdate = 0.0f; - int specIndex = g_hostEntity->v.iuser2; + const int specIndex = g_hostEntity->v.iuser2; if (specIndex != ENTINDEX(GetEntity())) return; static int index, goal, taskID; - if (GetCurrentTask() != nullptr) { - if (taskID != GetCurrentTask()->id || index != m_currentWaypointIndex || goal != GetCurrentTask()->data || timeDebugUpdate < engine->GetTime()) + if (taskID != GetCurrentTask()->id || index != m_currentWaypointIndex || goal != m_chosenGoalIndex || timeDebugUpdate < engine->GetTime()) { taskID = GetCurrentTask()->id; index = m_currentWaypointIndex; - goal = GetCurrentTask()->data; + goal = m_chosenGoalIndex; char taskName[80]; @@ -6009,7 +5760,7 @@ void Bot::DebugModeMsg(void) "Type: %s Money: %d Bot AI: %s \n" "Enemy%s Pickup: %s \n\n" - "CurrentIndex: %d GoalIndex: %d TD: %d \n" + "CurrentIndex: %d PrevGoalIndex: %d GoalIndex: %d \n" "Nav: %d Next Nav: %d \n" "GEWI: %d GEWI2: %d \n" "Move Speed: %2.f Strafe Speed: %2.f \n " @@ -6020,7 +5771,7 @@ void Bot::DebugModeMsg(void) botType, m_moneyAmount, m_isZombieBot ? "Zombie" : "Normal", enemyName, pickName, - m_currentWaypointIndex, m_prevGoalIndex, GetCurrentTask()->data, + m_currentWaypointIndex, m_prevGoalIndex, goal, m_navNode.IsEmpty() ? -1 : m_navNode.First(), (!m_navNode.IsEmpty() && m_navNode.HasNext()) ? m_navNode.Next() : -1, g_clients[client].wpIndex, g_clients[client].wpIndex2, m_moveSpeed, m_strafeSpeed, @@ -6093,8 +5844,7 @@ void Bot::BotAI(void) m_moveToGoal = true; m_wantsToFire = false; - static float movedDistance; // length of different vector (distance bot moved) - TraceResult tr{}; + float movedDistance = 2; // length of different vector (distance bot moved) // increase reaction time m_actualReactionTime += 2.0f * m_frameInterval; @@ -6107,11 +5857,12 @@ void Bot::BotAI(void) if (m_prevTime < engine->GetTime()) { // see how far bot has moved since the previous position... - movedDistance = (m_prevOrigin - pev->origin).GetLengthSquared(); + if (m_checkTerrain) + movedDistance = (m_prevOrigin - pev->origin).GetLengthSquared2D(); // save current position as previous m_prevOrigin = pev->origin; - m_prevTime = engine->GetTime() + 0.5f; + m_prevTime = engine->GetTime() + 0.2f; } // do all sensing, calculate/filter all actions here @@ -6131,7 +5882,7 @@ void Bot::BotAI(void) CheckReload(); // set the reaction time (surprise momentum) different each frame according to skill - m_idealReactionTime = CRandomFloat(g_skillTab[m_skill / 20].minSurpriseTime, g_skillTab[m_skill / 20].maxSurpriseTime); + m_idealReactionTime = crandomfloat(g_skillTab[m_skill / 20].minSurpriseTime, g_skillTab[m_skill / 20].maxSurpriseTime); const float inter = (m_frameInterval + g_pGlobals->frametime) * 0.5f; const Vector directionOld = (m_destOrigin + pev->velocity * -inter) - (pev->origin + pev->velocity * inter); @@ -6180,22 +5931,22 @@ void Bot::BotAI(void) if (m_radioOrder != 0) CheckRadioCommands(); - if (m_checkKnifeSwitch && m_buyingFinished && m_spawnTime + CRandomFloat(4.0f, 8.0f) < engine->GetTime()) + if (m_checkKnifeSwitch && m_buyingFinished && m_spawnTime + crandomfloat(4.0f, 8.0f) < engine->GetTime()) { m_checkKnifeSwitch = false; if (!IsZombieMode()) { - if (ebot_spraypaints.GetBool() && CRandomInt(1, 10) < 2) - PushTask(TASK_SPRAYLOGO, TASKPRI_SPRAYLOGO, -1, engine->GetTime() + 1.0f, false); + if (ebot_spraypaints.GetBool() && crandomint(1, 10) < 2) + PushTask(TASK_SPRAYLOGO, TASKPRI_SPRAYLOGO, engine->GetTime() + 1.0f, false); - if (!IsDeathmatchMode() && ChanceOf(m_personality == PERSONALITY_RUSHER ? 99 : m_personality == PERSONALITY_CAREFUL ? 33 : 66) && !m_isReloading && (g_mapType & (MAP_CS | MAP_DE | MAP_ES | MAP_AS))) + if (!IsDeathmatchMode() && chanceof(m_personality == PERSONALITY_RUSHER ? 99 : m_personality == PERSONALITY_CAREFUL ? 33 : 66) && !m_isReloading && (g_mapType & (MAP_CS | MAP_DE | MAP_ES | MAP_AS))) SelectKnife(); } } // check if we already switched weapon mode - if (m_checkWeaponSwitch && m_buyingFinished && m_spawnTime + CRandomFloat(2.0f, 3.5f) < engine->GetTime()) + if (m_checkWeaponSwitch && m_buyingFinished && m_spawnTime + crandomfloat(2.0f, 3.5f) < engine->GetTime()) { if (IsShieldDrawn()) pev->button |= IN_ATTACK2; @@ -6210,7 +5961,7 @@ void Bot::BotAI(void) case WEAPON_FAMAS: case WEAPON_GLOCK18: - if (ChanceOf(50)) + if (chanceof(50)) pev->button |= IN_ATTACK2; break; } @@ -6247,7 +5998,7 @@ void Bot::BotAI(void) // allowed to move to a destination position? if (m_moveToGoal) { - if (IsValidWaypoint(m_currentWaypointIndex) && m_waypointFlags & WAYPOINT_WAITUNTIL) + if (m_waypointFlags & WAYPOINT_WAITUNTIL) { TraceResult tr{}; TraceLine(m_waypoint.origin, m_waypoint.origin - Vector(0.0f, 0.0f, 60.0f), false, false, GetEntity(), &tr); @@ -6260,8 +6011,6 @@ void Bot::BotAI(void) } } - GetValidWaypoint(); - // time to reach waypoint if (m_navTimeset + GetEstimatedReachTime() < engine->GetTime()) { @@ -6286,7 +6035,7 @@ void Bot::BotAI(void) // use button waypoints if (m_waypointFlags & WAYPOINT_USEBUTTON) { - if ((pev->origin - m_waypoint.origin).GetLengthSquared() < SquaredF(80.0f)) + if ((pev->origin - m_waypoint.origin).GetLengthSquared() < squaredf(80.0f)) { if (g_isXash) { @@ -6321,17 +6070,19 @@ void Bot::BotAI(void) if (m_checkTerrain) { + TraceResult tr{}; + m_isStuck = false; CheckCloseAvoidance(directionNormal); // for rebuild path - if (!FNullEnt(m_avoid) && m_isStuck && IsValidWaypoint(m_currentWaypointIndex) && m_waypointFlags & WAYPOINT_ONLYONE) + if (!FNullEnt(m_avoid) && m_isStuck && m_waypointFlags & WAYPOINT_ONLYONE) FindPath(m_currentWaypointIndex, FindWaypoint(false)); - const float minSpeed = pev->flags & FL_DUCKING ? 4.0f : 10.0f; + const float minSpeed = pev->flags & FL_DUCKING ? 4.0f : 12.0f; if ((m_moveSpeed < -minSpeed || m_moveSpeed > minSpeed || m_strafeSpeed > minSpeed || m_strafeSpeed < -minSpeed) && m_lastCollTime < engine->GetTime()) { - if (m_damageTime >= engine->GetTime()) + if (m_damageTime > engine->GetTime()) { m_lastCollTime = m_damageTime + 0.5f; m_firstCollideTime = 0.0f; @@ -6339,7 +6090,7 @@ void Bot::BotAI(void) } else { - if (movedDistance < 2.0f && m_prevSpeed > 20.0f) + if (movedDistance < 2.0f && (m_prevSpeed > 20.0f || cabsf(m_prevVelocity.GetLength2D()) < (m_moveSpeed * 0.5f))) { m_prevTime = engine->GetTime(); m_isStuck = true; @@ -6353,9 +6104,9 @@ void Bot::BotAI(void) if (!IsOnLadder() && CantMoveForward(directionNormal, &tr)) { if (m_firstCollideTime == 0.0f) - m_firstCollideTime = engine->GetTime() + 0.5f; + m_firstCollideTime = engine->GetTime() + 0.2f; - else if (m_firstCollideTime <= engine->GetTime()) + else if (m_firstCollideTime < engine->GetTime()) m_isStuck = true; } else @@ -6367,11 +6118,11 @@ void Bot::BotAI(void) if (!m_isStuck) // not stuck? { // boosting improve - if (m_isZombieBot && m_waypointFlags & WAYPOINT_DJUMP && IsOnFloor() && ((pev->origin - m_waypoint.origin).GetLengthSquared() <= SquaredF(50.0f))) + if (m_isZombieBot && m_waypointFlags & WAYPOINT_DJUMP && IsOnFloor() && ((pev->origin - m_waypoint.origin).GetLengthSquared() < squaredf(54.0f))) pev->button |= IN_DUCK; else { - if (m_probeTime + 0.5f < engine->GetTime()) + if (m_probeTime + 1.0f < engine->GetTime()) ResetCollideState(); // reset collision memory if not being stuck for 0.5 secs else { @@ -6383,31 +6134,25 @@ void Bot::BotAI(void) } else { - Vector src, dest; - - if (!IsValidWaypoint(m_currentWaypointIndex)) - { - DeleteSearchNodes(); - m_currentWaypointIndex = g_waypoint->FindNearest(pev->origin, 9999.0f, -1, GetEntity()); - } - else if (!IsVisible(m_waypoint.origin, GetEntity())) - DeleteSearchNodes(); + GetValidWaypoint(); // not yet decided what to do? if (m_collisionState == COSTATE_UNDECIDED) { - int bits = 0; + uint32_t bits = 0; if (IsOnLadder()) bits |= COPROBE_STRAFE; else if (IsInWater()) bits |= (COPROBE_JUMP | COPROBE_STRAFE); else - bits |= (COPROBE_STRAFE | (ChanceOf(35) ? COPROBE_JUMP : 0)); + bits |= (COPROBE_STRAFE | (chanceof(35) ? COPROBE_JUMP : 0)); // collision check allowed if not flying through the air if (IsOnFloor() || IsOnLadder() || IsInWater()) { + Vector src, dest; + int state[8]; int i = 0; @@ -6438,13 +6183,13 @@ void Bot::BotAI(void) else dirLeft = true; - const Vector& testDir = m_moveSpeed > 0.0f ? g_pGlobals->v_forward : -g_pGlobals->v_forward; + const Vector testDir = m_moveSpeed > 0.0f ? g_pGlobals->v_forward : -g_pGlobals->v_forward; // now check which side is blocked src = pev->origin + g_pGlobals->v_right * 32.0f; dest = src + testDir * 32.0f; - TraceHull(src, dest, true, head_hull, GetEntity(), &tr); + TraceHull(src, dest, true, head_hull, pev->pContainingEntity, &tr); if (tr.flFraction != 1.0f) blockedRight = true; @@ -6452,7 +6197,7 @@ void Bot::BotAI(void) src = pev->origin - g_pGlobals->v_right * 32.0f; dest = src + testDir * 32.0f; - TraceHull(src, dest, true, head_hull, GetEntity(), &tr); + TraceHull(src, dest, true, head_hull, pev->pContainingEntity, &tr); if (tr.flFraction != 1.0f) blockedLeft = true; @@ -6492,16 +6237,16 @@ void Bot::BotAI(void) MakeVectors(m_moveAngles); src = EyePosition(); - src = src + g_pGlobals->v_right * 30.0f; + src = src + g_pGlobals->v_right * 16.0f; - TraceLine(src, m_destOrigin, true, true, GetEntity(), &tr); + TraceHull(src, m_destOrigin, true, point_hull, pev->pContainingEntity, &tr); if (tr.flFraction >= 1.0f) { src = EyePosition(); - src = src - g_pGlobals->v_right * 30.0f; + src = src - g_pGlobals->v_right * 16.0f; - TraceLine(src, m_destOrigin, true, true, GetEntity(), &tr); + TraceHull(src, m_destOrigin, true, point_hull, pev->pContainingEntity, &tr); if (tr.flFraction >= 1.0f) state[i] += 5; @@ -6513,16 +6258,29 @@ void Bot::BotAI(void) else src = pev->origin + Vector(0.0f, 0.0f, -17.0f); - dest = src + directionNormal * 60.0f; - TraceLine(src, dest, true, true, GetEntity(), &tr); + dest = src + directionNormal * 32.0f; + TraceHull(src, dest, true, point_hull, pev->pContainingEntity, &tr); if (tr.flFraction != 1.0f) state[i] += 10; } else state[i] = 0; + i++; - state[i] = 0; + + if (bits & COPROBE_DUCK) + { + state[i] = 0; + if (CanDuckUnder(directionNormal)) + state[i] += 10; + + if ((m_destOrigin.z + 36.0f <= pev->origin.z) && IsVisible(m_destOrigin, pev->pContainingEntity)) + state[i] += 5; + } + else + state[i] = 0; + i++; // weighted all possible moves, now sort them to start with most probable @@ -6581,8 +6339,11 @@ void Bot::BotAI(void) { case COSTATE_JUMP: if (IsOnFloor() || IsInWater()) + { if (IsInWater() || !m_isZombieBot || m_damageTime < engine->GetTime() || m_currentTravelFlags & PATHFLAG_JUMP || KnifeAttack()) pev->button |= IN_JUMP; + } + break; @@ -6609,8 +6370,42 @@ void Bot::BotAI(void) else m_isStuck = false; + // save the previous speed (for checking if stuck) + m_prevSpeed = cabsf(m_moveSpeed); + m_prevVelocity = pev->velocity; + m_lastDamageType = -1; // reset damage + + if (!m_jumpFinished) + { + // when fool bot enters pause after jump velocity still goes for a second... this is for reduce bot's fall chance (just think like a surfing, bot must instantly stop for pervent falling of the cliff due of velocity) + if (m_jumping && IsOnFloor()) + { + m_moveSpeed = 0.0f; + m_strafeSpeed = 0.0f; + + if (!(pev->flags & FL_DUCKING)) + { + m_jumpFinished = true; + m_jumping = false; + pev->speed = 0.0f; + pev->velocity = nullvec; + return; + } + + // remove duck buttons and the flag to avoid ducking on air animation + pev->button &= ~(IN_DUCK | IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT); + pev->oldbuttons &= ~(IN_DUCK | IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT); + } + + if (!IsOnFloor()) + { + pev->button |= IN_DUCK; + m_jumping = true; + } + } + bool OnLadderNoDuck = false; - if (IsOnLadder() || (IsValidWaypoint(m_currentWaypointIndex) && m_waypointFlags & WAYPOINT_LADDER)) + if (IsOnLadder() || m_waypointFlags & WAYPOINT_LADDER) { if (!(m_waypointFlags & WAYPOINT_CROUCH)) OnLadderNoDuck = true; @@ -6623,40 +6418,6 @@ void Bot::BotAI(void) } else if (m_duckTime > engine->GetTime()) pev->button |= IN_DUCK; - - if (pev->button & IN_JUMP) - { - if (m_currentTravelFlags & PATHFLAG_JUMP) - { - Vector point1Origin, point2Origin; - if (IsValidWaypoint(m_prevWptIndex)) - point1Origin = g_waypoint->GetPath(m_prevWptIndex)->origin; - else if (IsOnFloor()) - point1Origin = pev->origin; - - if (IsValidWaypoint(m_currentWaypointIndex)) - point2Origin = m_waypoint.origin; - - if (point1Origin != nullvec && point2Origin != nullvec) - { - if ((point1Origin - point2Origin).GetLengthSquared() >= SquaredF(100.0f)) - m_jumpTime = engine->GetTime() + CRandomFloat(1.0f, 1.5f); - else if (point1Origin.z > point2Origin.z) - m_jumpTime = engine->GetTime() + CRandomFloat(0.25f, 0.5f); - else - m_jumpTime = engine->GetTime() + CRandomFloat(0.5f, 1.0f); - } - } - else - m_jumpTime = engine->GetTime() + CRandomFloat(0.3f, 0.5f); - } - - if (m_jumpTime >= engine->GetTime() && !IsOnFloor() && !IsInWater() && !IsOnLadder()) - pev->button |= IN_DUCK; - - // save the previous speed (for checking if stuck) - m_prevSpeed = cabsf(m_moveSpeed); - m_lastDamageType = -1; // reset damage } void Bot::ChatMessage(int type, bool isTeamSay) @@ -6682,7 +6443,7 @@ bool Bot::HasHostage(void) if (!FNullEnt(hostage)) { // don't care about dead hostages - if (hostage->v.health <= 0.0f || (pev->origin - GetEntityOrigin(hostage)).GetLengthSquared() > SquaredF(600.0f)) + if (hostage->v.health <= 0.0f || (pev->origin - GetEntityOrigin(hostage)).GetLengthSquared() > squaredf(600.0f)) { hostage = nullptr; continue; @@ -6705,9 +6466,8 @@ void Bot::ResetCollideState(void) m_isStuck = false; - int i; - for (i = 0; i < 4; i++) - m_collideMoves[i] = 0; + for (auto& collide : m_collideMoves) + collide = 0; } int Bot::GetAmmo(void) @@ -6770,19 +6530,15 @@ void Bot::TakeDamage(edict_t* inflictor, int /*damage*/, int /*armor*/, int bits } } -// this function gets called by network message handler, when screenfade message get's send -// it's used to make bot blind froumd the grenade -void Bot::TakeBlinded(Vector fade, int alpha) +// this function gets called by network message handler, when screenfade message get's send it's used to make bot blind froumd the grenade +void Bot::TakeBlinded(const int alpha) { - if (fade.x != 255 || fade.y != 255 || fade.z != 255 || alpha <= 170) - return; - SetEnemy(nullptr); - m_blindTime = (engine->GetTime() + static_cast (alpha - 200)) * 0.0625f; + m_blindTime = (engine->GetTime() + static_cast(alpha - 200)) * 0.0625f; m_blindCampPoint = FindDefendWaypoint(pev->origin); - if ((g_waypoint->GetPath(m_blindCampPoint)->origin - pev->origin).GetLengthSquared() >= SquaredF(512.0f)) + if ((g_waypoint->GetPath(m_blindCampPoint)->origin - pev->origin).GetLengthSquared() > squaredf(512.0f)) m_blindCampPoint = -1; if (IsValidWaypoint(m_blindCampPoint)) @@ -6791,7 +6547,7 @@ void Bot::TakeBlinded(Vector fade, int alpha) m_blindMoveSpeed = -pev->maxspeed; m_blindSidemoveSpeed = 0.0f; - if (ChanceOf(50)) + if (chanceof(50)) m_blindSidemoveSpeed = pev->maxspeed; else m_blindSidemoveSpeed = -pev->maxspeed; @@ -6815,7 +6571,7 @@ void Bot::DiscardWeaponForUser(edict_t* user, bool discardC4) return; const Vector userOrigin = GetEntityOrigin(user); - if (IsAlive(user) && m_moneyAmount >= 2000 && HasPrimaryWeapon() && (userOrigin - pev->origin).GetLengthSquared() <= SquaredF(240.0f)) + if (IsAlive(user) && m_moneyAmount >= 2000 && HasPrimaryWeapon() && (userOrigin - pev->origin).GetLengthSquared() <= squaredf(240.0f)) { m_aimFlags |= AIM_ENTITY; m_lookAt = userOrigin; @@ -6863,107 +6619,106 @@ void Bot::ResetDoubleJumpState(void) m_jumpReady = false; } -// this function returns the velocity at which an object should looped from start to land near end. -// returns null vector if toss is not feasible -Vector Bot::CheckToss(const Vector& start, Vector end) +// this function returns the velocity at which an object should looped from start to land near end, returns nullvec if toss is not feasible +Vector Bot::CheckToss(const Vector start, const Vector stop) { TraceResult tr{}; - float gravity = engine->GetGravity() * 0.54f; + const float gravity = engine->GetGravity() * 0.55f; - end = end - pev->velocity; + Vector end = stop - pev->velocity; end.z -= 15.0f; if (cabsf(end.z - start.z) > 500.0f) return nullvec; Vector midPoint = start + (end - start) * 0.5f; - TraceHull(midPoint, midPoint + Vector(0.0f, 0.0f, 500.0f), true, head_hull, ENT(pev), &tr); + TraceHull(midPoint, midPoint + Vector(0.0f, 0.0f, 500.0f), true, head_hull, pev->pContainingEntity, &tr); - if (tr.flFraction < 1.0f) + if (tr.flFraction < 1.0f && tr.pHit) { midPoint = tr.vecEndPos; midPoint.z = tr.pHit->v.absmin.z - 1.0f; } - if ((midPoint.z < start.z) || (midPoint.z < end.z)) + if (midPoint.z < start.z || midPoint.z < end.z) return nullvec; - const float half = 0.5f * gravity; - float timeOne = csqrtf((midPoint.z - start.z) / half); - float timeTwo = csqrtf((midPoint.z - end.z) / half); + const float timeOne = csqrtf((midPoint.z - start.z) / (0.5f * gravity)); + const float timeTwo = csqrtf((midPoint.z - end.z) / (0.5f * gravity)); - if (timeOne < 0.1) + if (timeOne < 0.1f) return nullvec; - Vector nadeVelocity = (end - start) / (timeOne + timeTwo); - nadeVelocity.z = gravity * timeOne; + Vector velocity = (end - start) / (timeOne + timeTwo); + velocity.z = gravity * timeOne; - Vector apex = start + nadeVelocity * timeOne; + Vector apex = start + velocity * timeOne; apex.z = midPoint.z; - TraceHull(start, apex, false, head_hull, ENT(pev), &tr); + TraceHull(start, apex, false, head_hull, pev->pContainingEntity, &tr); if (tr.flFraction < 1.0f || tr.fAllSolid) return nullvec; - TraceHull(end, apex, true, head_hull, ENT(pev), &tr); + TraceHull(end, apex, true, head_hull, pev->pContainingEntity, &tr); if (tr.flFraction != 1.0f) { - float dot = -(tr.vecPlaneNormal | (apex - end).Normalize()); - - if (dot > 0.7f || tr.flFraction < 0.8f) // 60 degrees + const float dot = -(tr.vecPlaneNormal | (apex - end).Normalize()); + if (dot > 0.75f || tr.flFraction < 0.8f) return nullvec; } - return nadeVelocity * 0.777f; + return velocity * 0.777f; } -// this function returns the velocity vector at which an object should be thrown from start to hit end returns null vector if throw is not feasible -Vector Bot::CheckThrow(const Vector& start, Vector end) +// this function returns the velocity vector at which an object should be thrown from start to hit end, returns nullvec if throw is not feasible +Vector Bot::CheckThrow(const Vector start, const Vector end) { - Vector nadeVelocity = (end - start); + Vector velocity = end - start; TraceResult tr{}; - float gravity = engine->GetGravity() * 0.55f; - float time = nadeVelocity.GetLengthSquared() / SquaredF(196.0f); + const float gravity = engine->GetGravity() * 0.55f; + float time = velocity.GetLength() * 0.00512820512f; if (time < 0.01f) return nullvec; - else if (time > 2.0f) + + if (time > 2.0f) time = 1.2f; - nadeVelocity = nadeVelocity * (1.0f / time); - nadeVelocity.z += gravity * time * 0.5f; + const float half = time * 0.5f; + + velocity = velocity * (1.0f / time); + velocity.z += gravity * half * half; Vector apex = start + (end - start) * 0.5f; - apex.z += 0.5f * gravity * (time * 0.5f) * (time * 0.5f); + apex.z += 0.5f * gravity * half; - TraceLine(start, apex, true, false, GetEntity(), &tr); + TraceHull(start, apex, false, head_hull, pev->pContainingEntity, &tr); if (tr.flFraction != 1.0f) return nullvec; - TraceLine(end, apex, true, false, GetEntity(), &tr); + TraceHull(end, apex, true, head_hull, pev->pContainingEntity, &tr); if (tr.flFraction != 1.0f || tr.fAllSolid) { - float dot = -(tr.vecPlaneNormal | (apex - end).Normalize()); - - if (dot > 0.7f || tr.flFraction < 0.8f) + const float dot = -(tr.vecPlaneNormal | (apex - end).Normalize()); + if (dot > 0.75f || tr.flFraction < 0.8f) return nullvec; } - return nadeVelocity * 0.7793f; + return velocity * 0.7793f; } // this function checks if bomb is can be heard by the bot, calculations done by manual testing Vector Bot::CheckBombAudible(void) { - if (!g_bombPlanted || (GetCurrentTaskID() == TASK_ESCAPEFROMBOMB)) + if (!g_bombPlanted || GetCurrentTaskID() == TASK_ESCAPEFROMBOMB) return nullvec; // reliability check - Vector bombOrigin = g_waypoint->GetBombPosition(); + const Vector bombOrigin = g_waypoint->GetBombPosition(); if (m_skill > 90) return bombOrigin; @@ -6982,20 +6737,12 @@ Vector Bot::CheckBombAudible(void) desiredRadius = 1024.0f; // we hear bomb if length greater than radius - if (SquaredF(desiredRadius) < (pev->origin - bombOrigin).GetLengthSquared2D()) + if (squaredf(desiredRadius) < (pev->origin - bombOrigin).GetLengthSquared2D()) return bombOrigin; return nullvec; } -void Bot::MoveToVector(Vector to) -{ - if (to == nullvec) - return; - - FindPath(m_currentWaypointIndex, g_waypoint->FindNearest(to)); -} - void Bot::RunPlayerMovement(void) { // the purpose of this function is to compute, according to the specified computation @@ -7012,9 +6759,9 @@ void Bot::RunPlayerMovement(void) // elapses, that bot will behave like a ghost : no movement, but bullets and players can // pass through it. Then, when the next frame will begin, the stucking problem will arise! - m_msecVal = static_cast((engine->GetTime() - m_msecInterval) * 1000.0f); + m_msecVal = static_cast(cclampf((engine->GetTime() - m_msecInterval) * 1000.0f, 0.0f, 255.0f)); m_msecInterval = engine->GetTime(); - (*g_engfuncs.pfnRunPlayerMove) (GetEntity(), m_moveAngles, m_moveSpeed, m_strafeSpeed, 0.0f, static_cast(pev->button), 0, static_cast(m_msecVal)); + (*g_engfuncs.pfnRunPlayerMove) (GetEntity(), m_moveAngles, m_moveSpeed, m_strafeSpeed, 0.0f, static_cast(pev->button), pev->impulse, static_cast(m_msecVal)); } // this function checks burst mode, and switch it depending distance to to enemy @@ -7024,13 +6771,13 @@ void Bot::CheckBurstMode(const float distance) return; // no checking when shiled is active // if current weapon is glock, disable burstmode on long distances, enable it else - if (m_currentWeapon == WEAPON_GLOCK18 && distance < SquaredF(300.0f) && m_weaponBurstMode == BURST_DISABLED) + if (m_currentWeapon == WEAPON_GLOCK18 && distance < squaredf(300.0f) && m_weaponBurstMode == BURST_DISABLED) pev->button |= IN_ATTACK2; else if (m_currentWeapon == WEAPON_GLOCK18 && m_weaponBurstMode == BURST_ENABLED) pev->button |= IN_ATTACK2; // if current weapon is famas, disable burstmode on short distances, enable it else - if (m_currentWeapon == WEAPON_FAMAS && distance > SquaredF(400.0f) && m_weaponBurstMode == BURST_DISABLED) + if (m_currentWeapon == WEAPON_FAMAS && distance > squaredf(400.0f) && m_weaponBurstMode == BURST_DISABLED) pev->button |= IN_ATTACK2; else if (m_currentWeapon == WEAPON_FAMAS && m_weaponBurstMode == BURST_ENABLED) pev->button |= IN_ATTACK2; @@ -7040,17 +6787,17 @@ void Bot::CheckSilencer(void) { if ((m_currentWeapon == WEAPON_USP && m_skill < 90) || m_currentWeapon == WEAPON_M4A1 && !HasShield()) { - int random = (m_personality == PERSONALITY_RUSHER ? 33 : m_personality == PERSONALITY_CAREFUL ? 99 : 66); + const int random = (m_personality == PERSONALITY_RUSHER ? 33 : m_personality == PERSONALITY_CAREFUL ? 99 : 66); // aggressive bots don't like the silencer - if (ChanceOf(m_currentWeapon == WEAPON_USP ? random / 3 : random)) + if (chanceof(m_currentWeapon == WEAPON_USP ? random / 3 : random)) { if (pev->weaponanim > 6) // is the silencer not attached... pev->button |= IN_ATTACK2; // attach the silencer } else { - if (pev->weaponanim <= 6) // is the silencer attached... + if (pev->weaponanim < 7) // is the silencer attached... pev->button |= IN_ATTACK2; // detach the silencer } } @@ -7061,8 +6808,7 @@ float Bot::GetBombTimeleft(void) if (!g_bombPlanted) return 0.0f; - float timeLeft = ((g_timeBombPlanted + engine->GetC4TimerTime()) - engine->GetTime()); - + const float timeLeft = ((g_timeBombPlanted + engine->GetC4TimerTime()) - engine->GetTime()); if (timeLeft < 0.0f) return 0.0f; @@ -7071,33 +6817,15 @@ float Bot::GetBombTimeleft(void) float Bot::GetEstimatedReachTime(void) { - if (m_isZombieBot && !m_isStuck && m_damageTime >= engine->GetTime()) - return 12.0f; - - float estimatedTime = 6.0f; // time to reach next waypoint + const float maxSpeed = cmaxf(cabsf(pev->speed), pev->maxspeed * 0.5f); + float estimatedTime = (IsOnLadder() || m_waypointFlags & WAYPOINT_LADDER) ? (pev->origin - m_waypoint.origin).GetLength() / maxSpeed : (pev->origin - m_waypoint.origin).GetLength2D() / maxSpeed; - // calculate 'real' time that we need to get from one waypoint to another - if (IsValidWaypoint(m_currentWaypointIndex) && IsValidWaypoint(m_prevWptIndex)) - { - const float distance = (g_waypoint->GetPath(m_prevWptIndex)->origin - m_waypoint.origin).GetLengthSquared(); - - // caclulate estimated time - estimatedTime = 5.0f * (distance / SquaredF(pev->maxspeed)); - - // check for special waypoints, that can slowdown our movement - if ((m_waypointFlags & WAYPOINT_CROUCH) || (m_waypointFlags & WAYPOINT_LADDER) || (pev->button & IN_DUCK)) - estimatedTime *= 3.0f; - - // check for too low values - if (estimatedTime < 3.0f) - estimatedTime = 3.0f; - - // check for too high values - if (estimatedTime > 8.0f) - estimatedTime = 8.0f; - } + if (pev->flags & FL_DUCKING || m_waypointFlags & WAYPOINT_CROUCH) + estimatedTime *= 3.0f; + else + estimatedTime *= 1.5f; - return estimatedTime; + return cclampf(estimatedTime, 3.0f, 10.0f); } bool Bot::CampingAllowed(void) @@ -7206,7 +6934,7 @@ bool Bot::OutOfBombTimer(void) const Vector& bombOrigin = g_waypoint->GetBombPosition(); // bot will belive still had a chance - if ((m_hasDefuser && IsVisible(bombOrigin, GetEntity())) || (bombOrigin - pev->origin).GetLengthSquared() <= SquaredF(512.0f)) + if ((m_hasDefuser && IsVisible(bombOrigin, GetEntity())) || (bombOrigin - pev->origin).GetLengthSquared() <= squaredf(512.0f)) return false; bool hasTeammatesWithDefuserKit = false; @@ -7216,7 +6944,7 @@ bool Bot::OutOfBombTimer(void) for (const auto& bot : g_botManager->m_bots) { // search players with defuse kit - if (bot != nullptr && bot->m_team == TEAM_COUNTER && bot->m_hasDefuser && (bombOrigin - bot->pev->origin).GetLengthSquared() <= SquaredF(512.0f)) + if (bot != nullptr && bot->m_team == TEAM_COUNTER && bot->m_hasDefuser && (bombOrigin - bot->pev->origin).GetLengthSquared() <= squaredf(512.0f)) { hasTeammatesWithDefuserKit = true; break; @@ -7225,7 +6953,7 @@ bool Bot::OutOfBombTimer(void) } // add reach time to left time - float reachTime = g_waypoint->GetTravelTime(pev->maxspeed, m_waypoint.origin, bombOrigin); + const float reachTime = g_waypoint->GetTravelTime(pev->maxspeed, m_waypoint.origin, bombOrigin); // for counter-terrorist check alos is we have time to reach position plus average defuse time if ((timeLeft < reachTime && !m_hasDefuser && !hasTeammatesWithDefuserKit) || (timeLeft < reachTime && m_hasDefuser)) @@ -7274,7 +7002,7 @@ void Bot::ReactOnSound(void) const float distance = (client.soundPosition - pev->origin).GetLengthSquared(); const float hearingDistance = client.hearingDistance; - if (distance > SquaredF(hearingDistance) || hearingDistance >= 2048.0f || distance > SquaredF(m_maxhearrange)) + if (distance > squaredf(hearingDistance) || hearingDistance >= 2048.0f || distance > squaredf(m_maxhearrange)) continue; if (distance < maxdist) @@ -7339,7 +7067,7 @@ void Bot::EquipInBuyzone(int iBuyCount) static float lastEquipTime = 0.0f; // if bot is in buy zone, try to buy ammo for this weapon... - if (lastEquipTime + 15.0f < engine->GetTime() && m_inBuyZone && g_timeRoundStart + CRandomFloat(10.0f, 20.0f) + engine->GetBuyTime() < engine->GetTime() && !g_bombPlanted && m_moneyAmount > 700) + if (lastEquipTime + 15.0f < engine->GetTime() && m_inBuyZone && g_timeRoundStart + crandomfloat(10.0f, 20.0f) + engine->GetBuyTime() < engine->GetTime() && !g_bombPlanted && m_moneyAmount > 700) { m_buyingFinished = false; m_buyState = iBuyCount; diff --git a/source/chatlib.cpp b/source/chatlib.cpp index 5a9b21a..93400ff 100644 --- a/source/chatlib.cpp +++ b/source/chatlib.cpp @@ -110,13 +110,13 @@ char* HumanizeName(char* name) cstrcpy(outputName, name); // copy name to new buffer // drop tag marks, 75 percent of time - if (ChanceOf(75)) + if (chanceof(75)) StripTags(outputName); else cstrtrim(outputName); // sometimes switch name to lower characters - if (ChanceOf(50)) + if (chanceof(50)) { int i; for (i = 0; i < static_cast (cstrlen(outputName)); i++) @@ -312,14 +312,14 @@ void Bot::PrepareChatMessage(char* text) { if (g_gameVersion == CSVER_CZERO) { - if (CRandomInt(1, 100) < 30) + if (crandomint(1, 100) < 30) cstrcat(m_tempStrings, "CZ"); else cstrcat(m_tempStrings, "Condition Zero"); } else if ((g_gameVersion == CSVER_CSTRIKE) || (g_gameVersion == CSVER_VERYOLD)) { - if (CRandomInt(1, 100) < 30) + if (crandomint(1, 100) < 30) cstrcat(m_tempStrings, "CS"); else cstrcat(m_tempStrings, "Counter-Strike"); @@ -365,7 +365,7 @@ bool Bot::CheckKeywords(char* tempMessage, char* reply) } // didn't find a keyword? 50% of the time use some universal reply - if (ChanceOf(50) && !g_chatFactory[CHAT_NOKW].IsEmpty()) + if (chanceof(50) && !g_chatFactory[CHAT_NOKW].IsEmpty()) { cstrcpy(reply, g_chatFactory[CHAT_NOKW].GetRandomElement().GetBuffer()); return true; diff --git a/source/clib.cpp b/source/clib.cpp index 37033ba..c4bd346 100644 --- a/source/clib.cpp +++ b/source/clib.cpp @@ -23,7 +23,9 @@ #endif #endif -int CRandomInt(const int min, const int max) +static size_t cache; + +int crandomint(const int min, const int max) { if (min > max) return frand() % (min - max + 1) + max; @@ -31,7 +33,7 @@ int CRandomInt(const int min, const int max) return frand() % (max - min + 1) + min; } -float CRandomFloat(const float min, const float max) +float crandomfloat(const float min, const float max) { if (min > max) return fnext() * (min - max) / UINT64_MAX + max; @@ -39,22 +41,22 @@ float CRandomFloat(const float min, const float max) return fnext() * (max - min) / UINT64_MAX + min; } -bool ChanceOf(const int number) +bool chanceof(const int number) { - return CRandomInt(1, 100) <= number; + return crandomint(1, 101) < number; } -float SquaredF(const float value) +float squaredf(const float value) { return value * value; } -float SquaredI(const int value) +float squaredi(const int value) { return static_cast(value * value); } -int Squared(const int value) +int squared(const int value) { return value * value; } @@ -266,11 +268,11 @@ size_t cstrlen(const char* str) if (str == nullptr) return 0; - size_t length = 0; - while (length < SIZE_MAX && str[length] != '\0') - length++; + cache = 0; + while (cache < SIZE_MAX && str[cache] != '\0') + cache++; - return length; + return cache; } // this fixes bot spectator bug in linux builds @@ -315,12 +317,11 @@ int cstrncmp(const char* str1, const char* str2, const size_t num) if (str2 == nullptr) return 0; - size_t i; - for (i = 0; i < num; ++i) + for (cache = 0; cache < num; ++cache) { - if (str1[i] != str2[i]) - return (str1[i] < str2[i]) ? -1 : 1; - else if (str1[i] == '\0') + if (str1[cache] != str2[cache]) + return (str1[cache] < str2[cache]) ? -1 : 1; + else if (str1[cache] == '\0') return 0; } @@ -344,9 +345,8 @@ void cmemcpy(void* dest, const void* src, const size_t size) char* dest2 = static_cast(dest); const char* src2 = static_cast(src); - size_t i; - for (i = 0; i < size; ++i) - dest2[i] = src2[i]; + for (cache = 0; cache < size; ++cache) + dest2[cache] = src2[cache]; } void cmemset(void* dest, const int value, const size_t count) @@ -354,8 +354,7 @@ void cmemset(void* dest, const int value, const size_t count) unsigned char* ptr = static_cast(dest); const unsigned char byteValue = static_cast(value); - size_t i; - for (i = 0; i < count; ++i) + for (cache = 0; cache < count; ++cache) { *ptr = byteValue; ptr++; @@ -391,14 +390,14 @@ int cctz(unsigned int value) if (value == 0) return sizeof(unsigned int) * 8; - int count = 0; + cache = 0; while ((value & 1) == 0) { value >>= 1; - count++; + cache++; } - return count; + return cache; } int ctolower(const int value) @@ -443,32 +442,29 @@ void cstrtrim(char* string) return; char* ptr = string; - int length = 0, toggleFlag = 0, increment = 0; - int i = 0; - while (*ptr++) length++; - for (i = length - 1; i >= 0; i--) + for (cache = length - 1; cache >= 0; cache--) { - if (!cspace(string[i])) + if (!cspace(string[cache])) break; else { - string[i] = 0; + string[cache] = 0; length--; } } - for (i = 0; i < length; i++) + for (cache = 0; cache < length; cache++) { - if (cspace(string[i]) && !toggleFlag) + if (cspace(string[cache]) && !toggleFlag) { increment++; - if (increment + i < length) - string[i] = string[increment + i]; + if (increment + cache < length) + string[cache] = string[increment + cache]; } else { @@ -476,7 +472,7 @@ void cstrtrim(char* string) toggleFlag = 1; if (increment) - string[i] = string[increment + i]; + string[cache] = string[increment + cache]; } } @@ -513,11 +509,11 @@ char* cstrncpy(char* dest, const char* src, const size_t count) char* destPtr = dest; const char* srcPtr = src; - size_t i = 0; - for (; i < count && *srcPtr != '\0'; i++, destPtr++, srcPtr++) + cache = 0; + for (; cache < count && *srcPtr != '\0'; cache++, destPtr++, srcPtr++) *destPtr = *srcPtr; - for (; i < count; i++, destPtr++) + for (; cache < count; cache++, destPtr++) *destPtr = '\0'; return dest; @@ -568,7 +564,7 @@ size_t cstrspn(const char* str, const char* charset) if (str == nullptr || charset == nullptr) return 0; - size_t count = 0; + cache = 0; while (*str != '\0') { const char* charset_ptr = charset; @@ -588,11 +584,11 @@ size_t cstrspn(const char* str, const char* charset) if (!found) break; - count++; + cache++; str++; } - return count; + return cache; } size_t cstrcspn(const char* str, const char* charset) @@ -600,7 +596,7 @@ size_t cstrcspn(const char* str, const char* charset) if (str == nullptr || charset == nullptr) return 0; - size_t count = 0; + cache = 0; while (*str != '\0') { const char* charset_ptr = charset; @@ -620,11 +616,11 @@ size_t cstrcspn(const char* str, const char* charset) if (found) break; - count++; + cache++; str++; } - return count; + return cache; } int catoi(const char* str) diff --git a/source/combat.cpp b/source/combat.cpp index aa3febc..9fc808a 100644 --- a/source/combat.cpp +++ b/source/combat.cpp @@ -50,7 +50,7 @@ int Bot::GetNearbyFriendsNearPosition(Vector origin, float radius) if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team != m_team || client.ent == me) continue; - if ((client.origin - origin).GetLengthSquared() < SquaredF(radius)) + if ((client.origin - origin).GetLengthSquared() < squaredf(radius)) count++; } @@ -74,7 +74,7 @@ int Bot::GetNearbyEnemiesNearPosition(Vector origin, float radius) if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team == m_team) continue; - if ((client.origin - origin).GetLengthSquared() < SquaredF(radius)) + if ((client.origin - origin).GetLengthSquared() < squaredf(radius)) count++; } @@ -189,7 +189,7 @@ bool Bot::LookupEnemy(void) m_enemyUpdateTime = 0.0f; if (GetGameMode() == MODE_DM) - m_fearLevel += 0.15f; + m_fearLevel += 1.5f * m_frameInterval; } if ((m_enemyUpdateTime > engine->GetTime())) @@ -228,7 +228,7 @@ bool Bot::LookupEnemy(void) continue; if (m_blindRecognizeTime < engine->GetTime() && IsBehindSmokeClouds(entity)) - m_blindRecognizeTime = engine->GetTime() + CRandomFloat(2.0f, 3.0f); + m_blindRecognizeTime = engine->GetTime() + crandomfloat(2.0f, 3.0f); if (m_blindRecognizeTime >= engine->GetTime()) continue; @@ -251,7 +251,7 @@ bool Bot::LookupEnemy(void) if (m_currentWaypointIndex != GetEntityWaypoint(targetEntity)) { const float distance = (pev->origin - GetEntityOrigin(m_moveTargetEntity)).GetLengthSquared(); - if (distance < SquaredF(enemy_distance + 400.0f)) + if (distance < squaredf(enemy_distance + 400.0f)) { const int targetWpIndex = GetEntityWaypoint(targetEntity); bool shortDistance = false; @@ -318,7 +318,7 @@ bool Bot::LookupEnemy(void) movePoint++; int j; - for (int j = 0; j < Const_MaxPathIndex; j++) + for (j = 0; j < Const_MaxPathIndex; j++) { if (path->index[j] == srcIndex && path->connectionFlags[j] & PATHFLAG_JUMP) { @@ -330,7 +330,7 @@ bool Bot::LookupEnemy(void) } enemy_distance = (GetEntityOrigin(targetEntity) - pev->origin).GetLengthSquared(); - if ((enemy_distance < SquaredF(150.0f) && movePoint <= 1) || (targetEntity == m_moveTargetEntity && movePoint <= 2)) + if ((enemy_distance < squaredf(150.0f) && movePoint <= 1) || (targetEntity == m_moveTargetEntity && movePoint <= 2)) { moveTotarget = false; if (targetEntity == m_moveTargetEntity && movePoint <= 1) @@ -373,7 +373,7 @@ bool Bot::LookupEnemy(void) m_targetEntity = nullptr; - if (ChanceOf(m_skill)) + if (chanceof(m_skill)) m_enemySurpriseTime = engine->GetTime() + (m_actualReactionTime * 0.33333333333f); else m_enemySurpriseTime = engine->GetTime() + m_actualReactionTime; @@ -433,7 +433,7 @@ Vector Bot::GetAimPosition(void) if (!IsZombieMode() && (m_currentWeapon == WEAPON_AWP || m_currentWeapon == WEAPON_SCOUT)) return targetOrigin; // now check is our skill match to aim at head, else aim at enemy body - else if (IsZombieMode() || ChanceOf(m_skill) || UsesPistol()) + else if (IsZombieMode() || chanceof(m_skill) || UsesPistol()) targetOrigin += m_enemy->v.view_ofs + Vector(0.0f, 0.0f, GetZOffset(distance)); else targetOrigin += Vector(0.0f, 0.0f, GetZOffset(distance)); @@ -461,7 +461,7 @@ float Bot::GetZOffset(const float distance) float result = -2.0f; - if (distance > SquaredF(512.0f)) + if (distance > squaredf(512.0f)) { if (sniper) result = 0.18f; @@ -554,7 +554,7 @@ bool Bot::DoFirePause(float distance)//, FireDelay *fireDelay) if (ctanf(angle) * (distance + (distance * 0.25f)) > g_skillTab[m_skill / 20].recoilAmount) { if (m_firePause < (engine->GetTime() - 0.4)) - m_firePause = engine->GetTime() + CRandomFloat(0.4f, (0.4f + 1.2f * ((100 - m_skill)) * 0.01f)); + m_firePause = engine->GetTime() + crandomfloat(0.4f, (0.4f + 1.2f * ((100 - m_skill)) * 0.01f)); return true; } @@ -619,7 +619,7 @@ void Bot::FireWeapon(void) // is enough ammo available to fire AND check is better to use pistol in our current situation... if (g_gameVersion == HALFLIFE) { - if (selectIndex == WEAPON_SNARK || selectIndex == WEAPON_GAUSS ||selectIndex == WEAPON_EGON || (selectIndex == WEAPON_HANDGRENADE && distance > SquaredF(384.0f) && distance < SquaredF(768.0f)) || (selectIndex == WEAPON_RPG && distance > SquaredF(320.0f)) || (selectIndex == WEAPON_CROSSBOW && distance > SquaredF(320.0f))) + if (selectIndex == WEAPON_SNARK || selectIndex == WEAPON_GAUSS ||selectIndex == WEAPON_EGON || (selectIndex == WEAPON_HANDGRENADE && distance > squaredf(384.0f) && distance < squaredf(768.0f)) || (selectIndex == WEAPON_RPG && distance > squaredf(320.0f)) || (selectIndex == WEAPON_CROSSBOW && distance > squaredf(320.0f))) chosenWeaponIndex = selectIndex; else if (selectIndex != WEAPON_HANDGRENADE && selectIndex != WEAPON_RPG && selectIndex != WEAPON_CROSSBOW && (m_ammoInClip[selectTab[selectIndex].id] > 0) && !IsWeaponBadInDistance(selectIndex, distance)) chosenWeaponIndex = selectIndex; @@ -718,7 +718,7 @@ void Bot::FireWeapon(void) if (HasShield() && m_shieldCheckTime < engine->GetTime() && GetCurrentTaskID() != TASK_CAMP) // better shield gun usage { - if ((distance > SquaredF(768.0f)) && !IsShieldDrawn()) + if ((distance > squaredf(768.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 @@ -729,9 +729,9 @@ void Bot::FireWeapon(void) if (UsesSniper() && m_zoomCheckTime < engine->GetTime()) // is the bot holding a sniper rifle? { - if (distance > SquaredF(1500.0f) && pev->fov >= 40.0f) // should the bot switch to the long-range zoom? + if (distance > squaredf(1500.0f) && pev->fov >= 40.0f) // should the bot switch to the long-range zoom? pev->button |= IN_ATTACK2; - else if (distance > SquaredF(150.0f) && pev->fov >= 90.0f) // else should the bot switch to the close-range zoom ? + else if (distance > squaredf(150.0f) && pev->fov >= 90.0f) // else should the bot switch to the close-range zoom ? pev->button |= IN_ATTACK2; else if (pev->fov < 90.0f) // else should the bot restore the normal view ? pev->button |= IN_ATTACK2; @@ -740,7 +740,7 @@ void Bot::FireWeapon(void) } else if (UsesZoomableRifle() && m_zoomCheckTime < engine->GetTime() && m_skill < 90) // else is the bot holding a zoomable rifle? { - if (distance > SquaredF(800.0f) && pev->fov >= 90.0f) // should the bot switch to zoomed mode? + if (distance > squaredf(800.0f) && pev->fov >= 90.0f) // should the bot switch to zoomed mode? pev->button |= IN_ATTACK2; else if (pev->fov < 90.0f) // else should the bot restore the normal view? pev->button |= IN_ATTACK2; @@ -749,7 +749,7 @@ void Bot::FireWeapon(void) } // need to care for burst fire? - if (g_gameVersion == HALFLIFE || distance < SquaredF(384.0f) || m_blindTime > engine->GetTime()) + if (g_gameVersion == HALFLIFE || distance < squaredf(384.0f) || m_blindTime > engine->GetTime()) { if (m_currentWeapon == melee && selectId == melee) KnifeAttack(); @@ -793,31 +793,31 @@ void Bot::FireWeapon(void) else { pev->button |= IN_ATTACK; // use primary attack - delayTime = baseDelay + CRandomFloat(minDelay, maxDelay); + delayTime = baseDelay + crandomfloat(minDelay, maxDelay); m_zoomCheckTime = engine->GetTime(); } - if (!FNullEnt(enemy) && distance > SquaredF(1200.0f)) + if (!FNullEnt(enemy) && distance > squaredf(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 > SquaredF(2400.0f)) + if (distance > squaredf(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 > SquaredF(2400.0f)) + if (distance > squaredf(2400.0f)) delayTime += (delayTime == 0.0f) ? 0.12f : 0.08f; else delayTime += (delayTime == 0.0f) ? 0.08f : 0.0f; } else { - if (distance > SquaredF(2400.0f)) + if (distance > squaredf(2400.0f)) delayTime += (delayTime == 0.0f) ? 0.18f : 0.15f; else delayTime += (delayTime == 0.0f) ? 0.15f : 0.10f; @@ -867,10 +867,10 @@ bool Bot::KnifeAttack(float attackDistance) if (kaMode > 0) { - Vector entityOrigin = GetEntityOrigin(entity); - float distanceSkipZ = (pev->origin - entityOrigin).GetLengthSquared2D(); + const Vector entityOrigin = GetEntityOrigin(entity); + const float distanceSkipZ = (pev->origin - entityOrigin).GetLengthSquared2D(); - if (pev->origin.z > entityOrigin.z && distanceSkipZ < SquaredF(64.0f)) + if (pev->origin.z > entityOrigin.z && distanceSkipZ < squaredf(64.0f)) { pev->button |= IN_DUCK; m_campButtons |= IN_DUCK; @@ -881,7 +881,7 @@ bool Bot::KnifeAttack(float attackDistance) pev->button &= ~IN_DUCK; m_campButtons &= ~IN_DUCK; - if (pev->origin.z + 150.0f < entityOrigin.z && distanceSkipZ < SquaredF(300.0f)) + if (pev->origin.z + 150.0f < entityOrigin.z && distanceSkipZ < squaredf(300.0f)) pev->button |= IN_JUMP; } @@ -898,7 +898,7 @@ bool Bot::KnifeAttack(float attackDistance) pev->button |= IN_ATTACK; else if (kaMode == 2) pev->button |= IN_ATTACK2; - else if (CRandomInt(1, 10) < 3 || HasShield()) + else if (crandomint(1, 10) < 3 || HasShield()) pev->button |= IN_ATTACK; else pev->button |= IN_ATTACK2; @@ -921,7 +921,7 @@ bool Bot::IsWeaponBadInDistance(int weaponIndex, float distance) return false; // shotgun is too inaccurate at long distances, so weapon is bad - if (weaponID == WEAPON_SHOTGUN && distance > SquaredF(768.0f)) + if (weaponID == WEAPON_SHOTGUN && distance > squaredf(768.0f)) return true; } else @@ -931,12 +931,12 @@ bool Bot::IsWeaponBadInDistance(int weaponIndex, float distance) return false; // shotguns is too inaccurate at long distances, so weapon is bad - if ((weaponID == WEAPON_M3 || weaponID == WEAPON_XM1014) && distance > SquaredF(768.0f)) + if ((weaponID == WEAPON_M3 || weaponID == WEAPON_XM1014) && distance > squaredf(768.0f)) return true; if (!IsZombieMode()) { - if ((weaponID == WEAPON_SCOUT || weaponID == WEAPON_AWP || weaponID == WEAPON_G3SG1 || weaponID == WEAPON_SG550) && distance < SquaredF(512.0f)) + if ((weaponID == WEAPON_SCOUT || weaponID == WEAPON_AWP || weaponID == WEAPON_G3SG1 || weaponID == WEAPON_SG550) && distance < squaredf(512.0f)) return true; } } @@ -957,7 +957,7 @@ void Bot::FocusEnemy(void) const float distance = (m_lookAt - EyePosition()).GetLengthSquared(); // how far away is the enemy scum? - if (distance < SquaredF(128.0f)) + if (distance < squaredf(128.0f)) { if (m_currentWeapon == WEAPON_KNIFE) { @@ -1018,7 +1018,7 @@ void Bot::CombatFight(void) else return; - if (IsValidWaypoint(m_currentWaypointIndex) && (m_moveSpeed != 0.0f || m_strafeSpeed != 0.0f) && m_waypointFlags & WAYPOINT_CROUCH) + if ((m_moveSpeed != 0.0f || m_strafeSpeed != 0.0f) && m_waypointFlags & WAYPOINT_CROUCH) pev->button |= IN_DUCK; if (m_isZombieBot) // zombie ai @@ -1026,9 +1026,9 @@ void Bot::CombatFight(void) DeleteSearchNodes(); m_moveSpeed = pev->maxspeed; - if (m_isSlowThink && !(pev->flags & FL_DUCKING) && CRandomInt(1, 2) == 1 && !IsOnLadder() && pev->speed >= pev->maxspeed) + if (m_isSlowThink && !(pev->flags & FL_DUCKING) && crandomint(1, 2) == 1 && !IsOnLadder() && pev->speed >= pev->maxspeed) { - int random = CRandomInt(1, 3); + const int random = crandomint(1, 3); if (random == 1) pev->button |= IN_JUMP; else if (random == 2) @@ -1065,34 +1065,32 @@ void Bot::CombatFight(void) const Vector destOrigin = m_enemyOrigin + enemyVel * m_frameInterval; const float distance = (myVec - destOrigin).GetLengthSquared(); - if (m_isSlowThink && distance < SquaredF(768.0f) && m_enemy->v.health > 100 && ChanceOf(ebot_zp_use_grenade_percent.GetInt()) && m_enemy->v.velocity.GetLengthSquared() > SquaredF(10.0f)) + if (m_isSlowThink && distance < squaredf(768.0f) && m_enemy->v.health > 100 && chanceof(ebot_zp_use_grenade_percent.GetInt()) && m_enemy->v.velocity.GetLengthSquared() > squaredf(10.0f)) { if (m_skill >= 50) { - if (pev->weapons & (1 << WEAPON_FBGRENADE) && (m_enemy->v.speed >= m_enemy->v.maxspeed || distance < SquaredF(384.0f))) + if (pev->weapons & (1 << WEAPON_FBGRENADE) && (m_enemy->v.speed >= m_enemy->v.maxspeed || distance < squaredf(384.0f))) ThrowFrostNade(); else ThrowFireNade(); } else { - if (pev->weapons & (1 << WEAPON_FBGRENADE) && CRandomInt(1, 2) == 1) + if (pev->weapons & (1 << WEAPON_FBGRENADE) && crandomint(1, 2) == 1) ThrowFrostNade(); else ThrowFireNade(); } } - if (baseDistance > 0.0f && distance < SquaredF(baseDistance)) + if (baseDistance > 0.0f && distance < squaredf(baseDistance)) { DeleteSearchNodes(); m_destOrigin = destOrigin; m_moveSpeed = -pev->maxspeed; - Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval); - Vector directionNormal = directionOld.Normalize(); - Vector direction = directionNormal; - directionNormal.z = 0.0f; + const Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval); + const Vector directionNormal = directionOld.Normalize2D(); SetStrafeSpeed(directionNormal, pev->maxspeed); m_moveAngles = directionOld.ToAngles(); @@ -1108,40 +1106,43 @@ void Bot::CombatFight(void) DeleteSearchNodes(); - Vector enemyOrigin = m_lookAt; - float distance = (enemyOrigin - EyePosition()).GetLengthSquared(); // how far away is the enemy scum? + const Vector enemyOrigin = m_lookAt; + const float distance = (enemyOrigin - EyePosition()).GetLengthSquared(); // how far away is the enemy scum? if (m_currentWeapon == WEAPON_KNIFE) { - if (distance > SquaredF(128.0f)) + if (distance > squaredf(128.0f)) { - if (!(g_mapType & MAP_KA) && CRandomFloat(1.0f, pev->health) < 20.0f) + if (!(g_mapType & MAP_KA) && crandomfloat(1.0f, pev->health) < 20.0f) { const int seekindex = FindCoverWaypoint(99999.0f); if (IsValidWaypoint(seekindex)) - PushTask(TASK_SEEKCOVER, TASKPRI_SEEKCOVER, seekindex, 8.0f, true); + { + m_chosenGoalIndex = seekindex; + PushTask(TASK_SEEKCOVER, TASKPRI_SEEKCOVER, 8.0f, true); + } } if (m_navNode.IsEmpty()) { - const int nearest = g_waypoint->FindNearest(m_enemyOrigin, 99999999.0f, -1, m_enemy); - if (IsValidWaypoint(nearest)) - FindPath(m_currentWaypointIndex, nearest); + const int index = g_waypoint->FindNearest(m_enemyOrigin, 512.0f, -1, m_enemy); + if (IsValidWaypoint(index)) + FindPath(m_currentWaypointIndex, index); + else + FindPath(m_currentWaypointIndex, -1, m_enemyOrigin); } return; } } - else if (distance < SquaredF(256.0f)) // don't get knifed!!! + else if (distance < squaredf(256.0f)) // don't get knifed!!! { DeleteSearchNodes(); m_destOrigin = m_enemyOrigin; m_moveSpeed = -pev->maxspeed; - Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval); - Vector directionNormal = directionOld.Normalize(); - Vector direction = directionNormal; - directionNormal.z = 0.0f; + const Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval); + const Vector directionNormal = directionOld.Normalize2D(); SetStrafeSpeed(directionNormal, pev->maxspeed); m_moveAngles = directionOld.ToAngles(); @@ -1167,7 +1168,7 @@ void Bot::CombatFight(void) approach = 100; else { - approach = static_cast (pev->health * m_agressionLevel); + approach = static_cast(pev->health * m_agressionLevel); if (UsesSniper() && approach > 49) approach = 49; @@ -1175,13 +1176,13 @@ void Bot::CombatFight(void) if (UsesPistol() && !((m_enemy->v.weapons & WeaponBits_Secondary) || (m_enemy->v.weapons & (1 << WEAPON_SG550))) && !g_bombPlanted) { - m_fearLevel += 0.5f; + m_fearLevel += 5.0f * m_frameInterval; CheckGrenades(); CheckThrow(EyePosition(), m_throw); if ((m_states & STATE_SEEINGENEMY) && !m_isBomber) - PushTask(TASK_SEEKCOVER, TASKPRI_SEEKCOVER, -1, CRandomFloat(10.0f, 20.0f), true); + PushTask(TASK_SEEKCOVER, TASKPRI_SEEKCOVER, engine->GetTime() + crandomfloat(10.0f, 20.0f), true); } // only take cover when bomb is not planted and enemy can see the bot or the bot is VIP @@ -1207,11 +1208,11 @@ void Bot::CombatFight(void) { if (m_lastFightStyleCheck + 3.0 < engine->GetTime()) { - const int rand = CRandomInt(1, 100); + const int rand = crandomint(1, 100); - if (distance < SquaredF(450.0f)) + if (distance < squaredf(450.0f)) m_fightStyle = 0; - else if (distance < SquaredF(1024.0f)) + else if (distance < squaredf(1024.0f)) { if (rand < (UsesSubmachineGun() ? 50 : 30)) m_fightStyle = 0; @@ -1233,7 +1234,7 @@ void Bot::CombatFight(void) { if (m_lastFightStyleCheck + 3.0f < engine->GetTime()) { - if (ChanceOf(50)) + if (chanceof(50)) m_fightStyle = 1; else m_fightStyle = 0; @@ -1242,7 +1243,7 @@ void Bot::CombatFight(void) } } - if (m_fightStyle == 0 || ((pev->button & IN_RELOAD) || m_isReloading) || (UsesPistol() && distance < SquaredF(400.0f))) + if (m_fightStyle == 0 || ((pev->button & IN_RELOAD) || m_isReloading) || (UsesPistol() && distance < squaredf(400.0f))) { if (m_strafeSetTime < engine->GetTime()) { @@ -1257,10 +1258,10 @@ void Bot::CombatFight(void) else m_combatStrafeDir = 0; - if (ChanceOf(30)) + if (chanceof(30)) m_combatStrafeDir ^= 1; - m_strafeSetTime = engine->GetTime() + CRandomFloat(0.5f, 3.0f); + m_strafeSetTime = engine->GetTime() + crandomfloat(0.5f, 3.0f); } if (m_combatStrafeDir == 0) @@ -1270,7 +1271,7 @@ void Bot::CombatFight(void) else { m_combatStrafeDir ^= 1; - m_strafeSetTime = engine->GetTime() + CRandomFloat(0.5f, 1.5f); + m_strafeSetTime = engine->GetTime() + crandomfloat(0.5f, 1.5f); } } else @@ -1280,14 +1281,14 @@ void Bot::CombatFight(void) else { m_combatStrafeDir ^= 1; - m_strafeSetTime = engine->GetTime() + CRandomFloat(0.5f, 1.5f); + m_strafeSetTime = engine->GetTime() + crandomfloat(0.5f, 1.5f); } } - if (m_difficulty >= 3 && !UsesSniper() && (m_jumpTime + 5.0f < engine->GetTime() && IsOnFloor() && CRandomInt(0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.GetLength2D() > 150.0f)) + if (m_difficulty >= 3 && !UsesSniper() && !m_jumping && IsOnFloor() && crandomint(0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.GetLength2D() > 150.0f) pev->button |= IN_JUMP; - if (m_moveSpeed > 0.0f && distance > SquaredF(100.0f) && m_currentWeapon != WEAPON_KNIFE) + if (m_moveSpeed > 0.0f && distance > squaredf(100.0f) && m_currentWeapon != WEAPON_KNIFE) m_moveSpeed = 0.0f; if (m_currentWeapon == WEAPON_KNIFE) @@ -1488,13 +1489,13 @@ bool Bot::UsesBadPrimary(void) void Bot::ThrowFireNade(void) { if (pev->weapons & (1 << WEAPON_HEGRENADE)) - PushTask(TASK_THROWHEGRENADE, TASKPRI_THROWGRENADE, -1, CRandomFloat(0.6f, 0.9f), false); + PushTask(TASK_THROWHEGRENADE, TASKPRI_THROWGRENADE, engine->GetTime() + crandomfloat(0.6f, 0.9f), false); } void Bot::ThrowFrostNade(void) { if (pev->weapons & (1 << WEAPON_FBGRENADE)) - PushTask(TASK_THROWFBGRENADE, TASKPRI_THROWGRENADE, -1, CRandomFloat(0.6f, 0.9f), false); + PushTask(TASK_THROWFBGRENADE, TASKPRI_THROWGRENADE, engine->GetTime() + crandomfloat(0.6f, 0.9f), false); } int Bot::CheckGrenades(void) @@ -1593,7 +1594,7 @@ void Bot::SelectBestWeapon(void) return; } - if (!FNullEnt(m_enemy) && GetCurrentTaskID() == TASK_FIGHTENEMY && (pev->origin - m_enemyOrigin).GetLengthSquared() <= SquaredF(96.0f)) + if (!FNullEnt(m_enemy) && GetCurrentTaskID() == TASK_FIGHTENEMY && (pev->origin - m_enemyOrigin).GetLengthSquared() <= squaredf(96.0f)) { if (m_currentWeapon != WEAPON_KNIFE) SelectWeaponByName("weapon_knife"); @@ -1713,61 +1714,6 @@ void Bot::SelectWeaponbyNumber(int num) FakeClientCommand(GetEntity(), g_weaponSelect[num].weaponName); } -void Bot::CommandTeam(void) -{ - if (GetGameMode() != MODE_BASE && GetGameMode() != 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.index < 0) - continue; - - if (FNullEnt(client.ent)) - continue; - - 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() + CRandomFloat(10.0f, 30.0f); -} - void Bot::CheckReload(void) { // check the reload state diff --git a/source/control.cpp b/source/control.cpp index 9f80542..099bf2c 100644 --- a/source/control.cpp +++ b/source/control.cpp @@ -23,11 +23,15 @@ // #include +#ifdef WIN32 +#include +#else +#include +#endif ConVar ebot_quota("ebot_quota", "10"); ConVar ebot_forceteam("ebot_force_team", "any"); -ConVar ebot_auto_players("ebot_auto_players", "-1"); // i don't even know what is this... -ConVar ebot_quota_save("ebot_quota_save", "-1"); +ConVar ebot_auto_players("ebot_auto_players", "-1"); ConVar ebot_difficulty("ebot_difficulty", "4"); ConVar ebot_minskill("ebot_min_skill", "1"); @@ -59,17 +63,16 @@ BotControl::BotControl(void) InitQuota(); } -// this is a bot manager class destructor, do not use engine->GetMaxClients () here !! +// this is a bot manager class destructor BotControl::~BotControl(void) { - int i; - for (i = 0; i < 32; i++) + for (auto& bot : m_bots) { - if (m_bots[i]) - { - delete m_bots[i]; - m_bots[i] = nullptr; - } + if (bot == nullptr) + continue; + + delete bot; + bot = nullptr; } } @@ -83,7 +86,6 @@ void BotControl::CallGameEntity(entvars_t* vars) } static EntityPtr_t playerFunction = nullptr; - if (playerFunction == nullptr) playerFunction = (EntityPtr_t)g_gameLib->GetFunctionAddr("player"); @@ -91,11 +93,9 @@ void BotControl::CallGameEntity(entvars_t* vars) (*playerFunction) (vars); } -// this function completely prepares bot entity (edict) for creation, creates team, skill, sets name etc, and -// then sends result to bot constructor +// this function completely prepares bot entity (edict) for creation, creates team, skill, sets name etc, and then sends result to bot constructor int BotControl::CreateBot(String name, int skill, int personality, int team, int member) { - edict_t* bot = nullptr; if (g_numWaypoints < 1) // don't allow creating bots with no waypoints loaded { ServerPrint("No any waypoints for this map, Cannot Add E-BOT"); @@ -115,28 +115,28 @@ int BotControl::CreateBot(String name, int skill, int personality, int team, int if (ebot_difficulty.GetInt() >= 4) skill = 100; else if (ebot_difficulty.GetInt() == 3) - skill = CRandomInt(79, 99); + skill = crandomint(79, 99); else if (ebot_difficulty.GetInt() == 2) - skill = CRandomInt(50, 79); + skill = crandomint(50, 79); else if (ebot_difficulty.GetInt() == 1) - skill = CRandomInt(30, 50); + skill = crandomint(30, 50); else if (ebot_difficulty.GetInt() == 0) - skill = CRandomInt(1, 30); + skill = crandomint(1, 30); else { - int maxSkill = ebot_maxskill.GetInt(); - int minSkill = (ebot_minskill.GetInt() == 0) ? 1 : ebot_minskill.GetInt(); + const int maxSkill = ebot_maxskill.GetInt(); + const int minSkill = (ebot_minskill.GetInt() == 0) ? 1 : ebot_minskill.GetInt(); if (maxSkill <= 100 && minSkill > 0) - skill = CRandomInt(minSkill, maxSkill); + skill = crandomint(minSkill, maxSkill); else - skill = CRandomInt(0, 100); + skill = crandomint(0, 100); } } if (personality < 0 || personality > 2) { - int randomPrecent = CRandomInt(1, 3); + const int randomPrecent = crandomint(1, 3); if (randomPrecent == 1) personality = PERSONALITY_NORMAL; @@ -185,7 +185,7 @@ int BotControl::CreateBot(String name, int skill, int personality, int team, int } } else - sprintf(outputName, "e-bot %i", CRandomInt(1, 9999)); // just pick ugly random name + sprintf(outputName, "e-bot %i", crandomint(1, 9999)); // just pick ugly random name } else sprintf(outputName, "%s", (char*)name); @@ -198,6 +198,7 @@ int BotControl::CreateBot(String name, int skill, int personality, int team, int else cstrncpy(botName, outputName, sizeof(botName)); + edict_t* bot = nullptr; if (FNullEnt((bot = (*g_engfuncs.pfnCreateFakeClient) (botName)))) { CenterPrint(" Unable to create E-Bot, Maximum players reached (%d/%d)", engine->GetMaxClients(), engine->GetMaxClients()); @@ -219,7 +220,7 @@ int BotControl::GetIndex(edict_t* ent) if (FNullEnt(ent)) return -1; - int index = ENTINDEX(ent) - 1; + const int index = ENTINDEX(ent) - 1; if (index < 0 || index >= 32) return -1; @@ -230,7 +231,7 @@ int BotControl::GetIndex(edict_t* ent) } // this function returns index of bot (using own bot array) -int BotControl::GetIndex(int index) +int BotControl::GetIndex(const int index) { if (index < 0 || index >= 32) return -1; @@ -242,7 +243,7 @@ int BotControl::GetIndex(int index) } // this function finds a bot specified by index, and then returns pointer to it (using own bot array) -Bot* BotControl::GetBot(int index) +Bot* BotControl::GetBot(const int index) { if (index < 0 || index >= 32) return nullptr; @@ -266,8 +267,13 @@ Bot* BotControl::FindOneValidAliveBot(void) for (const auto& bot : m_bots) { - if (bot != nullptr && bot->m_isAlive) - foundBots.Push(bot->m_index - 1); + if (bot == nullptr) + continue; + + if (!bot->m_isAlive) + continue; + + foundBots.Push(bot->m_index - 1); } if (!foundBots.IsEmpty()) @@ -289,7 +295,7 @@ void BotControl::DoJoinQuitStuff(void) return; // add one more - if (CRandomInt(1, GetHumansNum()) <= 2); + if (crandomint(1, GetHumansNum()) < 3); g_botManager->AddRandom(); g_botManager->AddRandom(); @@ -303,7 +309,7 @@ void BotControl::DoJoinQuitStuff(void) if (min > max) max = min * 1.5f; - m_randomJoinTime = engine->GetTime() + CRandomFloat(min, max); + m_randomJoinTime = engine->GetTime() + crandomfloat(min, max); } void BotControl::Think(void) @@ -315,11 +321,10 @@ void BotControl::Think(void) if (bot == nullptr) continue; - if (bot->m_thinkDelay < engine->GetTime()) { bot->Think(); - bot->m_thinkDelay = engine->GetTime() + 0.1f; + bot->m_thinkDelay = engine->GetTime() + 0.05f; } if (bot->m_isAlive) @@ -351,98 +356,10 @@ void BotControl::AddBot(const String& name, int skill, int personality, int team void BotControl::CheckBotNum(void) { - if (ebot_auto_players.GetInt() == -1 && ebot_quota_save.GetInt() == -1) + if (ebot_auto_players.GetInt() < 1) return; int needBotNumber = 0; - if (ebot_quota_save.GetInt() != -1) - { - if (ebot_quota_save.GetInt() > 32) - ebot_quota_save.SetInt(32); - - needBotNumber = ebot_quota_save.GetInt(); - - File fp(FormatBuffer("%s/addons/ebot/ebot.cfg", GetModName()), "rt+"); - if (fp.IsValid()) - { - const char quotaCvar[11] = { 's', 'y', 'p', 'b', '_', 'q', 'u', 'o', 't', 'a', ' ' }; - - char line[256]; - bool changeed = false; - while (fp.GetBuffer(line, 255)) - { - bool trueCvar = true; - for (int j = 0; (j < 11 && trueCvar); j++) - { - if (quotaCvar[j] != line[j]) - trueCvar = false; - } - - if (!trueCvar) - continue; - - changeed = true; - - int i = 0; - for (i = 0; i <= 255; i++) - { - if (line[i] == 0) - break; - } - i++; - fp.Seek(-i, SEEK_CUR); - - if (line[11] == 0 || line[12] == 0 || line[13] == '"' || - line[11] == '\n' || line[12] == '\n') - { - changeed = false; - fp.Printf("//////////"); - break; - } - - if (line[11] == '"') - { - fp.PutString(FormatBuffer("ebot_quota \"%s%d\"", - needBotNumber > 10 ? "" : "0", needBotNumber)); - } - else - fp.PutString(FormatBuffer("ebot_quota %s%d", - needBotNumber > 10 ? "" : "0", needBotNumber)); - - ServerPrint("ebot_quota save to '%d' - C", needBotNumber); - - break; - } - - if (!changeed) - { - fp.Seek(0, SEEK_END); - fp.Printf(FormatBuffer("\nebot_quota \"%s%d\"\n", - needBotNumber > 10 ? "" : "0", needBotNumber)); - - ServerPrint("ebot_quota save to '%d' - A", needBotNumber); - } - - fp.Close(); - } - else - { - File fp2(FormatBuffer("%s/addons/ebot/ebot.cfg", GetModName()), "at"); - if (fp2.IsValid()) - { - fp2.Printf(FormatBuffer("\nebot_quota \"%s%d\"\n", - needBotNumber > 10 ? "" : "0", needBotNumber)); - - ServerPrint("ebot_quota save to '%d' - A", needBotNumber); - fp2.Close(); - } - else - ServerPrint("Unknow Problem - Cannot save ebot quota"); - } - - ebot_quota_save.SetInt(-1); - } - if (ebot_auto_players.GetInt() != -1) { if (ebot_auto_players.GetInt() > engine->GetMaxClients()) @@ -452,7 +369,7 @@ void BotControl::CheckBotNum(void) } needBotNumber = ebot_auto_players.GetInt() - GetHumansNum(); - if (needBotNumber <= 0) + if (needBotNumber < 0) needBotNumber = 0; } @@ -517,8 +434,8 @@ void BotControl::MaintainBotQuota(void) g_botManager->CheckBotNum(); if (m_maintainTime < engine->GetTime()) { - int botNumber = GetBotsNum(); - int maxClients = engine->GetMaxClients(); + const int botNumber = GetBotsNum(); + const int maxClients = engine->GetMaxClients(); int desiredBotCount = ebot_quota.GetInt(); if (ebot_autovacate.GetBool()) @@ -594,15 +511,15 @@ void BotControl::FillServer(int selection, int personality, int skill, int numTo int randomizedSkill = 0; if (skill >= 0 && skill <= 20) - randomizedSkill = CRandomInt(0, 20); + randomizedSkill = crandomint(0, 20); else if (skill >= 20 && skill <= 40) - randomizedSkill = CRandomInt(20, 40); + randomizedSkill = crandomint(20, 40); else if (skill >= 40 && skill <= 60) - randomizedSkill = CRandomInt(40, 60); + randomizedSkill = crandomint(40, 60); else if (skill >= 60 && skill <= 80) - randomizedSkill = CRandomInt(60, 80); + randomizedSkill = crandomint(60, 80); else if (skill >= 80 && skill <= 99) - randomizedSkill = CRandomInt(80, 99); + randomizedSkill = crandomint(80, 99); else if (skill == 100) randomizedSkill = skill; @@ -620,8 +537,10 @@ void BotControl::RemoveAll(void) for (const auto& bot : m_bots) { - if (bot != nullptr) // is this slot used? - bot->Kick(); + if (bot == nullptr) // is this slot used? + continue; + + bot->Kick(); } m_creationTab.Destroy(); @@ -640,7 +559,10 @@ void BotControl::RemoveFromTeam(Team team, bool removeAll) { for (const auto& bot : m_bots) { - if (bot != nullptr && team == bot->m_team) + if (bot == nullptr) + continue; + + if (team == bot->m_team) { bot->Kick(); @@ -730,18 +652,18 @@ void BotControl::RemoveRandom(void) { for (const auto& bot : m_bots) { - if (bot != nullptr) // is this slot used? - { - bot->Kick(); - break; - } + if (bot == nullptr) + continue; + + bot->Kick(); + break; } } // this function sets bots weapon mode void BotControl::SetWeaponMode(int selection) { - int tabMapStandart[7][Const_NumWeapons] = + const int tabMapStandart[7][Const_NumWeapons] = { {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Knife only {-1,-1,-1, 2, 2, 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Pistols only @@ -752,7 +674,7 @@ void BotControl::SetWeaponMode(int selection) {-1,-1,-1, 2, 2, 0, 1, 2, 2, 2, 1, 2, 0, 2, 0, 0, 1, 0, 1, 1, 2, 2, 0, 1, 2, 1} // Standard }; - int tabMapAS[7][Const_NumWeapons] = + const int tabMapAS[7][Const_NumWeapons] = { {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Knife only {-1,-1,-1, 2, 2, 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // Pistols only @@ -793,15 +715,14 @@ void BotControl::SetWeaponMode(int selection) // this function lists bots currently playing on the server void BotControl::ListBots(void) { - ServerPrintNoTag("%-3.5s %-9.13s %-17.18s %-3.4s %-3.4s %-3.4s", "index", "name", "personality", "team", "skill", "frags"); + ServerPrintNoTag("%-3.5s %-9.13s %-17.18s %-3.4s %-3.4s %-3.4s", "Index", "Name", "Personality", "Team", "Skill", "Frags"); - for (const auto& client : g_clients) + for (const auto& bot : m_bots) { - edict_t* player = client.ent; + if (bot == nullptr) + continue; - // is this player slot valid - if (IsValidBot(player) && GetBot(player)) - ServerPrintNoTag("[%-3.1d] %-9.13s %-17.18s %-3.4s %-3.1d %-3.1d", client.index, GetEntityName(player), GetBot(player)->m_personality == PERSONALITY_RUSHER ? "rusher" : GetBot(player)->m_personality == PERSONALITY_NORMAL ? "normal" : "careful", GetTeam(player) != 0 ? "CT" : "T", GetBot(player)->m_skill, static_cast (player->v.frags)); + ServerPrintNoTag("[%-3.1d] %-9.13s %-17.18s %-3.4s %-3.1d %-3.1d", bot->GetIndex(), GetEntityName(bot->GetEntity()), bot->m_personality == PERSONALITY_RUSHER ? "Rusher" : bot->m_personality == PERSONALITY_NORMAL ? "Normal" : "Careful", GetTeam(bot->GetEntity()) != 0 ? "CT" : "TR", bot->m_skill, static_cast(bot->GetEntity()->v.frags)); } } @@ -811,8 +732,10 @@ int BotControl::GetBotsNum(void) int count = 0; for (const auto& bot : m_bots) { - if (bot != nullptr) - count++; + if (bot == nullptr) + continue; + + count++; } return count; @@ -827,15 +750,20 @@ int BotControl::GetHumansNum(void) if (client.index < 0) continue; - if (m_bots[client.index] == nullptr) - count++; + if (FNullEnt(client.ent)) + continue; + + if (m_bots[client.index] != nullptr) + continue; + + count++; } return count; } // this function returns bot with highest frag -Bot* BotControl::GetHighestSkillBot(int team) +Bot* BotControl::GetHighestSkillBot(const int team) { Bot* highFragBot = nullptr; @@ -861,7 +789,7 @@ Bot* BotControl::GetHighestSkillBot(int team) // this function decides is players on specified team is able to buy primary weapons by calculating players // that have not enough money to buy primary (with economics), and if this result higher 80%, player is can't // buy primary weapons. -void BotControl::CheckTeamEconomics(int team) +void BotControl::CheckTeamEconomics(const int team) { if (GetGameMode() != MODE_BASE) { @@ -878,6 +806,9 @@ void BotControl::CheckTeamEconomics(int team) if (client.index < 0) continue; + if (FNullEnt(client.ent)) + continue; + if (m_bots[client.index] != nullptr && m_bots[client.index]->m_team == team) { if (m_bots[client.index]->m_moneyAmount < 1600) @@ -889,7 +820,7 @@ void BotControl::CheckTeamEconomics(int team) m_economicsGood[team] = true; - if (numTeamPlayers <= 1) + if (numTeamPlayers < 2) return; // if 80 percent of team have no enough money to purchase primary weapon @@ -904,24 +835,27 @@ void BotControl::CheckTeamEconomics(int team) // this function free all bots slots (used on server shutdown) void BotControl::Free(void) { - int i; - for (i = 0; i < 32; i++) + for (auto& bot : m_bots) { - if (m_bots[i] != nullptr) - { - if (ebot_save_bot_names.GetBool()) - m_savedBotNames.Push(STRING(m_bots[i]->GetEntity()->v.netname)); + if (bot == nullptr) + continue; - m_bots[i]->m_stayTime = 0.0f; - delete m_bots[i]; - m_bots[i] = nullptr; - } + if (ebot_save_bot_names.GetBool()) + m_savedBotNames.Push(STRING(bot->pev->netname)); + + bot->m_stayTime = 0.0f; + delete bot; + bot = nullptr; } } // this function frees one bot selected by index (used on bot disconnect) -void BotControl::Free(int index) +void BotControl::Free(const int index) { + // WTF??? + if (m_bots[index] == nullptr) + return; + m_bots[index]->m_stayTime = 0.0f; delete m_bots[index]; m_bots[index] = nullptr; @@ -936,7 +870,7 @@ Bot::Bot(edict_t* bot, int skill, int personality, int team, int member) char rejectReason[128]; int clientIndex = ENTINDEX(bot); - cmemset(reinterpret_cast (this), 0, sizeof(*this)); + cmemset(reinterpret_cast(this), 0, sizeof(*this)); pev = &bot->v; @@ -956,10 +890,10 @@ Bot::Bot(edict_t* bot, int skill, int personality, int team, int member) if (g_gameVersion == HALFLIFE) { char c_topcolor[4], c_bottomcolor[4], c_model[32]; - sprintf(c_topcolor, "%d", CRandomInt(1, 254)); - sprintf(c_bottomcolor, "%d", CRandomInt(1, 254)); + sprintf(c_topcolor, "%d", crandomint(0, 255)); + sprintf(c_bottomcolor, "%d", crandomint(0, 255)); Array models = String("barney,gina,gman,gordon,helmet,hgrunt,recon,robo,scientist,zombie").Split(","); - sprintf(c_model, "%s", (char*)models[CRandomInt(0, models.GetElementNumber() - 1)]); + sprintf(c_model, "%s", models[crandomint(0, models.GetElementNumber() - 1)].GetBuffer()); SET_CLIENT_KEYVALUE(clientIndex, buffer, "topcolor", c_topcolor); SET_CLIENT_KEYVALUE(clientIndex, buffer, "bottomcolor", c_bottomcolor); SET_CLIENT_KEYVALUE(clientIndex, buffer, "model", c_model); @@ -969,7 +903,7 @@ Bot::Bot(edict_t* bot, int skill, int personality, int team, int member) SET_CLIENT_KEYVALUE(clientIndex, buffer, "*bot", "1"); rejectReason[0] = 0; // reset the reject reason template string - MDLL_ClientConnect(bot, "E-BOT", FormatBuffer("%d.%d.%d.%d", CRandomInt(1, 255), CRandomInt(1, 255), CRandomInt(1, 255), CRandomInt(1, 255)), rejectReason); + MDLL_ClientConnect(bot, "E-BOT", FormatBuffer("%d.%d.%d.%d", crandomint(1, 255), crandomint(1, 255), crandomint(1, 255), crandomint(1, 255)), rejectReason); // should be set after client connect if (ebot_display_avatar.GetBool() && !g_botManager->m_avatars.IsEmpty()) @@ -987,18 +921,18 @@ Bot::Bot(edict_t* bot, int skill, int personality, int team, int member) // initialize all the variables for this bot... m_notStarted = true; // hasn't joined game yet m_difficulty = ebot_difficulty.GetInt(); // set difficulty - m_basePingLevel = CRandomInt(11, 111); + m_basePingLevel = crandomint(11, 111); m_startAction = CMENU_IDLE; m_moneyAmount = 0; - m_logotypeIndex = CRandomInt(0, 5); + m_logotypeIndex = crandomint(0, 5); // initialize msec value m_msecInterval = engine->GetTime(); // assign how talkative this bot will be - m_sayTextBuffer.chatDelay = CRandomFloat(3.8f, 10.0f); - m_sayTextBuffer.chatProbability = CRandomInt(1, 100); + m_sayTextBuffer.chatDelay = crandomfloat(3.8f, 10.0f); + m_sayTextBuffer.chatProbability = crandomint(1, 100); m_isAlive = false; m_skill = skill; @@ -1011,20 +945,20 @@ Bot::Bot(edict_t* bot, int skill, int personality, int team, int member) { case 1: m_personality = PERSONALITY_RUSHER; - m_baseAgressionLevel = CRandomFloat(0.8f, 1.2f); - m_baseFearLevel = CRandomFloat(0.0f, 0.5f); + m_baseAgressionLevel = crandomfloat(0.8f, 1.2f); + m_baseFearLevel = crandomfloat(0.0f, 0.5f); break; case 2: m_personality = PERSONALITY_CAREFUL; - m_baseAgressionLevel = CRandomFloat(0.0f, 0.3f); - m_baseFearLevel = CRandomFloat(0.75f, 1.0f); + m_baseAgressionLevel = crandomfloat(0.0f, 0.3f); + m_baseFearLevel = crandomfloat(0.75f, 1.0f); break; default: m_personality = PERSONALITY_NORMAL; - m_baseAgressionLevel = CRandomFloat(0.4f, 0.8f); - m_baseFearLevel = CRandomFloat(0.4f, 0.8f); + m_baseAgressionLevel = crandomfloat(0.4f, 0.8f); + m_baseFearLevel = crandomfloat(0.4f, 0.8f); break; } @@ -1032,11 +966,11 @@ Bot::Bot(edict_t* bot, int skill, int personality, int team, int member) cmemset(&m_ammo, 0, sizeof(m_ammo)); m_currentWeapon = 0; // current weapon is not assigned at start - m_voicePitch = CRandomInt(80, 120); // assign voice pitch + m_voicePitch = crandomint(80, 120); // assign voice pitch m_agressionLevel = m_baseAgressionLevel; m_fearLevel = m_baseFearLevel; - m_nextEmotionUpdate = engine->GetTime() + 0.5f; + m_nextEmotionUpdate = engine->GetTime() + 1.0f; // just to be sure m_actMessageIndex = 0; @@ -1086,14 +1020,12 @@ void Bot::NewRound(void) if (ebot_always_use_2d.GetBool()) m_2dH = true; else - m_2dH = static_cast(CRandomInt(0, 1)); + m_2dH = static_cast(crandomint(0, 1)); if (ebot_heuristic_type.GetInt() > 0 && ebot_heuristic_type.GetInt() < 5) m_heuristic = ebot_heuristic_type.GetInt(); else - m_heuristic = CRandomInt(1, 4); - - int i = 0; + m_heuristic = crandomint(1, 4); // delete all allocated path nodes DeleteSearchNodes(); @@ -1112,9 +1044,11 @@ void Bot::NewRound(void) m_duckDefuseCheckTime = 0.0f; m_prevWptIndex = -1; - m_navTimeset = engine->GetTime(); + m_jumpFinished = true; + m_jumping = false; + // clear all states & tasks m_states = 0; ResetTasks(); @@ -1167,8 +1101,8 @@ void Bot::NewRound(void) m_targetEntity = nullptr; m_followWaitTime = 0.0f; - for (i = 0; i < Const_MaxHostages; i++) - m_hostages[i] = nullptr; + for (auto& hostage : m_hostages) + hostage = nullptr; m_isReloading = false; m_reloadState = RSTATE_NONE; @@ -1183,9 +1117,7 @@ void Bot::NewRound(void) m_blindButton = 0; m_blindTime = 0.0f; - m_jumpTime = 0.0f; m_isStuck = false; - m_jumpFinished = false; m_sayTextBuffer.timeNextChat = engine->GetTime(); m_sayTextBuffer.entityIndex = -1; @@ -1202,7 +1134,7 @@ void Bot::NewRound(void) m_currentWeapon = 0; } - m_nextBuyTime = engine->GetTime() + CRandomFloat(0.6f, 1.2f); + m_nextBuyTime = engine->GetTime() + crandomfloat(0.6f, 1.2f); m_inBombZone = false; m_shieldCheckTime = 0.0f; @@ -1219,7 +1151,7 @@ void Bot::NewRound(void) m_radioOrder = 0; m_defendedBomb = false; - m_timeLogoSpray = engine->GetTime() + CRandomFloat(0.5f, 2.0f); + m_timeLogoSpray = engine->GetTime() + crandomfloat(0.5f, 2.0f); m_spawnTime = engine->GetTime(); m_lastChatTime = engine->GetTime(); pev->button = 0; @@ -1233,8 +1165,8 @@ void Bot::NewRound(void) m_heardSoundTime = engine->GetTime() - 8.0f; // clear its message queue - for (i = 0; i < 32; i++) - m_messageQueue[i] = CMENU_IDLE; + for (auto& message : m_messageQueue) + message = CMENU_IDLE; m_actMessageIndex = 0; m_pushMessageIndex = 0; @@ -1255,13 +1187,24 @@ void Bot::NewRound(void) PushMessageQueue(CMENU_BUY); } - PushTask(TASK_NORMAL, TASKPRI_NORMAL, -1, 1.0f, true); + PushTask(TASK_NORMAL, TASKPRI_NORMAL, 1.0f, true); // hear range based on difficulty - m_maxhearrange = float(m_skill * CRandomFloat(7.0f, 15.0f)); + m_maxhearrange = float(m_skill * crandomfloat(7.0f, 15.0f)); m_moveSpeed = pev->maxspeed; - m_tempstrafeSpeed = CRandomInt(1, 2) == 1 ? pev->maxspeed : -pev->maxspeed; + m_tempstrafeSpeed = crandomint(1, 2) == 1 ? pev->maxspeed : -pev->maxspeed; + +#ifdef WIN32 + thread core(&Waypoint::FindNearestInCircleThread, g_waypoint, pev->origin, 99999.0f, ref(m_currentWaypointIndex)); +#else + const auto reff = ref(m_currentWaypointIndex); + cthread core([this, reff]() { Waypoint::GetObjectPtr()->FindNearestInCircleThread(pev->origin, 99999.0f, reff); }); +#endif + core.join(); + + if (!IsValidWaypoint(m_currentWaypointIndex)) + m_currentWaypointIndex = g_waypoint->FindNearestInCircle(pev->origin, 999999.0f); } // this function kills a bot (not just using ClientKill, but like the CSBot does) @@ -1284,7 +1227,7 @@ void Bot::Kill(void) (*g_engfuncs.pfnSetOrigin) (hurtEntity, Vector(-4000.0f, -4000.0f, -4000.0f)); KeyValueData kv; - kv.szClassName = const_cast (g_weaponDefs[m_currentWeapon].className); + kv.szClassName = const_cast(g_weaponDefs[m_currentWeapon].className); kv.szKeyName = "damagetype"; kv.szValue = FormatBuffer("%d", (1 << 4)); kv.fHandled = false; @@ -1299,18 +1242,16 @@ void Bot::Kill(void) void Bot::Kick(void) { - edict_t* me = GetEntity(); - const char* myName = GetEntityName(me); + const char* myName = GetEntityName(GetEntity()); if (IsNullString(myName)) return; pev->flags |= FL_DORMANT; - const char* name = GetEntityName(me); - ServerCommand("kick \"%s\"", name); + ServerCommand("kick \"%s\"", myName); pev->flags |= FL_KILLME; if (!IsDedicatedServer()) - CenterPrint("E-Bot '%s' kicked from the server", name); + CenterPrint("E-Bot '%s' kicked from the server", myName); if (g_botManager->GetBotsNum() - 1 < ebot_quota.GetInt()) ebot_quota.SetInt(g_botManager->GetBotsNum() - 1); @@ -1324,7 +1265,7 @@ void Bot::StartGame(void) { if (g_gameVersion == HALFLIFE) { - if (CRandomInt(1, 5) == 1) + if (crandomint(1, 5) == 1) ChatMessage(CHAT_HELLO); m_notStarted = false; @@ -1335,7 +1276,7 @@ void Bot::StartGame(void) // check if something has assigned team to us if ((m_team == TEAM_TERRORIST || m_team == TEAM_COUNTER) && IsAlive(GetEntity())) { - if (CRandomInt(1, 5) == 1) + if (crandomint(1, 5) == 1) ChatMessage(CHAT_HELLO); m_notStarted = false; @@ -1379,7 +1320,7 @@ void Bot::StartGame(void) else if (m_startAction == CMENU_CLASS) { const int maxChoice = g_gameVersion == CSVER_CZERO ? 5 : 4; - m_wantedClass = CRandomInt(1, maxChoice); + m_wantedClass = crandomint(1, maxChoice); // select the class the bot wishes to use... FakeClientCommand(GetEntity(), "menuselect %d", maxChoice); @@ -1388,7 +1329,7 @@ void Bot::StartGame(void) m_notStarted = false; // check for greeting other players, since we connected - if (CRandomInt(1, 5) == 1) + if (crandomint(1, 5) == 1) ChatMessage(CHAT_HELLO); m_startAction = CMENU_IDLE; // switch back to idle diff --git a/source/engine.cpp b/source/engine.cpp index 7790c0f..4995efe 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -310,9 +310,13 @@ bool Client::IsInViewCone(const Vector& pos) const bool Client::IsVisible(const Vector& pos) const { - Tracer trace(GetHeadOrigin(), pos, NO_BOTH, m_ent); + TraceResult tr{}; + TraceLine(GetHeadOrigin(), pos, true, true, m_ent, &tr); - return !(trace.Fire() != 1.0); + if (tr.flFraction == 1.0f) + return true; + + return false; } bool Client::HasFlag(int clientFlags) @@ -335,7 +339,6 @@ void Client::Maintain(const Entity& ent) if (ent.IsPlayer()) { m_ent = ent; - m_safeOrigin = ent.GetOrigin(); m_flags |= ent.IsAlive() ? CLIENT_VALID | CLIENT_ALIVE : CLIENT_VALID; } diff --git a/source/globals.cpp b/source/globals.cpp index 7089058..e0539c3 100644 --- a/source/globals.cpp +++ b/source/globals.cpp @@ -171,28 +171,28 @@ plugin_info_t Plugin_info = // table with all available actions for the bots (filtered in & out in Bot::SetConditions) some of them have subactions included TaskItem g_taskFilters[] = { - {TASK_NORMAL, 0, -1, 0.0f, true}, - {TASK_PAUSE, 0, -1, 0.0f, false}, - {TASK_MOVETOPOSITION, 0, -1, 0.0f, true}, - {TASK_FOLLOWUSER, 0, -1, 0.0f, true}, - {TASK_PICKUPITEM, 0, -1, 0.0f, true}, - {TASK_CAMP, 0, -1, 0.0f, true}, - {TASK_PLANTBOMB, 0, -1, 0.0f, false}, - {TASK_DEFUSEBOMB, 0, -1, 0.0f, false}, - {TASK_FIGHTENEMY, 0, -1, 0.0f, false}, - {TASK_HUNTENEMY, 0, -1, 0.0f, false}, - {TASK_SEEKCOVER, 0, -1, 0.0f, false}, - {TASK_THROWHEGRENADE, 0, -1, 0.0f, false}, - {TASK_THROWFBGRENADE, 0, -1, 0.0f, false}, - {TASK_THROWSMGRENADE, 0, -1, 0.0f, false}, - {TASK_DOUBLEJUMP, 0, -1, 0.0f, false}, - {TASK_ESCAPEFROMBOMB, 0, -1, 0.0f, false}, - {TASK_DESTROYBREAKABLE, 0, -1, 0.0f, false}, - {TASK_HIDE, 0, -1, 0.0f, false}, - {TASK_BLINDED, 0, -1, 0.0f, false}, - {TASK_SPRAYLOGO, 0, -1, 0.0f, false}, - {TASK_MOVETOTARGET, 0, -1, 0.0f, true}, - {TASK_GOINGFORCAMP, 0, -1, 0.0f, true} + {TASK_NORMAL, 0, 0.0f, true}, + {TASK_PAUSE, 0, 0.0f, false}, + {TASK_MOVETOPOSITION, 0, 0.0f, true}, + {TASK_FOLLOWUSER, 0, 0.0f, true}, + {TASK_PICKUPITEM, 0, 0.0f, true}, + {TASK_CAMP, 0, 0.0f, true}, + {TASK_PLANTBOMB, 0, 0.0f, false}, + {TASK_DEFUSEBOMB, 0, 0.0f, false}, + {TASK_FIGHTENEMY, 0, 0.0f, false}, + {TASK_HUNTENEMY, 0, 0.0f, false}, + {TASK_SEEKCOVER, 0, 0.0f, false}, + {TASK_THROWHEGRENADE, 0, 0.0f, false}, + {TASK_THROWFBGRENADE, 0, 0.0f, false}, + {TASK_THROWSMGRENADE, 0, 0.0f, false}, + {TASK_DOUBLEJUMP, 0, 0.0f, false}, + {TASK_ESCAPEFROMBOMB, 0, 0.0f, false}, + {TASK_DESTROYBREAKABLE, 0, 0.0f, false}, + {TASK_HIDE, 0, 0.0f, false}, + {TASK_BLINDED, 0, 0.0f, false}, + {TASK_SPRAYLOGO, 0, 0.0f, false}, + {TASK_MOVETOTARGET, 0, 0.0f, true}, + {TASK_GOINGFORCAMP, 0, 0.0f, true} }; WeaponSelect g_weaponSelect[Const_NumWeapons + 1] = diff --git a/source/interface.cpp b/source/interface.cpp index 913e005..128db9f 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -206,7 +206,7 @@ int BotCommandHandler_O(edict_t* ent, const String& arg0, const String& arg1, co " Website: " PRODUCT_URL "\n" "+---------------------------------------------------------------------------------+\n"; - HudMessage(ent, true, Color(CRandomInt(33, 255), CRandomInt(33, 255), CRandomInt(33, 255)), aboutData); + HudMessage(ent, true, Color(crandomint(33, 255), crandomint(33, 255), crandomint(33, 255)), aboutData); } // displays version information @@ -311,7 +311,7 @@ int BotCommandHandler_O(edict_t* ent, const String& arg0, const String& arg1, co { int i; for (i = 0; i < 500; i++) - ServerPrintNoTag("Result Range[0 - 100]: %d", CRandomInt(0, 100)); + ServerPrintNoTag("Result Range[0 - 100]: %d", crandomint(0, 100)); } } @@ -435,7 +435,7 @@ int BotCommandHandler_O(edict_t* ent, const String& arg0, const String& arg1, co ClientPrint(ent, print_withtag, "Please set mesh , min 0, max 255"); else { - const int index = g_waypoint->FindNearest(GetEntityOrigin(g_hostEntity), 75.0f); + const int index = g_waypoint->FindNearestInCircle(GetEntityOrigin(g_hostEntity), 75.0f); if (IsValidWaypoint(index)) { g_waypoint->GetPath(index)->mesh = catoi(arg2); @@ -453,7 +453,7 @@ int BotCommandHandler_O(edict_t* ent, const String& arg0, const String& arg1, co ClientPrint(ent, print_withtag, "Please set gravity "); else { - const int index = g_waypoint->FindNearest(GetEntityOrigin(g_hostEntity), 75.0f); + const int index = g_waypoint->FindNearestInCircle(GetEntityOrigin(g_hostEntity), 75.0f); if (IsValidWaypoint(index)) { g_waypoint->GetPath(index)->gravity = cabsf(catof(arg2)); @@ -1194,11 +1194,11 @@ int Spawn(edict_t* ent) else if (cstrcmp(entityClassname, "func_escapezone") == 0) g_mapType |= MAP_ES; // next maps doesn't have map-specific entities, so determine it by name - else if (cstrncmp(GetMapName(), "fy_", 3) == 0) // fun map + else if (cstrncmp(GetMapName(), "fy_", 4) == 0) // fun map g_mapType |= MAP_FY; - else if (cstrncmp(GetMapName(), "ka_", 3) == 0) // knife arena map + else if (cstrncmp(GetMapName(), "ka_", 4) == 0) // knife arena map g_mapType |= MAP_KA; - else if (cstrncmp(GetMapName(), "awp_", 4) == 0) // awp only map + else if (cstrncmp(GetMapName(), "awp_", 5) == 0) // awp only map g_mapType |= MAP_AWP; else if (cstrncmp(GetMapName(), "he_", 4) == 0) // grenade wars g_mapType |= MAP_HE; @@ -1252,7 +1252,7 @@ void Touch(edict_t* pentTouched, edict_t* pentOther) if (!FNullEnt(pentTouched) && !FNullEnt(pentOther)) { - Bot* bot = g_botManager->GetBot(const_cast (pentOther)); + Bot* bot = g_botManager->GetBot(pentOther); if (bot != nullptr) bot->CheckTouchEntity(pentTouched); } @@ -1288,7 +1288,7 @@ int ClientConnect(edict_t* ent, const char* name, const char* addr, char rejectR // callbacks->OnClientConnect (ent, name, addr); // check if this client is the listen server client - if (cstrcmp(addr, "loopback") == 0) + if (cstrncmp(addr, "loopback", 9) == 0) g_hostEntity = ent; // save the edict of the listen server client... LoadEntityData(); @@ -1315,7 +1315,8 @@ void ClientDisconnect(edict_t* ent) const int i = ENTINDEX(ent) - 1; // check if its a bot - if (g_botManager->GetBot(i) != nullptr && g_botManager->GetBot(i)->pev == &ent->v) + Bot* bot = g_botManager->GetBot(i); + if (bot != nullptr && bot->pev->pContainingEntity == ent) g_botManager->Free(i); LoadEntityData(); @@ -1344,9 +1345,9 @@ void ClientUserInfoChanged(edict_t* ent, char* infobuffer) (*g_functionTable.pfnClientUserInfoChanged) (ent, infobuffer); } - int clientIndex = ENTINDEX(ent) - 1; + const int clientIndex = ENTINDEX(ent) - 1; - if (cstrcmp(password, INFOKEY_VALUE(infobuffer, const_cast (passwordField))) == 0) + if (cstrcmp(password, INFOKEY_VALUE(infobuffer, const_cast(passwordField))) == 0) g_clients[clientIndex].flags |= CFLAG_OWNER; else g_clients[clientIndex].flags &= ~CFLAG_OWNER; @@ -1382,7 +1383,7 @@ void ClientCommand(edict_t* ent) { if (cstricmp(command, "ebot") == 0) { - int state = BotCommandHandler(ent, IsNullString(CMD_ARGV(1)) ? "help" : CMD_ARGV(1), CMD_ARGV(2), CMD_ARGV(3), CMD_ARGV(4), CMD_ARGV(5), CMD_ARGV(6)); + const int state = BotCommandHandler(ent, IsNullString(CMD_ARGV(1)) ? "help" : CMD_ARGV(1), CMD_ARGV(2), CMD_ARGV(3), CMD_ARGV(4), CMD_ARGV(5), CMD_ARGV(6)); switch (state) { @@ -1406,7 +1407,7 @@ void ClientCommand(edict_t* ent) else if (cstricmp(command, "menuselect") == 0 && !IsNullString(arg1) && g_clients[ENTINDEX(ent) - 1].menu != nullptr) { Clients* client = &g_clients[ENTINDEX(ent) - 1]; - int selection = catoi(arg1); + const int selection = catoi(arg1); if (client->menu == &g_menus[12]) { @@ -1676,31 +1677,35 @@ void ClientCommand(edict_t* ent) int i; for (i = 0; i < g_numWaypoints; i++) { - if (g_waypoint->GetPath(i)->flags & WAYPOINT_TERRORIST) + const Path* pointer = g_waypoint->GetPath(i); + if (pointer == nullptr) + continue; + + if (pointer->flags & WAYPOINT_TERRORIST) terrPoints++; - if (g_waypoint->GetPath(i)->flags & WAYPOINT_COUNTER) + if (pointer->flags & WAYPOINT_COUNTER) ctPoints++; - if (g_waypoint->GetPath(i)->flags & WAYPOINT_GOAL) + if (pointer->flags & WAYPOINT_GOAL) goalPoints++; - if (g_waypoint->GetPath(i)->flags & WAYPOINT_RESCUE) + if (pointer->flags & WAYPOINT_RESCUE) rescuePoints++; - if (g_waypoint->GetPath(i)->flags & WAYPOINT_CAMP) + if (pointer->flags & WAYPOINT_CAMP) campPoints++; - if (g_waypoint->GetPath(i)->flags & WAYPOINT_SNIPER) + if (pointer->flags & WAYPOINT_SNIPER) sniperPoints++; - if (g_waypoint->GetPath(i)->flags & WAYPOINT_AVOID) + if (pointer->flags & WAYPOINT_AVOID) avoidPoints++; - if (g_waypoint->GetPath(i)->flags & WAYPOINT_USEBUTTON) + if (pointer->flags & WAYPOINT_USEBUTTON) usePoints++; - if (g_waypoint->GetPath(i)->flags & WAYPOINT_HMCAMPMESH) + if (pointer->flags & WAYPOINT_HMCAMPMESH) meshPoints++; } @@ -1773,7 +1778,7 @@ void ClientCommand(edict_t* ent) const int radiusValue[] = { 0, 8, 16, 32, 48, 64, 80, 96, 128 }; - if ((selection >= 1) && (selection <= 9)) + if (selection >= 1 && selection <= 9) g_waypoint->SetRadius(radiusValue[selection - 1]); if (g_isMetamod) @@ -1902,7 +1907,7 @@ void ClientCommand(edict_t* ent) { case 1: case 2: - if (FindNearestPlayer(reinterpret_cast (&bot), client->ent, 4096.0, true, true, true)) + if (FindNearestPlayer(reinterpret_cast(&bot), client->ent, 4096.0f, true, true, true)) { if (!(bot->pev->weapons & (1 << WEAPON_C4)) && !bot->HasHostage() && (bot->GetCurrentTaskID() != TASK_PLANTBOMB) && (bot->GetCurrentTaskID() != TASK_DEFUSEBOMB)) { @@ -1913,7 +1918,7 @@ void ClientCommand(edict_t* ent) bot->m_doubleJumpOrigin = GetEntityOrigin(client->ent); bot->m_doubleJumpEntity = client->ent; - bot->PushTask(TASK_DOUBLEJUMP, TASKPRI_DOUBLEJUMP, -1, engine->GetTime(), true); + bot->PushTask(TASK_DOUBLEJUMP, TASKPRI_DOUBLEJUMP, engine->GetTime(), true); bot->ChatSay(true, FormatBuffer("Ok %s, i will help you!", GetEntityName(ent))); } else if (selection == 2) @@ -1925,7 +1930,7 @@ void ClientCommand(edict_t* ent) case 3: case 4: - if (FindNearestPlayer(reinterpret_cast (&bot), ent, 300.0, true, true, true)) + if (FindNearestPlayer(reinterpret_cast (&bot), ent, 300.0f, true, true, true)) bot->DiscardWeaponForUser(ent, selection == 4 ? false : true); break; @@ -2206,23 +2211,23 @@ void ClientCommand(edict_t* ent) switch (selection) { case 1: - g_storeAddbotVars[0] = CRandomInt(0, 20); + g_storeAddbotVars[0] = crandomint(0, 20); break; case 2: - g_storeAddbotVars[0] = CRandomInt(20, 40); + g_storeAddbotVars[0] = crandomint(20, 40); break; case 3: - g_storeAddbotVars[0] = CRandomInt(40, 60); + g_storeAddbotVars[0] = crandomint(40, 60); break; case 4: - g_storeAddbotVars[0] = CRandomInt(60, 80); + g_storeAddbotVars[0] = crandomint(60, 80); break; case 5: - g_storeAddbotVars[0] = CRandomInt(80, 99); + g_storeAddbotVars[0] = crandomint(80, 99); break; case 6: @@ -2874,7 +2879,7 @@ int Spawn_Post(edict_t* ent) ent->v.flags &= ~FL_WORLDBRUSH; // clear the FL_WORLDBRUSH flag out of transparent ents // reset bot - auto bot = g_botManager->GetBot(ent); + Bot* bot = g_botManager->GetBot(ent); if (bot != nullptr) bot->NewRound(); @@ -2940,7 +2945,8 @@ void pfnChangeLevel(char* s1, char* s2) edict_t* pfnFindEntityByString(edict_t* edictStartSearchAfter, const char* field, const char* value) { // round starts in counter-strike 1.5 - if (cstrcmp(value, "info_map_parameters") == 0) + const char* cs = "info_map_parameters"; + if (cstrncmp(value, cs, sizeof(cs)) == 0) RoundInit(); if (g_isMetamod) @@ -2969,49 +2975,10 @@ void pfnEmitSound(edict_t* entity, int channel, const char* sample, float volume (*g_engfuncs.pfnEmitSound) (entity, channel, sample, volume, attenuation, flags, pitch); } -void pfnClientCommand(edict_t* ent, char* format, ...) -{ - // this function forces the client whose player entity is ent to issue a client command. - // How it works is that clients all have a g_xgv global string in their client DLL that - // stores the command string; if ever that string is filled with characters, the client DLL - // sends it to the engine as a command to be executed. When the engine has executed that - // command, this g_xgv string is reset to zero. Here is somehow a curious implementation of - // ClientCommand: the engine sets the command it wants the client to issue in his g_xgv, then - // the client DLL sends it back to the engine, the engine receives it then executes the - // command therein. Don't ask me why we need all this complicated crap. Anyhow since bots have - // no client DLL, be certain never to call this function upon a bot entity, else it will just - // make the server crash. Since hordes of uncautious, not to say stupid, programmers don't - // even imagine some players on their servers could be bots, this check is performed less than - // sometimes actually by their side, that's why we strongly recommend to check it here too. In - // case it's a bot asking for a client command, we handle it like we do for bot commands, ie - // using FakeClientCommand(). - - va_list ap; - char buffer[1024]; - - va_start(ap, format); - vsnprintf(buffer, sizeof(buffer), format, ap); - va_end(ap); - - // is the target entity an official bot, or a third party bot ? - if (IsValidBot(ent) || (ent->v.flags & FL_DORMANT)) - { - if (g_isMetamod) - RETURN_META(MRES_SUPERCEDE); // prevent bots to be forced to issue client commands - - return; - } - - if (g_isMetamod) - RETURN_META(MRES_IGNORED); - - CLIENT_COMMAND(ent, buffer); -} - // this function called each time a message is about to sent void pfnMessageBegin(int msgDest, int msgType, const float* origin, edict_t* ed) { - // store the message type in our own variables, since the GET_USER_MSG_ID () will just do a lot of cstrcmp()'s... + // store the message type in our own variables, since the GET_USER_MSG_ID() will just do a lot of strcmp()'s... if (g_isMetamod && NetworkMsg::GetObjectPtr()->GetId(NETMSG_MONEY) == -1) { NetworkMsg::GetObjectPtr()->SetId(NETMSG_VGUI, GET_USER_MSG_ID(PLID, "VGUIMenu", nullptr)); @@ -3023,7 +2990,7 @@ void pfnMessageBegin(int msgDest, int msgType, const float* origin, edict_t* ed) NetworkMsg::GetObjectPtr()->SetId(NETMSG_DAMAGE, GET_USER_MSG_ID(PLID, "Damage", nullptr)); NetworkMsg::GetObjectPtr()->SetId(NETMSG_MONEY, GET_USER_MSG_ID(PLID, "Money", nullptr)); NetworkMsg::GetObjectPtr()->SetId(NETMSG_STATUSICON, GET_USER_MSG_ID(PLID, "StatusIcon", nullptr)); - NetworkMsg::GetObjectPtr()->SetId(NETMSG_DEATH, GET_USER_MSG_ID(PLID, "DeathMsg", nullptr)); + //NetworkMsg::GetObjectPtr()->SetId(NETMSG_DEATH, GET_USER_MSG_ID(PLID, "DeathMsg", nullptr)); NetworkMsg::GetObjectPtr()->SetId(NETMSG_SCREENFADE, GET_USER_MSG_ID(PLID, "ScreenFade", nullptr)); NetworkMsg::GetObjectPtr()->SetId(NETMSG_HLTV, GET_USER_MSG_ID(PLID, "HLTV", nullptr)); NetworkMsg::GetObjectPtr()->SetId(NETMSG_TEXTMSG, GET_USER_MSG_ID(PLID, "TextMsg", nullptr)); @@ -3042,15 +3009,15 @@ void pfnMessageBegin(int msgDest, int msgType, const float* origin, edict_t* ed) NetworkMsg::GetObjectPtr()->HandleMessageIfRequired(msgType, NETMSG_WLIST); - if (!FNullEnt(ed)) + if (!FNullEnt(ed) && !(ed->v.flags & FL_DORMANT)) { - const int index = g_botManager->GetIndex(ed); + Bot* bot = g_botManager->GetBot(ed); // is this message for a bot? - if (index != -1 && !(ed->v.flags & FL_DORMANT) && g_botManager->GetBot(index)->GetEntity() == ed) + if (bot != nullptr && bot->pev->pContainingEntity == ed) { NetworkMsg::GetObjectPtr()->Reset(); - NetworkMsg::GetObjectPtr()->SetBot(g_botManager->GetBot(index)); + NetworkMsg::GetObjectPtr()->SetBot(bot); // message handling is done in usermsg.cpp NetworkMsg::GetObjectPtr()->HandleMessageIfRequired(msgType, NETMSG_VGUI); @@ -3071,15 +3038,17 @@ void pfnMessageBegin(int msgDest, int msgType, const float* origin, edict_t* ed) NetworkMsg::GetObjectPtr()->Reset(); //NetworkMsg::GetObjectPtr()->HandleMessageIfRequired (msgType, NETMSG_SCOREINFO); - NetworkMsg::GetObjectPtr()->HandleMessageIfRequired(msgType, NETMSG_DEATH); + //NetworkMsg::GetObjectPtr()->HandleMessageIfRequired(msgType, NETMSG_DEATH); NetworkMsg::GetObjectPtr()->HandleMessageIfRequired(msgType, NETMSG_TEXTMSG); if (msgType == SVC_INTERMISSION) { for (const auto& bot : g_botManager->m_bots) { - if (bot != nullptr) - bot->m_isAlive = false; + if (bot == nullptr) + continue; + + bot->m_isAlive = false; } } } @@ -3172,8 +3141,6 @@ void pfnWriteCoord(float value) void pfnWriteString(const char* sz) { - //Bot *bot = g_botManager->FindOneValidAliveBot (); - // if this message is for a bot, call the client message function... NetworkMsg::GetObjectPtr()->Execute((void*)sz); @@ -3339,78 +3306,50 @@ int pfnRegUserMsg(const char* name, int size) if (g_isMetamod) RETURN_META_VALUE(MRES_IGNORED, 0); - int message = REG_USER_MSG(name, size); + const int message = REG_USER_MSG(name, size); - if (cstrcmp(name, "VGUIMenu") == 0) + if (cstrncmp(name, "VGUIMenu", 9) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_VGUI, message); - else if (cstrcmp(name, "ShowMenu") == 0) + else if (cstrncmp(name, "ShowMenu", 9) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_SHOWMENU, message); - else if (cstrcmp(name, "WeaponList") == 0) + else if (cstrncmp(name, "WeaponList", 11) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_WLIST, message); - else if (cstrcmp(name, "CurWeapon") == 0) + else if (cstrncmp(name, "CurWeapon", 10) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_CURWEAPON, message); - else if (cstrcmp(name, "AmmoX") == 0) + else if (cstrncmp(name, "AmmoX", 6) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_AMMOX, message); - else if (cstrcmp(name, "AmmoPickup") == 0) + else if (cstrncmp(name, "AmmoPickup", 11) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_AMMOPICK, message); - else if (cstrcmp(name, "Damage") == 0) + else if (cstrncmp(name, "Damage", 7) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_DAMAGE, message); - else if (cstrcmp(name, "Money") == 0) + else if (cstrncmp(name, "Money", 6) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_MONEY, message); - else if (cstrcmp(name, "StatusIcon") == 0) + else if (cstrncmp(name, "StatusIcon", 11) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_STATUSICON, message); - else if (cstrcmp(name, "DeathMsg") == 0) - NetworkMsg::GetObjectPtr()->SetId(NETMSG_DEATH, message); - else if (cstrcmp(name, "ScreenFade") == 0) + //else if (cstrncmp(name, "DeathMsg", 9) == 0) + //NetworkMsg::GetObjectPtr()->SetId(NETMSG_DEATH, message); + else if (cstrncmp(name, "ScreenFade", 11) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_SCREENFADE, message); - else if (cstrcmp(name, "HLTV") == 0) + else if (cstrncmp(name, "HLTV", 5) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_HLTV, message); - else if (cstrcmp(name, "TextMsg") == 0) + else if (cstrncmp(name, "TextMsg", 8) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_TEXTMSG, message); - //else if (cstrcmp (name, "ScoreInfo") == 0) + //else if (cstrncmp (name, "ScoreInfo", 10) == 0) //NetworkMsg::GetObjectPtr()->SetId (NETMSG_SCOREINFO, message); - else if (cstrcmp(name, "BarTime") == 0) + else if (cstrncmp(name, "BarTime", 8) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_BARTIME, message); - else if (cstrcmp(name, "SendAudio") == 0) + else if (cstrncmp(name, "SendAudio", 10) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_SENDAUDIO, message); - else if (cstrcmp(name, "SayText") == 0) + else if (cstrncmp(name, "SayText", 8) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_SAYTEXT, message); - else if (cstrcmp(name, "BotVoice") == 0) + else if (cstrncmp(name, "BotVoice", 9) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_BOTVOICE, message); - else if (cstrcmp(name, "ResetHUD") == 0) + else if (cstrncmp(name, "ResetHUD", 9) == 0) NetworkMsg::GetObjectPtr()->SetId(NETMSG_BOTVOICE, message); return message; } -void pfnAlertMessage(ALERT_TYPE alertType, char* format, ...) -{ - va_list ap; - char buffer[1024]; - - va_start(ap, format); - vsprintf(buffer, format, ap); - va_end(ap); - - if (cstrstr(buffer, "_Defuse_") != nullptr) - { - // notify all terrorists that CT is starting bomb defusing - for (const auto& bot : g_botManager->m_bots) - { - if (bot != nullptr && bot->m_team == TEAM_TERRORIST && bot->m_isAlive) - { - bot->ResetTasks(); - bot->MoveToVector(g_waypoint->GetBombPosition()); - } - } - } - - if (g_isMetamod) - RETURN_META(MRES_IGNORED); - - (*g_engfuncs.pfnAlertMessage) (alertType, buffer); -} - gamedll_funcs_t gameDLLFunc; exportc int GetEntityAPI2(DLL_FUNCTIONS* functionTable, int* /*interfaceVersion*/) @@ -3541,7 +3480,6 @@ exportc int GetEngineFunctions(enginefuncs_t* functionTable, int* /*interfaceVer functionTable->pfnChangeLevel = pfnChangeLevel; functionTable->pfnFindEntityByString = pfnFindEntityByString; functionTable->pfnEmitSound = pfnEmitSound; - functionTable->pfnClientCommand = pfnClientCommand; functionTable->pfnMessageBegin = pfnMessageBegin; functionTable->pfnMessageEnd = pfnMessageEnd; functionTable->pfnWriteByte = pfnWriteByte; @@ -3558,7 +3496,6 @@ exportc int GetEngineFunctions(enginefuncs_t* functionTable, int* /*interfaceVer functionTable->pfnCmd_Argv = pfnCmd_Argv; functionTable->pfnCmd_Argc = pfnCmd_Argc; functionTable->pfnSetClientMaxspeed = pfnSetClientMaxspeed; - functionTable->pfnAlertMessage = pfnAlertMessage; functionTable->pfnGetPlayerAuthId = pfnGetPlayerAuthId; functionTable->pfnGetPlayerWONId = pfnGetPlayerWONId; diff --git a/source/navigate.cpp b/source/navigate.cpp index aaf3806..ba67366 100644 --- a/source/navigate.cpp +++ b/source/navigate.cpp @@ -23,7 +23,13 @@ // #include +#ifdef WIN32 +#include +#else +#include +#endif +ConVar ebot_debug_goal("ebot_debug_goal", "-1"); ConVar ebot_zombies_as_path_cost("ebot_zombie_count_as_path_cost", "1"); ConVar ebot_ping_affects_aim("ebot_ping_affects_aim", "0"); ConVar ebot_use_old_jump_method("ebot_use_old_jump_method", "0"); @@ -32,32 +38,40 @@ ConVar ebot_breakable_health_limit("ebot_breakable_health_limit", "3000.0"); int Bot::FindGoal(void) { + if (IsValidWaypoint(ebot_debug_goal.GetInt())) + return ebot_debug_goal.GetInt(); + + if (g_gameVersion == HALFLIFE) + return crandomint(0, g_numWaypoints - 1); + if (IsZombieMode()) { if (m_isZombieBot) { if (g_waypoint->m_terrorPoints.IsEmpty()) - return m_chosenGoalIndex = CRandomInt(0, g_numWaypoints - 1); + return crandomint(0, g_numWaypoints - 1); int i; Array Important; - for (int i = 0; i < g_waypoint->m_terrorPoints.GetElementNumber(); i++) + for (i = 0; i < g_waypoint->m_terrorPoints.GetElementNumber(); i++) { int index; - g_waypoint->m_terrorPoints.GetAt(i, index); + if (!g_waypoint->m_terrorPoints.GetAt(i, index)) + continue; + Important.Push(index); } if (!Important.IsEmpty()) - return m_chosenGoalIndex = Important.GetRandomElement(); + return Important.GetRandomElement(); } else if (IsValidWaypoint(m_myMeshWaypoint)) - return m_chosenGoalIndex = m_myMeshWaypoint; + return m_myMeshWaypoint; if (!g_waypoint->m_zmHmPoints.IsEmpty()) { // if round starts always go to nearest (zombies appeared) - if (g_DelayTimer <= engine->GetTime()) + if (g_DelayTimer < engine->GetTime()) { int targetWpIndex = -1; float distance = FLT_MAX; @@ -66,20 +80,23 @@ int Bot::FindGoal(void) for (i = 0; i < g_waypoint->m_zmHmPoints.GetElementNumber(); i++) { int wpIndex; - g_waypoint->m_zmHmPoints.GetAt(i, wpIndex); - if (IsValidWaypoint(wpIndex)) + if (!g_waypoint->m_zmHmPoints.GetAt(i, wpIndex)) + continue; + + const Path* pointer = g_waypoint->GetPath(wpIndex); + if (pointer == nullptr) + continue; + + const float theDistance = (pev->origin - pointer->origin).GetLengthSquared2D(); + if (theDistance < distance) { - const float theDistance = (pev->origin - g_waypoint->GetPath(wpIndex)->origin).GetLengthSquared2D(); - if (theDistance < distance) - { - distance = theDistance; - targetWpIndex = wpIndex; - } + distance = theDistance; + targetWpIndex = wpIndex; } } if (IsValidWaypoint(targetWpIndex)) - return m_chosenGoalIndex = targetWpIndex; + return targetWpIndex; } int i; @@ -87,18 +104,23 @@ int Bot::FindGoal(void) for (i = 0; i < g_waypoint->m_zmHmPoints.GetElementNumber(); i++) { int index; - g_waypoint->m_zmHmPoints.GetAt(i, index); + if (!g_waypoint->m_zmHmPoints.GetAt(i, index)) + continue; + + const Path* pointer = g_waypoint->GetPath(index); + if (pointer == nullptr) + continue; - if (m_numEnemiesLeft > 0 && m_numFriendsLeft > 0 && GetNearbyEnemiesNearPosition(g_waypoint->GetPath(index)->origin, 600.0f) > GetNearbyFriendsNearPosition(g_waypoint->GetPath(index)->origin, 600.0f)) + if (m_numEnemiesLeft > 0 && m_numFriendsLeft > 0 && GetNearbyEnemiesNearPosition(pointer->origin, 600.0f) > GetNearbyFriendsNearPosition(pointer->origin, 600.0f)) continue; ZombieWaypoints.Push(index); } if (!ZombieWaypoints.IsEmpty()) - return m_chosenGoalIndex = ZombieWaypoints.GetRandomElement(); + return m_zhCampPointIndex = ZombieWaypoints.GetRandomElement(); - if (!IsValidWaypoint(m_chosenGoalIndex)) + if (!IsValidWaypoint(m_zhCampPointIndex)) { int targetWpIndex = -1; float distance = FLT_MAX; @@ -106,32 +128,35 @@ int Bot::FindGoal(void) for (i = 0; i < g_waypoint->m_zmHmPoints.GetElementNumber(); i++) { int wpIndex; - g_waypoint->m_zmHmPoints.GetAt(i, wpIndex); - if (IsValidWaypoint(wpIndex)) - { - if (m_numEnemiesLeft > 0 && m_numFriendsLeft > 0 && GetNearbyEnemiesNearPosition(g_waypoint->GetPath(wpIndex)->origin, 600.0f) > GetNearbyFriendsNearPosition(g_waypoint->GetPath(wpIndex)->origin, 600.0f)) - continue; + if (!g_waypoint->m_zmHmPoints.GetAt(i, wpIndex)) + continue; - const float theDistance = (pev->origin - g_waypoint->GetPath(wpIndex)->origin).GetLengthSquared2D(); - if (theDistance < distance) - { - distance = theDistance; - targetWpIndex = wpIndex; - } + const Path* pointer = g_waypoint->GetPath(wpIndex); + if (pointer == nullptr) + continue; + + if (m_numEnemiesLeft > 0 && m_numFriendsLeft > 0 && GetNearbyEnemiesNearPosition(pointer->origin, 600.0f) > GetNearbyFriendsNearPosition(pointer->origin, 600.0f)) + continue; + + const float theDistance = (pev->origin - pointer->origin).GetLengthSquared2D(); + if (theDistance < distance) + { + distance = theDistance; + targetWpIndex = wpIndex; } } if (IsValidWaypoint(targetWpIndex)) - return m_chosenGoalIndex = targetWpIndex; + return targetWpIndex; } - if (!IsValidWaypoint(m_chosenGoalIndex)) - m_chosenGoalIndex = g_waypoint->m_zmHmPoints.GetRandomElement(); + if (!IsValidWaypoint(m_zhCampPointIndex)) + m_zhCampPointIndex = g_waypoint->m_zmHmPoints.GetRandomElement(); - return m_chosenGoalIndex; + return m_zhCampPointIndex; } else - return m_chosenGoalIndex = CRandomInt(0, g_numWaypoints - 1); + return crandomint(0, g_numWaypoints - 1); } else if (GetGameMode() == MODE_BASE) { @@ -146,7 +171,7 @@ int Bot::FindGoal(void) if (noTimeLeft) { TaskComplete(); - PushTask(TASK_ESCAPEFROMBOMB, TASKPRI_ESCAPEFROMBOMB, -1, 2.0f, true); + PushTask(TASK_ESCAPEFROMBOMB, TASKPRI_ESCAPEFROMBOMB, 2.0f, true); } else if (m_team == TEAM_COUNTER) { @@ -157,17 +182,15 @@ int Bot::FindGoal(void) { if (GetCurrentTaskID() != TASK_CAMP && GetCurrentTaskID() != TASK_GOINGFORCAMP) { - m_chosenGoalIndex = FindDefendWaypoint(bombOrigin); - if (IsValidWaypoint(m_chosenGoalIndex)) + const int index = FindDefendWaypoint(bombOrigin); + if (IsValidWaypoint(index)) { - m_campposition = g_waypoint->GetPath(m_chosenGoalIndex)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, m_chosenGoalIndex, GetBombTimeleft(), true); + m_campposition = g_waypoint->GetPath(index)->origin; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + GetBombTimeleft(), true); m_campButtons |= IN_DUCK; - return m_chosenGoalIndex; + return index; } } - else - return m_chosenGoalIndex; } else { @@ -179,9 +202,9 @@ int Bot::FindGoal(void) g_bombSayString = false; } - m_chosenGoalIndex = g_waypoint->FindNearest(bombOrigin, 999999.0f); - if (IsValidWaypoint(m_chosenGoalIndex)) - return m_chosenGoalIndex; + const int index = g_waypoint->FindNearestInCircle(bombOrigin, 999999.0f); + if (IsValidWaypoint(index)) + return index; } } } @@ -195,25 +218,23 @@ int Bot::FindGoal(void) if (GetCurrentTaskID() == TASK_CAMP || GetCurrentTaskID() == TASK_GOINGFORCAMP) TaskComplete(); - m_chosenGoalIndex = g_waypoint->FindNearest(bombOrigin, 999999.0f); - if (IsValidWaypoint(m_chosenGoalIndex)) - return m_chosenGoalIndex; + const int index = g_waypoint->FindNearestInCircle(bombOrigin, 999999.0f); + if (IsValidWaypoint(index)) + return index; } else { if (GetCurrentTaskID() != TASK_CAMP && GetCurrentTaskID() != TASK_GOINGFORCAMP) { - m_chosenGoalIndex = FindDefendWaypoint(bombOrigin); - if (IsValidWaypoint(m_chosenGoalIndex)) + const int index = FindDefendWaypoint(bombOrigin); + if (IsValidWaypoint(index)) { - m_campposition = g_waypoint->GetPath(m_chosenGoalIndex)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, m_chosenGoalIndex, GetBombTimeleft(), true); + m_campposition = g_waypoint->GetPath(index)->origin; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + GetBombTimeleft(), true); m_campButtons |= IN_DUCK; - return m_chosenGoalIndex; + return index; } } - else - return m_chosenGoalIndex; } } } @@ -230,20 +251,18 @@ int Bot::FindGoal(void) { if (GetCurrentTaskID() != TASK_CAMP && GetCurrentTaskID() != TASK_GOINGFORCAMP) { - m_chosenGoalIndex = FindDefendWaypoint(g_waypoint->GetPath(m_loosedBombWptIndex)->origin); + const int index = FindDefendWaypoint(g_waypoint->GetPath(m_loosedBombWptIndex)->origin); if (IsValidWaypoint(m_chosenGoalIndex)) { - m_campposition = g_waypoint->GetPath(m_chosenGoalIndex)->origin; - PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, m_chosenGoalIndex, GetBombTimeleft(), true); + m_campposition = g_waypoint->GetPath(index)->origin; + PushTask(TASK_GOINGFORCAMP, TASKPRI_GOINGFORCAMP, engine->GetTime() + GetBombTimeleft(), true); m_campButtons |= IN_DUCK; - return m_chosenGoalIndex; + return index; } } - else - return m_chosenGoalIndex; } else - return m_chosenGoalIndex = m_loosedBombWptIndex; + return m_loosedBombWptIndex; } else { @@ -251,9 +270,9 @@ int Bot::FindGoal(void) { if (!g_waypoint->m_ctPoints.IsEmpty()) { - m_chosenGoalIndex = g_waypoint->m_ctPoints.GetRandomElement(); - if (IsValidWaypoint(m_chosenGoalIndex)) - return m_chosenGoalIndex; + const int index = g_waypoint->m_ctPoints.GetRandomElement(); + if (IsValidWaypoint(index)) + return index; } } else @@ -266,12 +285,14 @@ int Bot::FindGoal(void) if (!g_waypoint->m_goalPoints.IsEmpty()) return m_chosenGoalIndex = g_waypoint->m_goalPoints.GetRandomElement(); } + else + return m_chosenGoalIndex; } else if (!g_waypoint->m_terrorPoints.IsEmpty()) { - m_chosenGoalIndex = g_waypoint->m_terrorPoints.GetRandomElement(); - if (IsValidWaypoint(m_chosenGoalIndex)) - return m_chosenGoalIndex; + const int index = g_waypoint->m_terrorPoints.GetRandomElement(); + if (IsValidWaypoint(index)) + return index; } } } @@ -288,21 +309,23 @@ int Bot::FindGoal(void) ohShit = true; if (!IsValidWaypoint(m_chosenGoalIndex) || !(g_waypoint->GetPath(m_chosenGoalIndex)->flags & WAYPOINT_RESCUE)) return m_chosenGoalIndex = g_waypoint->m_rescuePoints.GetRandomElement(); + else + return m_chosenGoalIndex; } else { - if (!g_waypoint->m_ctPoints.IsEmpty() && CRandomInt(1, 2) == 1) - return m_chosenGoalIndex = g_waypoint->m_ctPoints.GetRandomElement(); + if (!g_waypoint->m_ctPoints.IsEmpty() && crandomint(1, 2) == 1) + return g_waypoint->m_ctPoints.GetRandomElement(); else if (!g_waypoint->m_goalPoints.IsEmpty()) - return m_chosenGoalIndex = g_waypoint->m_goalPoints.GetRandomElement(); + return g_waypoint->m_goalPoints.GetRandomElement(); } } else { - if (!g_waypoint->m_rescuePoints.IsEmpty() && (ohShit || CRandomInt(1, 11) == 1)) - return m_chosenGoalIndex = g_waypoint->m_rescuePoints.GetRandomElement(); + if (!g_waypoint->m_rescuePoints.IsEmpty() && (ohShit || crandomint(1, 11) == 1)) + return g_waypoint->m_rescuePoints.GetRandomElement(); else if (!g_waypoint->m_goalPoints.IsEmpty()) - return m_chosenGoalIndex = g_waypoint->m_goalPoints.GetRandomElement(); + return g_waypoint->m_goalPoints.GetRandomElement(); } } else if (g_mapType & MAP_AS) @@ -310,21 +333,21 @@ int Bot::FindGoal(void) if (m_team == TEAM_COUNTER) { if (m_isVIP && !g_waypoint->m_goalPoints.IsEmpty()) - return m_chosenGoalIndex = g_waypoint->m_goalPoints.GetRandomElement(); + return g_waypoint->m_goalPoints.GetRandomElement(); else { - if (!g_waypoint->m_goalPoints.IsEmpty() && CRandomInt(1, 2) == 1) - return m_chosenGoalIndex = g_waypoint->m_goalPoints.GetRandomElement(); + if (!g_waypoint->m_goalPoints.IsEmpty() && crandomint(1, 2) == 1) + return g_waypoint->m_goalPoints.GetRandomElement(); else if (!g_waypoint->m_ctPoints.IsEmpty()) - return m_chosenGoalIndex = g_waypoint->m_ctPoints.GetRandomElement(); + return g_waypoint->m_ctPoints.GetRandomElement(); } } else { - if (!g_waypoint->m_goalPoints.IsEmpty() && CRandomInt(1, 11) == 1) - return m_chosenGoalIndex = g_waypoint->m_goalPoints.GetRandomElement(); + if (!g_waypoint->m_goalPoints.IsEmpty() && crandomint(1, 11) == 1) + return g_waypoint->m_goalPoints.GetRandomElement(); else if (!g_waypoint->m_terrorPoints.IsEmpty()) - return m_chosenGoalIndex = g_waypoint->m_terrorPoints.GetRandomElement(); + return g_waypoint->m_terrorPoints.GetRandomElement(); } } } @@ -334,148 +357,188 @@ int Bot::FindGoal(void) const Vector origin = GetEntityOrigin(m_lastEnemy); if (origin != nullvec) { - m_chosenGoalIndex = g_waypoint->FindNearest(origin, 9999999.0f, -1, m_lastEnemy); - if (IsValidWaypoint(m_chosenGoalIndex)) - return m_chosenGoalIndex; + const int index = g_waypoint->FindNearest(origin, 9999999.0f, -1, m_lastEnemy); + if (IsValidWaypoint(index)) + return index; } } - return m_chosenGoalIndex = g_waypoint->m_otherPoints.GetRandomElement(); + return crandomint(0, g_numWaypoints - 1); } bool Bot::GoalIsValid(void) { - const int goal = GetCurrentGoalID(); - if (!IsValidWaypoint(goal)) // not decided about a goal + if (!IsValidWaypoint(m_chosenGoalIndex)) // not decided about a goal return false; - else if (goal == m_currentWaypointIndex) // no nodes needed - return true; else if (m_navNode.IsEmpty()) // no path calculated return false; + else if (m_chosenGoalIndex == m_navNode.Last()) + return true; - return (goal == m_navNode.Last()); + return false; } // this function is a main path navigation bool Bot::DoWaypointNav(void) { // check if we need to find a waypoint... - if (!IsValidWaypoint(m_currentWaypointIndex)) - { - GetValidWaypoint(); - return false; - } - else if (m_waypointOrigin != nullvec) - { - m_cachedWaypointIndex = m_currentWaypointIndex; - m_destOrigin = m_waypointOrigin; - } + GetValidWaypoint(); - // this waypoint has additional travel flags - care about them - if (!m_jumpFinished && m_currentTravelFlags & PATHFLAG_JUMP && !m_isSlowThink) - { - // cheating for jump, bots cannot do some hard jumps and double jumps too - // who cares about double jump for bots? :) - pev->button |= IN_JUMP; + m_destOrigin = m_waypointOrigin; - if (ebot_use_old_jump_method.GetBool()) + auto autoJump = [&](void) { - pev->velocity.x = (m_destOrigin.x - pev->origin.x) * (1.0f + (pev->maxspeed / 500.0f) + pev->gravity); - pev->velocity.y = (m_destOrigin.y - pev->origin.y) * (1.0f + (pev->maxspeed / 500.0f) + pev->gravity); - } - else - { - const Vector myOrigin = GetBottomOrigin(GetEntity()); - Vector waypointOrigin = m_destOrigin; + // cheating for jump, bots cannot do some hard jumps and double jumps too + // who cares about double jump for bots? :) + auto jump = [&](void) + { + if (ebot_use_old_jump_method.GetBool()) + { + pev->velocity.x = (m_destOrigin.x - pev->origin.x) * (1.0f + (pev->maxspeed / 500.0f) + pev->gravity); + pev->velocity.y = (m_destOrigin.y - pev->origin.y) * (1.0f + (pev->maxspeed / 500.0f) + pev->gravity); + } + else + { + const Vector myOrigin = GetBottomOrigin(GetEntity()); + Vector waypointOrigin = m_destOrigin; - if (m_waypointFlags & WAYPOINT_CROUCH) - waypointOrigin.z -= 18.0f; - else - waypointOrigin.z -= 36.0f; + if (m_waypointFlags & WAYPOINT_CROUCH) + waypointOrigin.z -= 18.0f; + else + waypointOrigin.z -= 36.0f; - const float timeToReachWaypoint = csqrtf(SquaredF(waypointOrigin.x - myOrigin.x) + SquaredF(waypointOrigin.y - myOrigin.y)) / pev->maxspeed; - pev->velocity.x = (waypointOrigin.x - myOrigin.x) / timeToReachWaypoint; - pev->velocity.y = (waypointOrigin.y - myOrigin.y) / timeToReachWaypoint; - } + const float timeToReachWaypoint = csqrtf(squaredf(waypointOrigin.x - myOrigin.x) + squaredf(waypointOrigin.y - myOrigin.y)) / pev->maxspeed; + pev->velocity.x = (waypointOrigin.x - myOrigin.x) / timeToReachWaypoint; + pev->velocity.y = (waypointOrigin.y - myOrigin.y) / timeToReachWaypoint; + } + }; - m_jumpFinished = true; - m_checkTerrain = false; - } - else if (m_waypointFlags & WAYPOINT_CROUCH && !(m_waypointFlags & WAYPOINT_CAMP)) - pev->button |= IN_DUCK; + jump(); + pev->button |= (IN_DUCK | IN_JUMP); + jump(); - const float inter = (m_frameInterval + g_pGlobals->frametime) * 0.54f; - float waypointDistance = 0.0f; - float waypointDistance2 = 0.0f; - const Vector origin = pev->origin + pev->velocity * inter; - const Vector wpOrigin = m_destOrigin + pev->velocity * -inter; + m_checkTerrain = false; + PushTask(TASK_PAUSE, TASKPRI_PAUSE, engine->GetTime() + crandomfloat(0.75f, 1.25f), false); + }; - if (m_waypointFlags & WAYPOINT_LADDER || IsOnLadder()) - { - waypointDistance = (origin - wpOrigin).GetLengthSquared(); - waypointDistance2 = (pev->origin - m_destOrigin).GetLengthSquared(); - m_aimStopTime = 0.0f; - if (m_destOrigin.z >= (origin.z + 16.0f)) - m_destOrigin = m_waypoint.origin + Vector(0, 0, 16.0f); - else if (m_destOrigin.z < origin.z + 16.0f && !IsOnLadder() && IsOnFloor()) - { - m_moveSpeed = csqrtf(waypointDistance); - if (m_moveSpeed < 150.0f) - m_moveSpeed = 150.0f; - else if (m_moveSpeed > pev->maxspeed) - m_moveSpeed = pev->maxspeed; - } - } - else if (!(pev->flags & FL_ONGROUND) && m_jumpTime > engine->GetTime()) // jumping - { - waypointDistance = (origin - wpOrigin).GetLengthSquared(); - waypointDistance2 = (pev->origin - m_destOrigin).GetLengthSquared(); - } - else - { - waypointDistance = (origin - wpOrigin).GetLengthSquared2D(); - waypointDistance2 = (pev->origin - m_destOrigin).GetLengthSquared2D(); - } + if (m_waypointFlags & WAYPOINT_CROUCH && !(m_waypointFlags & WAYPOINT_CAMP)) + pev->button |= IN_DUCK; float desiredDistance; // initialize the radius for a special waypoint type, where the wpt is considered to be reached - if (m_currentTravelFlags & PATHFLAG_JUMP) - desiredDistance = SquaredF(4.0f); - else if (m_waypointFlags & WAYPOINT_LIFT) - desiredDistance = SquaredF(48.0f); - else if (m_waypointFlags & WAYPOINT_LADDER) - desiredDistance = SquaredF(32.0f + m_frameInterval + g_pGlobals->frametime); - else if (m_waypoint.radius > 4) - desiredDistance = SquaredI(static_cast(m_waypoint.radius)); + if (m_waypointFlags & WAYPOINT_JUMP || m_currentTravelFlags & PATHFLAG_JUMP) + desiredDistance = 9.0f; + else if (m_waypointFlags & WAYPOINT_LADDER || IsOnLadder()) + desiredDistance = 24.0f; + else if (m_waypoint.radius > 9) + desiredDistance = static_cast(m_waypoint.radius); + else + desiredDistance = 9.0f; + + desiredDistance += m_frameInterval + g_pGlobals->frametime; + float waypointDistance; + + if (pev->flags & FL_DUCKING || m_waypointFlags & WAYPOINT_CROUCH) + waypointDistance = (pev->origin - m_waypointOrigin).GetLengthSquared2D(); + else if (IsOnLadder() || m_waypointFlags & WAYPOINT_LADDER) + waypointDistance = ((pev->origin + pev->velocity * m_frameInterval) - m_waypointOrigin).GetLengthSquared(); + else if (!IsOnFloor() && !IsInWater()) + waypointDistance = ((pev->origin + pev->velocity * -m_frameInterval) - m_waypointOrigin).GetLengthSquared(); + else if (m_waypointFlags & WAYPOINT_FALLRISK || m_waypointFlags & WAYPOINT_JUMP || m_currentTravelFlags & PATHFLAG_JUMP) + waypointDistance = ((pev->origin + pev->velocity * -m_frameInterval) - m_waypointOrigin).GetLengthSquared(); else - desiredDistance = SquaredF(4.0f); + waypointDistance = ((pev->origin + pev->velocity * m_frameInterval) - (m_waypointOrigin + pev->velocity * -m_frameInterval)).GetLengthSquared2D(); - desiredDistance += 54.0f / inter; + if (!IsOnLadder() && !(m_waypointFlags & WAYPOINT_LADDER) && !(m_waypointFlags & WAYPOINT_FALLRISK)) + { + if (!(m_waypointFlags & WAYPOINT_JUMP) && !FNullEnt(m_avoid)) + desiredDistance *= 2.0f; + else if (desiredDistance < 65.0f) + desiredDistance += cmaxf(cabsf(cabsf(pev->speed) - desiredDistance), 27.0f) * m_frameInterval; + } - if (waypointDistance < desiredDistance || waypointDistance2 < desiredDistance) + if (waypointDistance < squaredf(desiredDistance)) { // did we reach a destination waypoint? - if (GetCurrentGoalID() == m_currentWaypointIndex) + if (m_chosenGoalIndex == m_currentWaypointIndex) return true; else if (m_navNode.IsEmpty()) return false; - if ((g_mapType & MAP_DE) && g_bombPlanted && m_team == TEAM_COUNTER && GetCurrentTaskID() != TASK_ESCAPEFROMBOMB && GetCurrentGoalID() != -1) + if ((g_mapType & MAP_DE) && g_bombPlanted && m_team == TEAM_COUNTER && GetCurrentTaskID() != TASK_ESCAPEFROMBOMB && m_chosenGoalIndex != -1) { const Vector bombOrigin = CheckBombAudible(); // bot within 'hearable' bomb tick noises? if (bombOrigin != nullvec) { - if ((bombOrigin - g_waypoint->GetPath(GetCurrentGoalID())->origin).GetLengthSquared() > SquaredF(512.0f)) - g_waypoint->SetGoalVisited(GetCurrentGoalID()); // doesn't hear so not a good goal + if ((bombOrigin - g_waypoint->GetPath(m_chosenGoalIndex)->origin).GetLengthSquared() > squaredf(512.0f)) + g_waypoint->SetGoalVisited(m_chosenGoalIndex); // doesn't hear so not a good goal } else - g_waypoint->SetGoalVisited(GetCurrentGoalID()); // doesn't hear so not a good goal + g_waypoint->SetGoalVisited(m_chosenGoalIndex); // doesn't hear so not a good goal } - HeadTowardWaypoint(); // do the actual movement checking + m_currentTravelFlags = 0; + m_navNode.Shift(); + + if (!m_navNode.IsEmpty()) + { + const int oldIndex = m_currentWaypointIndex; + const int destIndex = m_navNode.First(); + + if (oldIndex == m_chosenGoalIndex || destIndex == m_chosenGoalIndex) + { + m_prevGoalIndex = m_chosenGoalIndex; + m_chosenGoalIndex = -1; + } + + if (oldIndex != destIndex) + { + ChangeWptIndex(destIndex); + SetWaypointOrigin(); + + const Path* pointer = g_waypoint->GetPath(oldIndex); + if (pointer != nullptr) + { + int i; + for (i = 0; i < Const_MaxPathIndex; i++) + { + if (pointer->index[i] == destIndex) + { + m_currentTravelFlags = pointer->connectionFlags[i]; + if (m_currentTravelFlags & PATHFLAG_JUMP) + { + // jump directly to the waypoint, otherwise we will fall... + m_jumpFinished = false; + m_jumping = false; + m_waypointOrigin = g_waypoint->GetPath(destIndex)->origin; + m_waypoint.origin = m_waypointOrigin; + m_destOrigin = m_waypointOrigin; + autoJump(); + } + + break; + } + } + } + + if (IsOnLadder()) + { + TraceResult tr{}; + TraceLine(Vector(pev->origin.x, pev->origin.y, pev->absmin.z), m_waypointOrigin, false, false, pev->pContainingEntity, &tr); + if (tr.flFraction < 1.0f) + { + if (m_waypointOrigin.z >= pev->origin.z) + m_waypointOrigin += tr.vecPlaneNormal; + else + m_waypointOrigin -= tr.vecPlaneNormal; + } + } + } + } + return false; } @@ -508,7 +571,7 @@ class PriorityQueue return m_size; } - inline PriorityQueue(const int initialSize = g_numWaypoints + 32) + inline PriorityQueue(const int initialSize = g_numWaypoints * 2) { m_size = 0; m_heapSize = initialSize; @@ -630,7 +693,7 @@ inline const float GF_CostHuman(const int index, const int parent, const int tea continue; const float distance = (client.origin - path->origin).GetLengthSquared(); - if (distance < SquaredI(path->radius + 64)) + if (distance < squaredi(path->radius + 64)) return 65355.0f; } } @@ -644,7 +707,7 @@ inline const float GF_CostHuman(const int index, const int parent, const int tea continue; const float distance = ((client.ent->v.origin + client.ent->v.velocity * g_pGlobals->frametime) - waypointOrigin).GetLengthSquared(); - if (distance < SquaredI(path->radius + 128)) + if (distance < squaredi(path->radius + 128)) count++; totalDistance += distance; @@ -695,7 +758,7 @@ inline const float GF_CostCareful(const int index, const int parent, const int t continue; const float distance = (client.origin - path->origin).GetLengthSquared(); - if (distance < SquaredI(path->radius + 64)) + if (distance < squaredi(path->radius + 64)) return 65355.0f; } } @@ -713,7 +776,7 @@ inline const float GF_CostCareful(const int index, const int parent, const int t if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team != team) continue; - if ((client.origin - path->origin).GetLengthSquared() < SquaredI(512 + path->radius)) + if ((client.origin - path->origin).GetLengthSquared() < squaredi(512 + path->radius)) count++; else if (IsVisible(path->origin, client.ent)) count++; @@ -766,7 +829,7 @@ inline const float GF_CostNormal(const int index, const int parent, const int te continue; const float distance = (client.origin - path->origin).GetLengthSquared(); - if (distance < SquaredI(path->radius + 64)) + if (distance < squaredi(path->radius + 64)) return 65355.0f; } } @@ -784,7 +847,7 @@ inline const float GF_CostNormal(const int index, const int parent, const int te if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team != team) continue; - if ((client.origin - path->origin).GetLengthSquared() < SquaredI(512 + path->radius)) + if ((client.origin - path->origin).GetLengthSquared() < squaredi(512 + path->radius)) count++; else if (IsVisible(path->origin, client.ent)) count++; @@ -840,7 +903,7 @@ inline const float GF_CostRusher(const int index, const int parent, const int te continue; const float distance = (client.origin - path->origin).GetLengthSquared(); - if (distance < SquaredI(path->radius + 64)) + if (distance < squaredi(path->radius + 64)) return 65355.0f; } } @@ -871,22 +934,14 @@ inline const float GF_CostNoHostage(const int index, const int parent, const int if (path->flags & WAYPOINT_LADDER) return 65355.0f; - if (path->flags & WAYPOINT_AVOID) - return 65355.0f; - - if (path->flags & WAYPOINT_WAITUNTIL) - return 65355.0f; - - if (path->flags & WAYPOINT_JUMP) - return 65355.0f; - - if (path->flags & WAYPOINT_DJUMP) - return 65355.0f; - int i; for (i = 0; i < Const_MaxPathIndex; i++) { - const int neighbour = g_waypoint->GetPath(index)->index[i]; + const Path* pointer = g_waypoint->GetPath(index); + if (pointer == nullptr) + continue; + + const int neighbour = pointer->index[i]; if (IsValidWaypoint(neighbour) && (path->connectionFlags[neighbour] & PATHFLAG_JUMP || path->connectionFlags[neighbour] & PATHFLAG_DOUBLE)) return 65355.0f; } @@ -945,7 +1000,7 @@ inline const float HF_Euclidean(const int start, const int goal) const float y = cabsf(startOrigin.y - goalOrigin.y); const float z = cabsf(startOrigin.z - goalOrigin.z); - const float euclidean = csqrtf(SquaredF(x) + SquaredF(y) + SquaredF(z)); + const float euclidean = csqrtf(squaredf(x) + squaredf(y) + squaredf(z)); return 1000.0f * (cceilf(euclidean) - euclidean); } @@ -957,19 +1012,24 @@ inline const float HF_Euclidean2D(const int start, const int goal) const float x = cabsf(startOrigin.x - goalOrigin.x); const float y = cabsf(startOrigin.y - goalOrigin.y); - const float euclidean = csqrtf(SquaredF(x) + SquaredF(y)); + const float euclidean = csqrtf(squaredf(x) + squaredf(y)); return 1000.0f * (cceilf(euclidean) - euclidean); } // this function finds a path from srcIndex to destIndex -void Bot::FindPath(int srcIndex, int destIndex) +void Bot::FindPath(int srcIndex, const int destIndex, const Vector destOrigin) { if (g_pathTimer > engine->GetTime() && !m_navNode.IsEmpty()) return; - if (g_gameVersion == HALFLIFE) + if (g_gameVersion == HALFLIFE || destOrigin != nullvec) { - FindShortestPath(srcIndex, destIndex); +#ifdef WIN32 + thread core(&Bot::FindPathHL, this, srcIndex, destIndex, destOrigin); +#else + cthread core([this, srcIndex, destIndex, destOrigin]() { this->FindPathHL(srcIndex, destIndex, destOrigin); }); +#endif + core.detach(); return; } @@ -981,7 +1041,7 @@ void Bot::FindPath(int srcIndex, int destIndex) srcIndex = index; else { - const int secondIndex = g_waypoint->FindNearest(pev->origin + pev->velocity * m_frameInterval, 1024.0f, -1, GetEntity()); + const int secondIndex = g_waypoint->FindNearest(pev->origin + pev->velocity * m_frameInterval, 1024.0f, -1, pev->pContainingEntity); if (IsValidWaypoint(secondIndex)) srcIndex = secondIndex; else @@ -990,7 +1050,7 @@ void Bot::FindPath(int srcIndex, int destIndex) } if (!IsValidWaypoint(destIndex)) - destIndex = g_waypoint->m_otherPoints.GetRandomElement(); + return; if (srcIndex == destIndex) { @@ -1101,10 +1161,6 @@ void Bot::FindPath(int srcIndex, int destIndex) // delete path for new one DeleteSearchNodes(); - // set the chosen goal value - m_chosenGoalIndex = destIndex; - m_goalValue = 0.0f; - do { m_navNode.Add(currentIndex); @@ -1113,22 +1169,10 @@ void Bot::FindPath(int srcIndex, int destIndex) m_navNode.Reverse(); - m_currentWaypointIndex = m_navNode.First(); - m_cachedWaypointIndex = m_currentWaypointIndex; + ChangeWptIndex(m_navNode.First()); + SetWaypointOrigin(); - const Path* pointer = g_waypoint->GetPath(m_currentWaypointIndex); - if (pointer != nullptr) - { - if (pointer->radius > 8 && ((pev->origin + pev->velocity * m_frameInterval) - pointer->origin).GetLengthSquared2D() < SquaredI(pointer->radius)) - m_waypointOrigin = pev->origin + pev->velocity * (m_frameInterval + m_frameInterval); - else - m_waypointOrigin = pointer->origin; - } - - m_destOrigin = m_waypointOrigin; - m_jumpFinished = false; g_pathTimer = engine->GetTime() + 0.25f; - return; } @@ -1151,7 +1195,7 @@ void Bot::FindPath(int srcIndex, int destIndex) { TraceResult tr{}; const Vector origin = g_waypoint->GetPath(self)->origin; - TraceLine(origin, origin - Vector(0.0f, 0.0f, 60.0f), false, false, GetEntity(), &tr); + TraceLine(origin, origin - Vector(0.0f, 0.0f, 60.0f), false, false, pev->pContainingEntity, &tr); if (tr.flFraction == 1.0f) continue; } @@ -1186,14 +1230,14 @@ void Bot::FindPath(int srcIndex, int destIndex) if (!PossiblePath.IsEmpty()) { - FindShortestPath(srcIndex, PossiblePath.GetRandomElement()); + FindShortestPath(srcIndex, PossiblePath.GetRandomElement(), nullvec); return; } FindShortestPath(srcIndex, destIndex); } -void Bot::FindShortestPath(int srcIndex, int destIndex) +void Bot::FindShortestPath(int srcIndex, const int destIndex, const Vector destOrigin) { // if we're stuck, find nearest waypoint if (!IsValidWaypoint(srcIndex)) @@ -1203,7 +1247,7 @@ void Bot::FindShortestPath(int srcIndex, int destIndex) srcIndex = index; else { - const int secondIndex = g_waypoint->FindNearest(pev->origin + pev->velocity * m_frameInterval, 1024.0f, -1, GetEntity()); + const int secondIndex = g_waypoint->FindNearest(pev->origin + pev->velocity * m_frameInterval, 1024.0f, -1, pev->pContainingEntity); if (IsValidWaypoint(secondIndex)) srcIndex = secondIndex; else @@ -1250,10 +1294,6 @@ void Bot::FindShortestPath(int srcIndex, int destIndex) // delete path for new one DeleteSearchNodes(); - // set chosen goal - m_chosenGoalIndex = destIndex; - m_goalValue = 0.0f; - do { m_navNode.Add(currentIndex); @@ -1262,22 +1302,10 @@ void Bot::FindShortestPath(int srcIndex, int destIndex) m_navNode.Reverse(); - m_currentWaypointIndex = m_navNode.First(); - m_cachedWaypointIndex = m_currentWaypointIndex; + ChangeWptIndex(m_navNode.First()); + SetWaypointOrigin(); - const Path* pointer = g_waypoint->GetPath(m_currentWaypointIndex); - if (pointer != nullptr) - { - if (pointer->radius > 8 && ((pev->origin + pev->velocity * m_frameInterval) - pointer->origin).GetLengthSquared2D() < SquaredI(pointer->radius)) - m_waypointOrigin = pev->origin + pev->velocity * (m_frameInterval + m_frameInterval); - else - m_waypointOrigin = pointer->origin; - } - - m_destOrigin = m_waypointOrigin; - m_jumpFinished = false; g_pathTimer = engine->GetTime() + 0.25f; - return; } @@ -1300,7 +1328,7 @@ void Bot::FindShortestPath(int srcIndex, int destIndex) { TraceResult tr{}; const Vector origin = g_waypoint->GetPath(self)->origin; - TraceLine(origin, origin - Vector(0.0f, 0.0f, 60.0f), false, false, GetEntity(), &tr); + TraceLine(origin, origin - Vector(0.0f, 0.0f, 60.0f), false, false, pev->pContainingEntity, &tr); if (tr.flFraction == 1.0f) continue; } @@ -1324,6 +1352,178 @@ void Bot::FindShortestPath(int srcIndex, int destIndex) } } } + + m_chosenGoalIndex = -1; +} + +void Bot::FindPathHL(int srcIndex, int destIndex, const Vector destOrigin) +{ + // if we're stuck, find nearest waypoint + if (!IsValidWaypoint(srcIndex)) + { + if (!IsValidWaypoint(m_currentWaypointIndex)) + return; + + srcIndex = m_currentWaypointIndex; + } + + if (destOrigin != nullvec) + { + const int index = g_waypoint->FindNearestInCircleSingle(destOrigin); + if (IsValidWaypoint(index)) + destIndex = index; + } + + if (!IsValidWaypoint(destIndex)) + return; + + if (srcIndex == destIndex) + { + DeleteSearchNodes(); + m_navNode.Add(destIndex); + return; + } + + const float (*hcalc) (const int, const int) = nullptr; + + if (m_2dH) + { + switch (m_heuristic) + { + case 1: + hcalc = HF_Distance2D; + break; + case 2: + hcalc = HF_Manhattan2D; + break; + case 3: + hcalc = HF_Chebyshev2D; + break; + case 4: + hcalc = HF_Euclidean2D; + break; + default: + hcalc = HF_Distance2D; + break; + } + } + else + { + switch (m_heuristic) + { + case 1: + hcalc = HF_Distance; + break; + case 2: + hcalc = HF_Manhattan; + break; + case 3: + hcalc = HF_Chebyshev; + break; + case 4: + hcalc = HF_Euclidean; + break; + default: + hcalc = HF_Distance; + break; + } + } + + if (hcalc == nullptr) + return; + + int i; + AStar_t waypoints[Const_MaxWaypoints]; + for (i = 0; i < g_numWaypoints; i++) + { + waypoints[i].g = 0.0f; + waypoints[i].f = 0.0f; + waypoints[i].parent = -1; + waypoints[i].state = State::New; + } + + // put start node into open list + const auto srcWaypoint = &waypoints[srcIndex]; + srcWaypoint->g = hcalc(srcIndex, destIndex); + srcWaypoint->f = hcalc(srcIndex, destIndex); + srcWaypoint->state = State::Open; + + PriorityQueue openList; + openList.Insert(srcIndex, srcWaypoint->f); + while (!openList.IsEmpty()) + { + // remove the first node from the open list + int currentIndex = openList.Remove(); + + // is the current node the goal node? + if (currentIndex == destIndex) + { + // delete path for new one + DeleteSearchNodes(); + + do + { + m_navNode.Add(currentIndex); + currentIndex = waypoints[currentIndex].parent; + } while (IsValidWaypoint(currentIndex)); + + m_navNode.Reverse(); + + ChangeWptIndex(m_navNode.First()); + SetWaypointOrigin(); + + g_pathTimer = engine->GetTime() + 0.25f; + return; + } + + const auto currWaypoint = &waypoints[currentIndex]; + if (currWaypoint->state != State::Open) + continue; + + // put current node into Closed list + currWaypoint->state = State::Closed; + + // now expand the current node + for (i = 0; i < Const_MaxPathIndex; i++) + { + const int self = g_waypoint->GetPath(currentIndex)->index[i]; + if (!IsValidWaypoint(self)) + continue; + + const float g = currWaypoint->g + hcalc(currentIndex, self); + const float f = g + hcalc(self, destIndex); + const auto childWaypoint = &waypoints[self]; + if (childWaypoint->state == State::New || childWaypoint->f > f) + { + // put the current child into open list + childWaypoint->parent = currentIndex; + childWaypoint->state = State::Open; + childWaypoint->g = g; + childWaypoint->f = f; + openList.Insert(self, f); + } + } + } + + // roam around poorly :( + Array PossiblePath; + for (i = 0; i < g_numWaypoints; i++) + { + if (waypoints[i].state == State::Closed) + PossiblePath.Push(i); + } + + if (!PossiblePath.IsEmpty()) + { +#ifdef WIN32 + thread core(&Bot::FindPathHL, this, srcIndex, PossiblePath.GetRandomElement(), nullvec); +#else + const int index = PossiblePath.GetRandomElement(); + cthread core([this, srcIndex, index]() { this->FindPathHL(srcIndex, index, Vector::GetNull()); }); +#endif + core.detach(); + return; + } } void Bot::DeleteSearchNodes(void) @@ -1354,7 +1554,7 @@ void Bot::CheckTouchEntity(edict_t* entity) m_moveSpeed = 0.0f; m_strafeSpeed = 0.0f; - PushTask(TASK_DEFUSEBOMB, TASKPRI_DEFUSEBOMB, -1, 0.0, false); + PushTask(TASK_DEFUSEBOMB, TASKPRI_DEFUSEBOMB, 0.0f, false); } } @@ -1364,10 +1564,7 @@ void Bot::CheckTouchEntity(edict_t* entity) // see if it's breakable if ((FClassnameIs(entity, "func_breakable") || (FClassnameIs(entity, "func_pushable") && (entity->v.spawnflags & SF_PUSH_BREAKABLE)) || FClassnameIs(entity, "func_wall")) && entity->v.health > 0.0f && entity->v.health < ebot_breakable_health_limit.GetFloat()) { - edict_t* me = GetEntity(); - if (me == nullptr) - return; - + edict_t* me = pev->pContainingEntity; TraceResult tr{}; TraceHull(EyePosition(), m_destOrigin, false, point_hull, me, &tr); @@ -1386,7 +1583,7 @@ void Bot::CheckTouchEntity(edict_t* entity) else m_campButtons = pev->button & IN_DUCK; - PushTask(TASK_DESTROYBREAKABLE, TASKPRI_SHOOTBREAKABLE, -1, 1.0f, false); + PushTask(TASK_DESTROYBREAKABLE, TASKPRI_SHOOTBREAKABLE, 1.0f, false); if (pev->origin.z > m_breakable.z) // make bots smarter { @@ -1408,7 +1605,7 @@ void Bot::CheckTouchEntity(edict_t* entity) if (enemy->m_currentWeapon == WEAPON_KNIFE) continue; - edict_t* ent = enemy->GetEntity(); + edict_t* ent = enemy->pev->pContainingEntity; if (ent == nullptr) continue; @@ -1425,7 +1622,7 @@ void Bot::CheckTouchEntity(edict_t* entity) else enemy->m_campButtons = enemy->pev->button & IN_DUCK; - enemy->PushTask(TASK_DESTROYBREAKABLE, TASKPRI_SHOOTBREAKABLE, -1, 1.0f, false); + enemy->PushTask(TASK_DESTROYBREAKABLE, TASKPRI_SHOOTBREAKABLE, 1.0f, false); } } } @@ -1445,7 +1642,7 @@ void Bot::CheckTouchEntity(edict_t* entity) if (bot->m_isZombieBot) continue; - edict_t* ent = bot->GetEntity(); + edict_t* ent = bot->pev->pContainingEntity; if (ent == nullptr) continue; @@ -1468,7 +1665,7 @@ void Bot::CheckTouchEntity(edict_t* entity) else bot->m_campButtons = bot->pev->button & IN_DUCK; - bot->PushTask(TASK_DESTROYBREAKABLE, TASKPRI_SHOOTBREAKABLE, -1, 1.0f, false); + bot->PushTask(TASK_DESTROYBREAKABLE, TASKPRI_SHOOTBREAKABLE, 1.0f, false); } } } @@ -1521,11 +1718,7 @@ void Bot::SetMoveTarget(edict_t* entity) m_moveTargetOrigin = nullvec; if (GetCurrentTaskID() == TASK_MOVETOTARGET) - { RemoveCertainTask(TASK_MOVETOTARGET); - m_prevGoalIndex = -1; - GetCurrentTask()->data = -1; - } return; } @@ -1541,98 +1734,119 @@ void Bot::SetMoveTarget(edict_t* entity) return; SetEntityWaypoint(entity); - SetEntityWaypoint(GetEntity(), GetEntityWaypoint(entity)); + SetEntityWaypoint(pev->pContainingEntity, GetEntityWaypoint(entity)); m_moveTargetEntity = entity; - PushTask(TASK_MOVETOTARGET, TASKPRI_MOVETOTARGET, -1, 0.0, true); + PushTask(TASK_MOVETOTARGET, TASKPRI_MOVETOTARGET, 0.0f, true); } -// this function find a node in the near of the bot if bot had lost his path of pathfinder needs -// to be restarted over again -int Bot::FindWaypoint(bool skipLag) +// this function find a node in the near of the bot if bot had lost his path of pathfinder waypoints to be restarted over again +int Bot::FindWaypoint(const bool skipLag) { if (skipLag && !m_isSlowThink && IsValidWaypoint(m_cachedWaypointIndex)) return m_cachedWaypointIndex; - edict_t* me = GetEntity(); + if (!IsValidWaypoint(m_currentWaypointIndex) || !g_waypoint->Reachable(pev->pContainingEntity, m_currentWaypointIndex)) + { + if (!IsValidWaypoint(m_cachedWaypointIndex) || !g_waypoint->Reachable(pev->pContainingEntity, m_cachedWaypointIndex)) + { + // too many... we need speed! + if (g_numWaypoints > 2048) + m_currentWaypointIndex = g_waypoint->FindNearestInCircle(pev->origin); + else + { + const int index = g_waypoint->FindNearest(pev->origin, 999999.0f, -1, pev->pContainingEntity); + if (IsValidWaypoint(index)) + m_currentWaypointIndex = index; + else + m_currentWaypointIndex = g_waypoint->FindNearestInCircle(pev->origin); + } + } + else + m_currentWaypointIndex = m_cachedWaypointIndex; + } + int busy = -1; float lessDist[3] = {FLT_MAX, FLT_MAX, FLT_MAX}; int lessIndex[3] = {-1, -1, -1}; - int at; - for (at = 0; at < g_numWaypoints; at++) + Array waypoints; + if (g_waypoint->CollectWaypoints(m_currentWaypointIndex, waypoints)) { - if (!IsValidWaypoint(at)) - continue; - - const Path* pointer = g_waypoint->GetPath(at); - if (pointer == nullptr) - continue; - - if (m_team == TEAM_COUNTER && pointer->flags & WAYPOINT_ZOMBIEONLY) - continue; - else if (m_team == TEAM_TERRORIST && pointer->flags & WAYPOINT_HUMANONLY) - continue; + if (!waypoints.IsEmpty()) + { + int i; + for (i = 0; i < waypoints.GetElementNumber(); i++) + { + int at; + if (!waypoints.GetAt(i, at)) + continue; - bool skip = !!(int(pointer->index) == m_currentWaypointIndex); + const Path* pointer = g_waypoint->GetPath(at); + if (pointer == nullptr) + continue; - // skip current and recent previous nodes - if (at == m_prevWptIndex) - skip = true; + if (m_team == TEAM_COUNTER && pointer->flags & WAYPOINT_ZOMBIEONLY) + continue; + else if (m_team == TEAM_TERRORIST && pointer->flags & WAYPOINT_HUMANONLY) + continue; - // skip the current node, if any - if (skip) - continue; + bool skip = !!(int(pointer->index) == m_currentWaypointIndex); - // skip if isn't visible - if (!IsVisible(pointer->origin, me)) - continue; + // skip current and recent previous nodes + if (at == m_prevWptIndex) + skip = true; - // cts with hostages should not pick - if (m_team == TEAM_COUNTER && HasHostage()) - continue; + // skip the current node, if any + if (skip) + continue; - // check we're have link to it - if (IsValidWaypoint(m_currentWaypointIndex) && !g_waypoint->IsConnected(m_currentWaypointIndex, at)) - continue; + // skip if isn't visible + if (!IsVisible(pointer->origin, pev->pContainingEntity)) + continue; - // ignore non-reacheable nodes... - if (!g_waypoint->IsNodeReachable(m_waypoint.origin, pointer->origin)) - continue; + // cts with hostages should not pick + if (m_team == TEAM_COUNTER && HasHostage()) + continue; - // check if node is already used by another bot... - if (IsWaypointOccupied(at)) - { - busy = at; - continue; - } + // check we're have link to it or ignore non-reacheable nodes... + if (!g_waypoint->IsConnected(m_currentWaypointIndex, at) && !g_waypoint->IsNodeReachable(pev->origin, pointer->origin)) + continue; - // if we're still here, find some close nodes - const float distance = (pev->origin - pointer->origin).GetLengthSquared(); + // check if node is already used by another bot... + if (IsWaypointOccupied(at)) + { + busy = at; + continue; + } - if (distance < lessDist[0]) - { - lessDist[2] = lessDist[1]; - lessIndex[2] = lessIndex[1]; + // if we're still here, find some close nodes + const float distance = (pev->origin - pointer->origin).GetLengthSquared(); + if (distance < lessDist[0]) + { + lessDist[2] = lessDist[1]; + lessIndex[2] = lessIndex[1]; - lessDist[1] = lessDist[0]; - lessIndex[1] = lessIndex[0]; + lessDist[1] = lessDist[0]; + lessIndex[1] = lessIndex[0]; - lessDist[0] = distance; - lessIndex[0] = at; - } - else if (distance < lessDist[1]) - { - lessDist[2] = lessDist[1]; - lessIndex[2] = lessIndex[1]; + lessDist[0] = distance; + lessIndex[0] = at; + } + else if (distance < lessDist[1]) + { + lessDist[2] = lessDist[1]; + lessIndex[2] = lessIndex[1]; - lessDist[1] = distance; - lessIndex[1] = at; - } - else if (distance < lessDist[2]) - { - lessDist[2] = distance; - lessIndex[2] = at; + lessDist[1] = distance; + lessIndex[1] = at; + } + else if (distance < lessDist[2]) + { + lessDist[2] = distance; + lessIndex[2] = at; + } + } } } @@ -1643,9 +1857,9 @@ int Bot::FindWaypoint(bool skipLag) // choice from found if (IsValidWaypoint(lessIndex[2])) - index = CRandomInt(0, 2); + index = crandomint(0, 2); else if (IsValidWaypoint(lessIndex[1])) - index = CRandomInt(0, 1); + index = crandomint(0, 1); else if (IsValidWaypoint(lessIndex[0])) index = 0; @@ -1655,9 +1869,9 @@ int Bot::FindWaypoint(bool skipLag) if (!IsValidWaypoint(selected) && IsValidWaypoint(busy)) selected = busy; - // worst case... find atleast something + // worst case... if (!IsValidWaypoint(selected)) - selected = g_waypoint->FindNearest(pev->origin + pev->velocity, 9999.0f, -1, me); + selected = g_waypoint->FindNearestInCircle(pev->origin); ChangeWptIndex(selected); SetWaypointOrigin(); @@ -1678,7 +1892,7 @@ void Bot::SetWaypointOrigin(void) const uint8_t radius = m_waypoint.radius; if (radius > 0) { - MakeVectors(Vector(pev->angles.x, AngleNormalize(pev->angles.y + CRandomFloat(-90.0f, 90.0f)), 0.0f)); + MakeVectors(Vector(pev->angles.x, AngleNormalize(pev->angles.y + crandomfloat(-90.0f, 90.0f)), 0.0f)); int sPoint = -1; if (m_navNode.HasNext()) @@ -1690,7 +1904,7 @@ void Bot::SetWaypointOrigin(void) for (i = 0; i < 5; i++) { waypointOrigin[i] = m_waypointOrigin; - waypointOrigin[i] += Vector(CRandomFloat(-frad, frad), CRandomFloat(-frad, frad), 0.0f); + waypointOrigin[i] += Vector(crandomfloat(-frad, frad), crandomfloat(-frad, frad), 0.0f); } float sDistance = FLT_MAX; @@ -1708,43 +1922,36 @@ void Bot::SetWaypointOrigin(void) m_waypointOrigin = waypointOrigin[sPoint]; } } - - if (IsOnLadder()) - { - m_aimStopTime = 0.0f; - TraceResult tr{}; - TraceLine(Vector(pev->origin.x, pev->origin.y, pev->absmin.z), m_waypointOrigin, true, true, GetEntity(), &tr); - - if (tr.flFraction < 1.0f) - m_waypointOrigin = (pev->origin - m_waypointOrigin) * 0.5f + Vector(0.0f, 0.0f, 32.0f); - } } // checks if the last waypoint the bot was heading for is still valid -void Bot::GetValidWaypoint(void) +bool Bot::GetValidWaypoint(void) { bool needFindWaypont = false; if (!IsValidWaypoint(m_currentWaypointIndex)) needFindWaypont = true; - else if ((m_navTimeset + GetEstimatedReachTime() < engine->GetTime())) + else if (m_navTimeset + GetEstimatedReachTime() < engine->GetTime()) needFindWaypont = true; else { - int waypointIndex1, waypointIndex2; - const int client = ENTINDEX(GetEntity()) - 1; - waypointIndex1 = g_clients[client].wpIndex; - waypointIndex2 = g_clients[client].wpIndex2; + const int client = m_index - 1; + const int waypointIndex1 = g_clients[client].wpIndex; + const int waypointIndex2 = g_clients[client].wpIndex2; - if (m_currentWaypointIndex != waypointIndex1 && m_currentWaypointIndex != waypointIndex2 && (m_waypoint.origin - pev->origin).GetLengthSquared() > SquaredF(600.0f) && !g_waypoint->Reachable(GetEntity(), m_currentWaypointIndex)) + if (m_currentWaypointIndex != waypointIndex1 && m_currentWaypointIndex != waypointIndex2 && (m_waypoint.origin - pev->origin).GetLengthSquared() > squaredf(384.0f) && !g_waypoint->Reachable(pev->pContainingEntity, m_currentWaypointIndex) && !g_waypoint->IsNodeReachableWithJump(pev->origin, m_destOrigin, -1)) needFindWaypont = true; } if (needFindWaypont) { DeleteSearchNodes(); - FindWaypoint(); - SetWaypointOrigin(); + m_currentWaypointIndex = -1; + m_cachedWaypointIndex = -1; + FindWaypoint(false); + return true; } + + return false; } // get the current waypoint and flags @@ -1752,7 +1959,7 @@ void Bot::GetWaypoint(void) { if (IsValidWaypoint(m_currentWaypointIndex)) { - Path* pointer = g_waypoint->GetPath(m_currentWaypointIndex); + const Path* pointer = g_waypoint->GetPath(m_currentWaypointIndex); if (pointer != nullptr) { m_waypoint.origin = pointer->origin; @@ -1788,14 +1995,13 @@ void Bot::ChangeWptIndex(const int waypointIndex) } bool badPrevWpt = true; - int i; - for (i = 0; i < Const_MaxPathIndex; i++) + for (const auto link : m_waypoint.index) { - if (m_waypoint.index[i] == waypointIndex) + if (link == waypointIndex) badPrevWpt = false; } - if (badPrevWpt == true) + if (badPrevWpt) m_prevWptIndex = -1; else m_prevWptIndex = m_currentWaypointIndex; @@ -1809,7 +2015,7 @@ void Bot::ChangeWptIndex(const int waypointIndex) int Bot::ChooseBombWaypoint(void) { if (g_waypoint->m_goalPoints.IsEmpty()) - return CRandomInt(0, g_numWaypoints - 1); // reliability check + return crandomint(0, g_numWaypoints - 1); // reliability check Vector bombOrigin = CheckBombAudible(); @@ -1859,13 +2065,12 @@ int Bot::FindDefendWaypoint(Vector origin) // no camp waypoints if (g_waypoint->m_campPoints.IsEmpty()) - return CRandomInt(0, g_numWaypoints - 1); + return crandomint(0, g_numWaypoints - 1); // invalid index if (!IsValidWaypoint(m_currentWaypointIndex)) return g_waypoint->m_campPoints.GetRandomElement(); - edict_t* me = GetEntity(); Array BestSpots; Array OkSpots; Array WorstSpots; @@ -1877,9 +2082,6 @@ int Bot::FindDefendWaypoint(Vector origin) if (!g_waypoint->m_campPoints.GetAt(i, index)) continue; - if (!IsValidWaypoint(index)) - continue; - const Path* pointer = g_waypoint->GetPath(index); if (pointer == nullptr) continue; @@ -1898,11 +2100,11 @@ int Bot::FindDefendWaypoint(Vector origin) if (!IsWaypointOccupied(index)) { TraceResult tr{}; - TraceLine(pointer->origin, origin, true, true, me, &tr); + TraceLine(pointer->origin, origin, true, true, pev->pContainingEntity, &tr); if (tr.flFraction == 1.0f) // distance isn't matter BestSpots.Push(index); - else if ((pointer->origin - origin).GetLengthSquared() < SquaredF(1024.0f)) + else if ((pointer->origin - origin).GetLengthSquared() < squaredf(1024.0f)) OkSpots.Push(index); else WorstSpots.Push(index); @@ -1927,16 +2129,14 @@ int Bot::FindDefendWaypoint(Vector origin) int Bot::FindCoverWaypoint(float maxDistance) { // really? - if (maxDistance < SquaredF(512.0f)) - maxDistance = SquaredF(512.0f); + if (maxDistance < squaredf(512.0f)) + maxDistance = squaredf(512.0f); // do not move to a position near to the enemy const float enemydist = (m_lastEnemyOrigin - pev->origin).GetLengthSquared2D(); if (maxDistance > enemydist) maxDistance = enemydist; - edict_t* me = GetEntity(); - Array BestSpots; Array OkSpots; @@ -1962,11 +2162,11 @@ int Bot::FindCoverWaypoint(float maxDistance) { TraceResult tr{}; const Vector origin = !FNullEnt(m_enemy) ? GetPlayerHeadOrigin(m_enemy) : m_lastEnemyOrigin; - TraceLine(pointer->origin, origin, true, true, me, &tr); + TraceLine(pointer->origin, origin, true, true, pev->pContainingEntity, &tr); if (tr.flFraction != 1.0f && (pointer->origin - origin).GetLengthSquared() > (pointer->origin - pev->origin).GetLengthSquared()) { - if ((pointer->origin - pev->origin).GetLengthSquared() < SquaredF(maxDistance)) + if ((pointer->origin - pev->origin).GetLengthSquared() < squaredf(maxDistance)) BestSpots.Push(i); else OkSpots.Push(i); @@ -1977,12 +2177,11 @@ int Bot::FindCoverWaypoint(float maxDistance) if (!BestSpots.IsEmpty() && !IsValidWaypoint(ChoosenIndex)) { float maxdist = maxDistance; - int i; for (i = 0; i < BestSpots.GetElementNumber(); i++) { - const int index = BestSpots.GetAt(i); - if (!IsValidWaypoint(index)) + int index; + if (!BestSpots.GetAt(i, index)) continue; const Path* pointer = g_waypoint->GetPath(i); @@ -2027,60 +2226,8 @@ int Bot::FindCoverWaypoint(float maxDistance) return -1; // do not use random points } -// advances in our pathfinding list and sets the appropiate destination origins for this bot -bool Bot::HeadTowardWaypoint(void) -{ - // no waypoints from pathfinding? - if (m_navNode.IsEmpty()) - return false; - - m_navNode.Shift(); // advance in list - m_currentTravelFlags = 0; // reset travel flags (jumping etc) - - // we're not at the end of the list? - if (!m_navNode.IsEmpty()) - { - const int destIndex = m_navNode.First(); - - // find out about connection flags - if (IsValidWaypoint(m_currentWaypointIndex)) - { - int i; - for (i = 0; i < Const_MaxPathIndex; i++) - { - if (m_waypoint.index[i] == destIndex) - { - m_currentTravelFlags = m_waypoint.connectionFlags[i]; - m_jumpFinished = false; - break; - } - } - } - - ChangeWptIndex(destIndex); - SetWaypointOrigin(); - - if (IsOnLadder()) - { - TraceResult tr{}; - TraceLine(Vector(pev->origin.x, pev->origin.y, pev->absmin.z), m_waypointOrigin, false, false, GetEntity(), &tr); - if (tr.flFraction < 1.0f) - { - if (m_waypointOrigin.z >= pev->origin.z) - m_waypointOrigin += tr.vecPlaneNormal; - else - m_waypointOrigin -= tr.vecPlaneNormal; - } - } - } - - m_navTimeset = engine->GetTime(); - - return true; -} - // checks if bot is blocked in his movement direction (excluding doors) -bool Bot::CantMoveForward(Vector normal, TraceResult* tr) +bool Bot::CantMoveForward(const Vector normal, TraceResult* tr) { // first do a trace from the bot's eyes forward... Vector src = EyePosition(); @@ -2089,7 +2236,7 @@ bool Bot::CantMoveForward(Vector normal, TraceResult* tr) MakeVectors(Vector(0.0f, pev->angles.y, 0.0f)); // trace from the bot's eyes straight forward... - TraceLine(src, forward, true, GetEntity(), tr); + TraceLine(src, forward, true, pev->pContainingEntity, tr); // check if the trace hit something... if (tr->flFraction < 1.0f) @@ -2105,7 +2252,7 @@ bool Bot::CantMoveForward(Vector normal, TraceResult* tr) src = EyePosition() + Vector(0.0f, 0.0f, -16.0f) - g_pGlobals->v_right * 16.0f; forward = EyePosition() + Vector(0.0f, 0.0f, -16.0f) + g_pGlobals->v_right * 16.0f + normal * 24.0f; - TraceLine(src, forward, true, GetEntity(), tr); + TraceLine(src, forward, true, pev->pContainingEntity, tr); // check if the trace hit something... if (tr->flFraction < 1.0f && cstrncmp("func_door", STRING(tr->pHit->v.classname), 9) != 0) @@ -2116,7 +2263,7 @@ bool Bot::CantMoveForward(Vector normal, TraceResult* tr) src = EyePosition() + Vector(0.0f, 0.0f, -16.0f) + g_pGlobals->v_right * 16.0f; forward = EyePosition() + Vector(0.0f, 0.0f, -16.0f) - g_pGlobals->v_right * 16.0f + normal * 24.0f; - TraceLine(src, forward, true, GetEntity(), tr); + TraceLine(src, forward, true, pev->pContainingEntity, tr); // check if the trace hit something... if (tr->flFraction < 1.0f && cstrncmp("func_door", STRING(tr->pHit->v.classname), 9) != 0) @@ -2128,7 +2275,7 @@ bool Bot::CantMoveForward(Vector normal, TraceResult* tr) src = pev->origin + Vector(0.0f, 0.0f, -19.0f + 19.0f); forward = src + Vector(0.0f, 0.0f, 10.0f) + normal * 24.0f; - TraceLine(src, forward, true, GetEntity(), tr); + TraceLine(src, forward, true, pev->pContainingEntity, tr); // check if the trace hit something... if (tr->flFraction < 1.0f && cstrncmp("func_door", STRING(tr->pHit->v.classname), 9) != 0) @@ -2137,7 +2284,7 @@ bool Bot::CantMoveForward(Vector normal, TraceResult* tr) src = pev->origin; forward = src + normal * 24.0f; - TraceLine(src, forward, true, GetEntity(), tr); + TraceLine(src, forward, true, pev->pContainingEntity, tr); // check if the trace hit something... if (tr->flFraction < 1.0f && cstrncmp("func_door", STRING(tr->pHit->v.classname), 9) != 0) @@ -2150,7 +2297,7 @@ bool Bot::CantMoveForward(Vector normal, TraceResult* tr) forward = pev->origin + Vector(0.0f, 0.0f, -17.0f) + g_pGlobals->v_right * 16.0f + normal * 24.0f; // trace from the bot's waist straight forward... - TraceLine(src, forward, true, GetEntity(), tr); + TraceLine(src, forward, true, pev->pContainingEntity, tr); // check if the trace hit something... if (tr->flFraction < 1.0f && cstrncmp("func_door", STRING(tr->pHit->v.classname), 9) != 0) @@ -2160,7 +2307,7 @@ bool Bot::CantMoveForward(Vector normal, TraceResult* tr) src = pev->origin + Vector(0.0f, 0.0f, -17.0f) + g_pGlobals->v_right * 16.0f; forward = pev->origin + Vector(0.0f, 0.0f, -17.0f) - g_pGlobals->v_right * 16.0f + normal * 24.0f; - TraceLine(src, forward, true, GetEntity(), tr); + TraceLine(src, forward, true, pev->pContainingEntity, tr); // check if the trace hit something... if (tr->flFraction < 1.0f && cstrncmp("func_door", STRING(tr->pHit->v.classname), 9) != 0) @@ -2170,16 +2317,14 @@ bool Bot::CantMoveForward(Vector normal, TraceResult* tr) return false; // bot can move forward, return false } -bool Bot::CanJumpUp(Vector normal) +// this function check if bot can jump over some obstacle +bool Bot::CanJumpUp(const Vector normal) { - // this function check if bot can jump over some obstacle - - TraceResult tr{}; - // can't jump if not on ground and not on ladder/swimming if (!IsOnFloor() && (IsOnLadder() || !IsInWater())) return false; + TraceResult tr{}; MakeVectors(Vector(0.0f, pev->angles.y, 0.0f)); // check for normal jump height first... @@ -2187,7 +2332,7 @@ bool Bot::CanJumpUp(Vector normal) Vector dest = src + normal * 32.0f; // trace a line forward at maximum jump height... - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); if (tr.flFraction < 1.0f) goto CheckDuckJump; @@ -2197,7 +2342,7 @@ bool Bot::CanJumpUp(Vector normal) src = dest; dest.z = dest.z + 37.0f; - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); if (tr.flFraction < 1.0f) return false; @@ -2208,7 +2353,7 @@ bool Bot::CanJumpUp(Vector normal) dest = src + normal * 32.0f; // trace a line forward at maximum jump height... - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); // if trace hit something, return false if (tr.flFraction < 1.0f) @@ -2218,7 +2363,7 @@ bool Bot::CanJumpUp(Vector normal) src = dest; dest.z = dest.z + 37.0f; - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); // if trace hit something, return false if (tr.flFraction < 1.0f) @@ -2229,7 +2374,7 @@ bool Bot::CanJumpUp(Vector normal) dest = src + normal * 32.0f; // trace a line forward at maximum jump height... - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); // if trace hit something, return false if (tr.flFraction < 1.0f) @@ -2239,7 +2384,7 @@ bool Bot::CanJumpUp(Vector normal) src = dest; dest.z = dest.z + 37.0f; - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); // if trace hit something, return false return tr.flFraction > 1.0f; @@ -2251,7 +2396,7 @@ bool Bot::CanJumpUp(Vector normal) dest = src + normal * 32.0f; // trace a line forward at maximum jump height... - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); if (tr.flFraction < 1.0f) return false; @@ -2261,7 +2406,7 @@ bool Bot::CanJumpUp(Vector normal) src = dest; dest.z = dest.z + 37.0f; - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); // if trace hit something, check duckjump if (tr.flFraction < 1.0f) @@ -2273,7 +2418,7 @@ bool Bot::CanJumpUp(Vector normal) dest = src + normal * 32.0f; // trace a line forward at maximum jump height... - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); // if trace hit something, return false if (tr.flFraction < 1.0f) @@ -2283,7 +2428,7 @@ bool Bot::CanJumpUp(Vector normal) src = dest; dest.z = dest.z + 37.0f; - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); // if trace hit something, return false if (tr.flFraction < 1.0f) @@ -2294,7 +2439,7 @@ bool Bot::CanJumpUp(Vector normal) dest = src + normal * 32.0f; // trace a line forward at maximum jump height... - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); // if trace hit something, return false if (tr.flFraction < 1.0f) @@ -2304,7 +2449,53 @@ bool Bot::CanJumpUp(Vector normal) src = dest; dest.z = dest.z + 37.0f; - TraceLine(src, dest, true, GetEntity(), &tr); + TraceLine(src, dest, true, pev->pContainingEntity, &tr); + + // if trace hit something, return false + return tr.flFraction > 1.0f; +} + +// this function check if bot can duck under obstacle +bool Bot::CanDuckUnder(const Vector normal) +{ + TraceResult tr{}; + Vector baseHeight; + + // use center of the body first... + if (pev->flags & FL_DUCKING) + baseHeight = pev->origin + Vector(0.0f, 0.0f, -17.0f); + else + baseHeight = pev->origin; + + Vector src = baseHeight; + Vector dest = src + normal * 32.0f; + + // trace a line forward at duck height... + TraceLine(src, dest, true, pev->pContainingEntity, &tr); + + // if trace hit something, return false + if (tr.flFraction < 1.0f) + return false; + + MakeVectors(Vector(0.0f, pev->angles.y, 0.0f)); + + // now check same height to one side of the bot... + src = baseHeight + g_pGlobals->v_right * 16.0f; + dest = src + normal * 32.0f; + + // trace a line forward at duck height... + TraceLine(src, dest, true, pev->pContainingEntity, &tr); + + // if trace hit something, return false + if (tr.flFraction < 1.0f) + return false; + + // now check same height on the other side of the bot... + src = baseHeight + (-g_pGlobals->v_right * 16.0f); + dest = src + normal * 32.0f; + + // trace a line forward at duck height... + TraceLine(src, dest, true, pev->pContainingEntity, &tr); // if trace hit something, return false return tr.flFraction > 1.0f; @@ -2316,7 +2507,7 @@ bool Bot::CheckWallOnBehind(void) MakeVectors(pev->angles); // do a trace to the left... - TraceLine(pev->origin, pev->origin - g_pGlobals->v_forward * 54.0f, false, false, GetEntity(), &tr); + TraceLine(pev->origin, pev->origin - g_pGlobals->v_forward * 54.0f, false, false, pev->pContainingEntity, &tr); // check if the trace hit something... if (tr.flFraction != 1.0f) @@ -2326,11 +2517,10 @@ bool Bot::CheckWallOnBehind(void) } else { - TraceResult tr2; - TraceLine(tr.vecEndPos, tr.vecEndPos - g_pGlobals->v_up * 54.0f, false, false, GetEntity(), &tr2); + TraceLine(tr.vecEndPos, tr.vecEndPos - g_pGlobals->v_up * 54.0f, false, false, pev->pContainingEntity, &tr); // we don't want fall - if (tr2.flFraction == 1.0f) + if (tr.flFraction == 1.0f) { m_lastWallOrigin = pev->origin; return true; @@ -2346,7 +2536,7 @@ bool Bot::CheckWallOnLeft(void) MakeVectors(pev->angles); // do a trace to the left... - TraceLine(pev->origin, pev->origin - g_pGlobals->v_right * 54.0f, false, false, GetEntity(), &tr); + TraceLine(pev->origin, pev->origin - g_pGlobals->v_right * 54.0f, false, false, pev->pContainingEntity, &tr); // check if the trace hit something... if (tr.flFraction != 1.0f) @@ -2356,11 +2546,10 @@ bool Bot::CheckWallOnLeft(void) } else { - TraceResult tr2; - TraceLine(tr.vecEndPos, tr.vecEndPos - g_pGlobals->v_up * 54.0f, false, false, GetEntity(), &tr2); + TraceLine(tr.vecEndPos, tr.vecEndPos - g_pGlobals->v_up * 54.0f, false, false, pev->pContainingEntity, &tr); // we don't want fall - if (tr2.flFraction == 1.0f) + if (tr.flFraction == 1.0f) { m_lastWallOrigin = pev->origin; return true; @@ -2376,7 +2565,7 @@ bool Bot::CheckWallOnRight(void) MakeVectors(pev->angles); // do a trace to the right... - TraceLine(pev->origin, pev->origin + g_pGlobals->v_right * 54.0f, false, false, GetEntity(), &tr); + TraceLine(pev->origin, pev->origin + g_pGlobals->v_right * 54.0f, false, false, pev->pContainingEntity, &tr); // check if the trace hit something... if (tr.flFraction != 1.0f) @@ -2386,11 +2575,10 @@ bool Bot::CheckWallOnRight(void) } else { - TraceResult tr2; - TraceLine(tr.vecEndPos, tr.vecEndPos - g_pGlobals->v_up * 54.0f, false, false, GetEntity(), &tr2); + TraceLine(tr.vecEndPos, tr.vecEndPos - g_pGlobals->v_up * 54.0f, false, false, pev->pContainingEntity, &tr); // we don't want fall - if (tr2.flFraction == 1.0f) + if (tr.flFraction == 1.0f) { m_lastWallOrigin = pev->origin; return true; @@ -2415,7 +2603,7 @@ bool Bot::IsDeadlyDrop(Vector targetOriginPos) down.z = down.z - 1000.0f; // straight down 1000 units - TraceHull(check, down, true, head_hull, GetEntity(), &tr); + TraceHull(check, down, true, head_hull, pev->pContainingEntity, &tr); if (tr.flFraction > 0.036f) // We're not on ground anymore? tr.flFraction = 0.036f; @@ -2425,14 +2613,14 @@ bool Bot::IsDeadlyDrop(Vector targetOriginPos) float distance = (targetOriginPos - check).GetLengthSquared(); // distance from goal - while (distance > SquaredF(16.0f)) + while (distance > squaredf(16.0f)) { check = check + direction * 16.0f; // move 10 units closer to the goal... down = check; down.z = down.z - 1000.0f; // straight down 1000 units - TraceHull(check, down, true, head_hull, GetEntity(), &tr); + TraceHull(check, down, true, head_hull, pev->pContainingEntity, &tr); if (tr.fStartSolid) // Wall blocking? return false; @@ -2454,18 +2642,21 @@ void Bot::CheckCloseAvoidance(const Vector& dirNormal) if (ebot_has_semiclip.GetBool()) return; - if (GetGameMode() == MODE_DM || GetGameMode() == MODE_NOTEAM) + if (GetGameMode() == MODE_DM) + return; + + if (GetGameMode() == MODE_NOTEAM) return; if (pev->solid == SOLID_NOT) return; - float distance = SquaredF(512.0f); - const float maxSpeed = SquaredF(pev->maxspeed); + float distance = squaredf(512.0f); + const float maxSpeed = squaredf(pev->maxspeed); m_avoid = nullptr; // get our priority - const unsigned int myPri = GetPlayerPriority(GetEntity()); + const unsigned int myPri = GetPlayerPriority(pev->pContainingEntity); // find nearest player to bot for (const auto& client : g_clients) @@ -2487,7 +2678,7 @@ void Bot::CheckCloseAvoidance(const Vector& dirNormal) continue; // our team, alive and not myself? - if (client.team != m_team || client.ent == GetEntity()) + if (client.team != m_team || client.ent == pev->pContainingEntity) continue; // get priority of other player @@ -2523,14 +2714,10 @@ void Bot::CheckCloseAvoidance(const Vector& dirNormal) Bot* otherBot = g_botManager->GetBot(m_avoid); if (otherBot != nullptr) { - GetCurrentTask()->data = otherBot->GetCurrentTask()->data; m_prevGoalIndex = otherBot->m_prevGoalIndex; m_chosenGoalIndex = otherBot->m_chosenGoalIndex; - int index = GetCurrentGoalID(); - if (index == -1) - index = m_chosenGoalIndex; - + int index = m_chosenGoalIndex; if (index == -1) index = m_prevGoalIndex; @@ -2557,7 +2744,7 @@ void Bot::CheckCloseAvoidance(const Vector& dirNormal) const float nextFrameDistance = (pev->origin - (m_avoid->v.origin + m_avoid->v.velocity * interval)).GetLengthSquared(); // is player that near now or in future that we need to steer away? - if (movedDistance < SquaredF(72.0f) || (distance < SquaredF(80.0f) && nextFrameDistance < distance)) + if (movedDistance < squaredf(72.0f) || (distance < squaredf(80.0f) && nextFrameDistance < distance)) { const Vector dir = (pev->origin - m_avoid->v.origin).Normalize2D(); @@ -2567,7 +2754,7 @@ void Bot::CheckCloseAvoidance(const Vector& dirNormal) else SetStrafeSpeed(dirNormal, -pev->maxspeed); - if (distance < SquaredF(72.0f)) + if (distance < squaredf(72.0f)) { if ((dir | forward.Normalize2D()) < 0.0f) m_moveSpeed = -pev->maxspeed; @@ -2585,23 +2772,28 @@ int Bot::GetCampAimingWaypoint(void) int currentWay = m_currentWaypointIndex; if (!IsValidWaypoint(currentWay)) - currentWay = g_waypoint->FindNearest(pev->origin); + { + if (IsValidWaypoint(m_cachedWaypointIndex)) + currentWay = m_cachedWaypointIndex; + else + currentWay = g_waypoint->FindNearestInCircle(pev->origin); + } int DangerWaypoint = -1; - int i; for (i = 0; i < g_numWaypoints; i++) { - if (!IsValidWaypoint(i)) + if (currentWay == i) continue; - if (currentWay == i) + const Path* pointer = g_waypoint->GetPath(i); + if (pointer == nullptr) continue; - if (!IsVisible(g_waypoint->GetPath(i)->origin, GetEntity())) + if (!IsVisible(pointer->origin, pev->pContainingEntity)) continue; - if ((g_waypoint->GetPath(i)->origin - pev->origin).GetLengthSquared() > SquaredF(512.0f)) + if ((pointer->origin - pev->origin).GetLengthSquared() > squaredf(512.0f)) BestWaypoints.Push(i); else OkWaypoints.Push(i); @@ -2612,7 +2804,7 @@ int Bot::GetCampAimingWaypoint(void) else if (!OkWaypoints.IsEmpty()) return OkWaypoints.GetRandomElement(); - return g_waypoint->m_otherPoints.GetRandomElement(); + return crandomint(0, g_numWaypoints - 1); } void Bot::FacePosition(void) @@ -2689,7 +2881,7 @@ void Bot::FacePosition(void) { m_lookYawVel = 0.0f; m_idealAngles.y = direction.y; - m_aimStopTime = engine->GetTime() + CRandomFloat(0.25f, 1.25f); + m_aimStopTime = engine->GetTime() + crandomfloat(0.25f, 1.25f); } else { @@ -2738,7 +2930,7 @@ void Bot::SetStrafeSpeed(Vector moveDir, float strafeSpeed) m_strafeSpeed = m_tempstrafeSpeed; - if ((m_isStuck || pev->speed >= pev->maxspeed) && !IsOnLadder() && m_jumpTime + 5.0f < engine->GetTime() && IsOnFloor()) + if ((m_isStuck || pev->speed >= pev->maxspeed) && !IsOnLadder() && !m_jumping) pev->button |= IN_JUMP; } else if (dot > 0 && !CheckWallOnRight()) @@ -2752,23 +2944,34 @@ void Bot::SetStrafeSpeed(Vector moveDir, float strafeSpeed) // find hostage improve int Bot::FindHostage(void) { - if (m_team != TEAM_COUNTER || !(g_mapType & MAP_CS) || m_isZombieBot) + if (m_team != TEAM_COUNTER || !(g_mapType & MAP_CS)) return -1; edict_t* ent = nullptr; while (!FNullEnt(ent = FIND_ENTITY_BY_CLASSNAME(ent, "hostage_entity"))) { - bool canF = true; + if (ent->v.health <= 0.0f) + continue; + bool canF = true; for (const auto& bot : g_botManager->m_bots) { - if (bot != nullptr && bot->m_isAlive) + if (bot == nullptr) + continue; + + if (!bot->m_isAlive) + continue; + + for (const auto& hostage : bot->m_hostages) { - for (int j = 0; j < Const_MaxHostages; j++) - { - if (bot->m_hostages[j] == ent) - canF = false; - } + if (FNullEnt(hostage)) + continue; + + if (hostage->v.health <= 0.0f) + continue; + + if (hostage == ent) + canF = false; } } @@ -2780,8 +2983,7 @@ int Bot::FindHostage(void) else { // do we need second try? - const int nearestIndex2 = g_waypoint->FindNearest(entOrigin); - + const int nearestIndex2 = g_waypoint->FindNearestInCircle(entOrigin); if (IsValidWaypoint(nearestIndex2) && canF) return nearestIndex2; } @@ -2809,8 +3011,7 @@ int Bot::FindLoosedBomb(void) else { // do we need second try? - const int nearestIndex2 = g_waypoint->FindNearest(bombOrigin); - + const int nearestIndex2 = g_waypoint->FindNearestInCircle(bombOrigin); if (IsValidWaypoint(nearestIndex2)) return nearestIndex2; } @@ -2824,6 +3025,15 @@ int Bot::FindLoosedBomb(void) bool Bot::IsWaypointOccupied(const int index) { + if (ebot_has_semiclip.GetBool()) + return false; + + if (GetGameMode() == MODE_DM) + return false; + + if (GetGameMode() == MODE_NOTEAM) + return false; + if (pev->solid == SOLID_NOT) return false; @@ -2835,14 +3045,14 @@ bool Bot::IsWaypointOccupied(const int index) if (FNullEnt(client.ent)) continue; - if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team != m_team || client.ent == GetEntity()) + if (!(client.flags & CFLAG_USED) || !(client.flags & CFLAG_ALIVE) || client.team != m_team || client.ent == pev->pContainingEntity) continue; - auto bot = g_botManager->GetBot(client.index); + Bot* bot = g_botManager->GetBot(client.index); if (bot != nullptr) { - if (bot->m_chosenGoalIndex == index) - return true; + if (bot == this) + return false; if (bot->m_currentWaypointIndex == index) return true; @@ -2853,7 +3063,7 @@ bool Bot::IsWaypointOccupied(const int index) else { const Path* pointer = g_waypoint->GetPath(index); - if (pointer && ((client.ent->v.origin + client.ent->v.velocity * m_frameInterval) - pointer->origin).GetLengthSquared() < SquaredI(pointer->radius + 54)) + if (pointer && ((client.ent->v.origin + client.ent->v.velocity * m_frameInterval) - pointer->origin).GetLengthSquared() < squaredi(pointer->radius + 54)) return true; } } diff --git a/source/netmsg.cpp b/source/netmsg.cpp index 1f5bbfa..08f761e 100644 --- a/source/netmsg.cpp +++ b/source/netmsg.cpp @@ -29,10 +29,8 @@ NetworkMsg::NetworkMsg(void) m_message = NETMSG_UNDEFINED; m_state = 0; m_bot = nullptr; - - int i; - for (i = 0; i < NETMSG_NUM; i++) - m_registerdMessages[i] = NETMSG_UNDEFINED; + for (auto& reg : m_registerdMessages) + reg = NETMSG_UNDEFINED; } void NetworkMsg::HandleMessageIfRequired(const int messageType, const int requiredType) @@ -46,7 +44,7 @@ void NetworkMsg::Execute(void* p) if (m_message == NETMSG_UNDEFINED) return; // no message or not for bot, return - // some needed variables + // some needed variables static uint8_t r, g, b; static uint8_t enabled; @@ -88,21 +86,21 @@ void NetworkMsg::Execute(void* p) if (m_bot != nullptr) { const char* x = PTR_TO_STR(p); - if (cstrcmp(x, "#Team_Select") == 0) // team select menu? + if (cstrncmp(x, "#Team_Select", 13) == 0) // team select menu? m_bot->m_startAction = CMENU_TEAM; - else if (cstrcmp(x, "#Team_Select_Spect") == 0) // team select menu? + else if (cstrncmp(x, "#Team_Select_Spect", 19) == 0) // team select menu? m_bot->m_startAction = CMENU_TEAM; - else if (cstrcmp(x, "#IG_Team_Select_Spect") == 0) // team select menu? + else if (cstrncmp(x, "#IG_Team_Select_Spect", 22) == 0) // team select menu? m_bot->m_startAction = CMENU_TEAM; - else if (cstrcmp(x, "#IG_Team_Select") == 0) // team select menu? + else if (cstrncmp(x, "#IG_Team_Select", 16) == 0) // team select menu? m_bot->m_startAction = CMENU_TEAM; - else if (cstrcmp(x, "#IG_VIP_Team_Select") == 0) // team select menu? + else if (cstrncmp(x, "#IG_VIP_Team_Select", 20) == 0) // team select menu? m_bot->m_startAction = CMENU_TEAM; - else if (cstrcmp(x, "#IG_VIP_Team_Select_Spect") == 0) // team select menu? + else if (cstrncmp(x, "#IG_VIP_Team_Select_Spect", 26) == 0) // team select menu? m_bot->m_startAction = CMENU_TEAM; - else if (cstrcmp(x, "#Terrorist_Select") == 0) // T model select? + else if (cstrncmp(x, "#Terrorist_Select", 18) == 0) // T model select? m_bot->m_startAction = CMENU_CLASS; - else if (cstrcmp(x, "#CT_Select") == 0) // CT model select menu? + else if (cstrncmp(x, "#CT_Select", 11) == 0) // CT model select menu? m_bot->m_startAction = CMENU_CLASS; } @@ -114,7 +112,7 @@ void NetworkMsg::Execute(void* p) switch (m_state) { case 0: - cstrcpy(weaponProp.className, PTR_TO_STR(p)); + cstrncpy(weaponProp.className, PTR_TO_STR(p), sizeof(weaponProp.className)); break; case 1: @@ -160,7 +158,7 @@ void NetworkMsg::Execute(void* p) case 2: clip = PTR_TO_INT(p); // ammo currently in the clip for this weapon - if (m_bot != nullptr && id <= 31) + if (m_bot != nullptr && id < Const_MaxWeapons) { if (state != 0) m_bot->m_currentWeapon = id; @@ -246,16 +244,16 @@ void NetworkMsg::Execute(void* p) if (g_gameVersion != HALFLIFE && m_bot != nullptr) { const char* x = PTR_TO_STR(p); - if (cstrcmp(x, "defuser") == 0) + if (cstrncmp(x, "defuser", 8) == 0) m_bot->m_hasDefuser = (enabled != 0); - else if (cstrcmp(x, "buyzone") == 0) + else if (cstrncmp(x, "buyzone", 8) == 0) { m_bot->m_inBuyZone = (enabled != 0); m_bot->EquipInBuyzone(0); } - else if (cstrcmp(x, "vipsafety") == 0) + else if (cstrncmp(x, "vipsafety", 10) == 0) m_bot->m_inVIPZone = (enabled != 0); - else if (cstrcmp(x, "c4") == 0) + else if (cstrncmp(x, "c4", 3) == 0) m_bot->m_inBombZone = (enabled == 2); } @@ -263,7 +261,7 @@ void NetworkMsg::Execute(void* p) } break; - case NETMSG_DEATH: // this message sends on death + /*case NETMSG_DEATH: // this message sends on death switch (m_state) { case 0: @@ -289,7 +287,7 @@ void NetworkMsg::Execute(void* p) break; } break; - + */ case NETMSG_SCREENFADE: // this message gets sent when the Screen fades (Flashbang) switch (m_state) { @@ -307,8 +305,11 @@ void NetworkMsg::Execute(void* p) case 6: if (m_bot != nullptr) - m_bot->TakeBlinded(Vector(r, g, b), PTR_TO_BYTE(p)); - + { + const int alpha = PTR_TO_BYTE(p); + if (r == 255 && g == 255 && b == 255 && alpha > 170) + m_bot->TakeBlinded(alpha); + } break; } diff --git a/source/support.cpp b/source/support.cpp index 6b5b973..2a7b451 100644 --- a/source/support.cpp +++ b/source/support.cpp @@ -176,7 +176,7 @@ Vector GetNearestWalkablePosition(const Vector& origin, edict_t* ent, bool retur FirstOrigin = nullvec; if (g_numWaypoints > 0) - SecondOrigin = g_waypoint->GetPath(g_waypoint->FindNearest(origin))->origin; // get nearest waypoint for walk + SecondOrigin = g_waypoint->GetPath(g_waypoint->FindNearestInCircle(origin))->origin; // get nearest waypoint for walk else SecondOrigin = nullvec; @@ -657,8 +657,9 @@ void RoundInit(void) for (const auto& client : g_clients) { - if (g_botManager->GetBot(client.index) != nullptr) - g_botManager->GetBot(client.index)->NewRound(); + Bot* bot = g_botManager->GetBot(client.index); + if (bot != nullptr) + bot->NewRound(); g_radioSelect[client.index] = 0; } @@ -674,7 +675,6 @@ void RoundInit(void) g_lastRadioTime[1] = 0.0f; g_botsCanPause = false; - g_waypoint->ClearGoalScore(); g_waypoint->SetBombPosition(true); if (g_gameVersion != HALFLIFE) @@ -947,7 +947,7 @@ bool IsWeaponShootingThroughWall(int id) return false; } -void SetGameMode(int gamemode) +void SetGameMode(const int gamemode) { ebot_gamemod.SetInt(gamemode); } @@ -962,7 +962,7 @@ bool IsDeathmatchMode(void) return (ebot_gamemod.GetInt() == MODE_DM || ebot_gamemod.GetInt() == MODE_TDM); } -bool IsValidWaypoint(int index) +bool IsValidWaypoint(const int index) { if (index < 0 || index >= g_numWaypoints) return false; @@ -1094,14 +1094,14 @@ int SetEntityWaypoint(edict_t* ent, int mode) if (getWpOrigin != nullvec && wpIndex >= 0 && wpIndex < g_numWaypoints) { float distance = (getWpOrigin - origin).GetLengthSquared(); - if (distance >= SquaredF(300.0f)) + if (distance >= squaredf(300.0f)) needCheckNewWaypoint = true; - else if (distance >= SquaredF(32.0f)) + else if (distance >= squaredf(32.0f)) { Vector wpOrigin = g_waypoint->GetPath(wpIndex)->origin; distance = (wpOrigin - origin).GetLengthSquared(); - if (distance > SquaredF(g_waypoint->GetPath(wpIndex)->radius + 32.0f)) + if (distance > squaredf(g_waypoint->GetPath(wpIndex)->radius + 32.0f)) needCheckNewWaypoint = true; else { @@ -1263,9 +1263,9 @@ void HudMessage(edict_t* ent, bool toCenter, const Color& rgb, char* format, ... WRITE_BYTE(static_cast (rgb.green)); WRITE_BYTE(static_cast (rgb.blue)); WRITE_BYTE(0); - WRITE_BYTE(CRandomInt(230, 255)); - WRITE_BYTE(CRandomInt(230, 255)); - WRITE_BYTE(CRandomInt(230, 255)); + WRITE_BYTE(crandomint(230, 255)); + WRITE_BYTE(crandomint(230, 255)); + WRITE_BYTE(crandomint(230, 255)); WRITE_BYTE(200); WRITE_SHORT(FixedUnsigned16(0.0078125, 1 << 8)); WRITE_SHORT(FixedUnsigned16(2, 1 << 8)); @@ -1884,7 +1884,7 @@ void GetVoiceAndDur(ChatterMessage message, char** voice, float* dur) { if (message == ChatterMessage::Yes) { - int rV = CRandomInt(1, 12); + int rV = crandomint(1, 12); if (rV == 1) { *voice = "affirmative"; @@ -1948,7 +1948,7 @@ void GetVoiceAndDur(ChatterMessage message, char** voice, float* dur) } else if (message == ChatterMessage::No) { - int rV = CRandomInt(1, 13); + int rV = crandomint(1, 13); if (rV == 1) { *voice = "ahh_negative"; @@ -2017,7 +2017,7 @@ void GetVoiceAndDur(ChatterMessage message, char** voice, float* dur) } else if (message == ChatterMessage::SeeksEnemy) { - int rV = CRandomInt(1, 15); + int rV = crandomint(1, 15); if (rV == 1) { *voice = "help"; @@ -2096,7 +2096,7 @@ void GetVoiceAndDur(ChatterMessage message, char** voice, float* dur) } else if (message == ChatterMessage::Clear) { - int rV = CRandomInt(1, 17); + int rV = crandomint(1, 17); if (rV == 1) { *voice = "clear"; @@ -2209,7 +2209,7 @@ void GetVoiceAndDur(ChatterMessage message, char** voice, float* dur) } else if (message == ChatterMessage::CoverMe) { - int rV = CRandomInt(1, 2); + int rV = crandomint(1, 2); if (rV == 1) { *voice = "cover_me"; @@ -2223,7 +2223,7 @@ void GetVoiceAndDur(ChatterMessage message, char** voice, float* dur) } else if (message == ChatterMessage::Happy) { - int rV = CRandomInt(1, 10); + int rV = crandomint(1, 10); if (rV == 1) { *voice = "yea_baby"; diff --git a/source/waypoint.cpp b/source/waypoint.cpp index 1e9def7..684251c 100644 --- a/source/waypoint.cpp +++ b/source/waypoint.cpp @@ -23,6 +23,13 @@ // #include +#ifdef WIN32 +#include +#else +#include +#endif +#include +mutex mtx; ConVar ebot_analyze_distance("ebot_analyze_distance", "40"); ConVar ebot_analyze_disable_fall_connections("ebot_analyze_disable_fall_connections", "0"); @@ -45,14 +52,13 @@ void Waypoint::Initialize(void) // have any waypoint path nodes been allocated yet? if (m_waypointPaths) { - int i; - for (i = 0; i < g_numWaypoints; i++) + for (auto& path : m_paths) { - if (m_paths[i] == nullptr) + if (path == nullptr) continue; - delete m_paths[i]; - m_paths[i] = nullptr; + delete path; + path = nullptr; } } @@ -60,6 +66,31 @@ void Waypoint::Initialize(void) m_lastWaypoint = nullvec; } +void AddWaypointsForEntities(const char* className, const Vector& TargetPosition, const Vector& targetOrigin, float goalDist, bool checkEffect = false) +{ + TraceResult vis{}; + edict_t* ent = nullptr; + while (!FNullEnt(ent = FIND_ENTITY_BY_CLASSNAME(ent, className))) + { + if (checkEffect && (ent->v.effects & EF_NODRAW) && ent->v.speed > 0.0f) + continue; + + const Vector entOrigin = GetEntityOrigin(ent); + TraceHull(TargetPosition, entOrigin, true, point_hull, g_hostEntity, &vis); + + if (g_waypoint->IsNodeReachable(targetOrigin, TargetPosition) && g_waypoint->IsNodeReachable(TargetPosition, targetOrigin) && vis.flFraction == 1.0f && (TargetPosition - entOrigin).GetLengthSquared() < goalDist) + g_waypoint->Add(100, TargetPosition); + } +} + +bool CheckCrouchRequirement(const Vector& TargetPosition, const Vector& targetOrigin) +{ + TraceResult upcheck{}; + const Vector TargetPosition2 = Vector(TargetPosition.x, TargetPosition.y, (TargetPosition.z + 36.0f)); + TraceHull(TargetPosition, TargetPosition2, true, point_hull, g_hostEntity, &upcheck); + return upcheck.flFraction != 1.0f; +} + void CreateWaypoint(Vector Next, float range, float goalDist) { Next.z += 19.0f; @@ -68,98 +99,48 @@ void CreateWaypoint(Vector Next, float range, float goalDist) Next.z -= 19.0f; range *= 0.75f; - if (tr.flFraction == 1.0f || IsBreakable(tr.pHit)) - { - const int startindex = g_waypoint->FindNearestInCircle(tr.vecEndPos, range); - - if (!IsValidWaypoint(startindex)) - { - TraceResult tr2; - TraceHull(tr.vecEndPos, Vector(tr.vecEndPos.x, tr.vecEndPos.y, (tr.vecEndPos.z - 800.0f)), NO_BOTH, HULL_HEAD, g_hostEntity, &tr2); - - if (tr2.flFraction != 1.0f) - { - bool isBreakable = IsBreakable(tr.pHit); - Vector TargetPosition = tr2.vecEndPos; - TargetPosition.z = TargetPosition.z + 19.0f;// +36.0f; + if (tr.flFraction != 1.0f && !IsBreakable(tr.pHit)) + return; - const int endindex = g_waypoint->FindNearestInCircle(TargetPosition, range); + const int startindex = g_waypoint->FindNearestInCircleSingle(tr.vecEndPos, range); + if (IsValidWaypoint(startindex)) + return; - if (!IsValidWaypoint(endindex)) - { - const Vector targetOrigin = g_waypoint->GetPath(g_waypoint->FindNearestInCircle(TargetPosition, 250.0f))->origin; + TraceResult tr2{}; + TraceHull(tr.vecEndPos, Vector(tr.vecEndPos.x, tr.vecEndPos.y, (tr.vecEndPos.z - 800.0f)), NO_BOTH, HULL_HEAD, g_hostEntity, &tr2); - if (!IsZombieMode()) - { - if (g_mapType & MAP_DE) - { - edict_t* ent = nullptr; - while (!FNullEnt(ent = FIND_ENTITY_BY_CLASSNAME(ent, "func_bomb_target"))) - { - const Vector entOrigin = GetEntityOrigin(ent); - TraceResult vis; - TraceLine(TargetPosition, entOrigin, true, false, g_hostEntity, &vis); - - if (g_waypoint->IsNodeReachable(targetOrigin, TargetPosition) && g_waypoint->IsNodeReachable(TargetPosition, targetOrigin) && vis.flFraction == 1.0f && (TargetPosition - entOrigin).GetLengthSquared() < goalDist) - g_waypoint->Add(100, TargetPosition); - } - - while (!FNullEnt(ent = FIND_ENTITY_BY_CLASSNAME(ent, "info_bomb_target"))) - { - const Vector entOrigin = GetEntityOrigin(ent); - TraceResult vis; - TraceLine(TargetPosition, entOrigin, true, false, g_hostEntity, &vis); - - if (g_waypoint->IsNodeReachable(targetOrigin, TargetPosition) && g_waypoint->IsNodeReachable(TargetPosition, targetOrigin) && vis.flFraction == 1.0f && (TargetPosition - entOrigin).GetLengthSquared() < goalDist) - g_waypoint->Add(100, TargetPosition); - } - } - else if (g_mapType & MAP_CS) - { - edict_t* ent = nullptr; - while (!FNullEnt(ent = FIND_ENTITY_BY_CLASSNAME(ent, "hostage_entity"))) - { - // if already saved || moving skip it - if (ent->v.effects & EF_NODRAW && ent->v.speed > 0) - continue; - - const Vector entOrigin = GetEntityOrigin(ent); - TraceResult vis; - TraceLine(TargetPosition, entOrigin, true, false, g_hostEntity, &vis); - - if (g_waypoint->IsNodeReachable(targetOrigin, TargetPosition) && g_waypoint->IsNodeReachable(TargetPosition, targetOrigin) && vis.flFraction == 1.0f && (TargetPosition - entOrigin).GetLengthSquared() < goalDist) - g_waypoint->Add(100, TargetPosition); - } - } - } + if (tr2.flFraction == 1.0f) + return; - const int doublecheckindex = g_waypoint->FindNearest(TargetPosition, range); - if (!IsValidWaypoint(doublecheckindex)) - { - g_analyzeputrequirescrouch = false; + const bool isBreakable = IsBreakable(tr.pHit); + Vector TargetPosition = tr2.vecEndPos; + TargetPosition.z = TargetPosition.z + 19.0f; - TraceResult upcheck; - Vector TargetPosition2 = Vector(TargetPosition.x, TargetPosition.y, (TargetPosition.z + 36.0f)); - TraceLine(TargetPosition, TargetPosition2, true, false, g_hostEntity, &upcheck); + const int endindex = g_waypoint->FindNearestInCircleSingle(TargetPosition, range); + if (IsValidWaypoint(endindex)) + return; - if (upcheck.flFraction != 1.0f) - g_analyzeputrequirescrouch = true; + const Vector targetOrigin = g_waypoint->GetPath(g_waypoint->FindNearestInCircleSingle(TargetPosition, 256.0f))->origin; - if ((g_waypoint->IsNodeReachable(targetOrigin, g_analyzeputrequirescrouch ? Vector(TargetPosition.x, TargetPosition.y, (TargetPosition.z - 18.0f)) : TargetPosition) && - g_waypoint->IsNodeReachable(g_analyzeputrequirescrouch ? Vector(TargetPosition.x, TargetPosition.y, (TargetPosition.z - 18.0f)) : TargetPosition, targetOrigin)) - || (g_waypoint->IsNodeReachableWithJump(targetOrigin, g_analyzeputrequirescrouch ? Vector(TargetPosition.x, TargetPosition.y, (TargetPosition.z - 18.0f)) : TargetPosition, -1) && g_waypoint->IsNodeReachableWithJump(targetOrigin, g_analyzeputrequirescrouch ? Vector(TargetPosition.x, TargetPosition.y, (TargetPosition.z - 18.0f)) : TargetPosition, -1))) - g_waypoint->Add(isBreakable ? 1 : -1, g_analyzeputrequirescrouch ? Vector(TargetPosition.x, TargetPosition.y, (TargetPosition.z - 18.0f)) : TargetPosition); - } - } - } + if (!IsZombieMode()) + { + if (g_mapType & MAP_DE) + { + AddWaypointsForEntities("func_bomb_target", TargetPosition, targetOrigin, goalDist); + AddWaypointsForEntities("info_bomb_target", TargetPosition, targetOrigin, goalDist); } + else if (g_mapType & MAP_CS) + AddWaypointsForEntities("hostage_entity", TargetPosition, targetOrigin, goalDist, true); } + + g_analyzeputrequirescrouch = CheckCrouchRequirement(TargetPosition, targetOrigin); + if (g_waypoint->IsNodeReachable(targetOrigin, TargetPosition)) + g_waypoint->Add(isBreakable ? 1 : -1, g_analyzeputrequirescrouch ? Vector(TargetPosition.x, TargetPosition.y, (TargetPosition.z - 18.0f)) : TargetPosition); } void AnalyzeThread(void) { - float goalDist = SquaredF(ebot_analyze_goal_check_distance.GetFloat()); - + const float goalDist = squaredf(ebot_analyze_goal_check_distance.GetFloat()); if (!ebot_use_old_analyzer.GetBool()) { if (!FNullEnt(g_hostEntity)) @@ -171,8 +152,10 @@ void AnalyzeThread(void) HudMessage(g_hostEntity, true, Color(100, 100, 255), message); } - else if (!IsDedicatedServer()) // let player join first... + else if (!IsDedicatedServer()) + { return; + } static float magicTimer; int i; @@ -180,94 +163,64 @@ void AnalyzeThread(void) { if (g_expanded[i]) continue; - + if (magicTimer > engine->GetTime()) return; if ((ebot_analyzer_min_fps.GetFloat() + g_pGlobals->frametime) < 1.0f / g_pGlobals->frametime) - magicTimer = engine->GetTime() + g_pGlobals->frametime * 0.066f; // pause + magicTimer = engine->GetTime() + g_pGlobals->frametime * 0.066f; - Vector WayVec = g_waypoint->GetPath(i)->origin; - float range = ebot_analyze_distance.GetFloat(); + const Vector WayVec = g_waypoint->GetPath(i)->origin; + const float range = ebot_analyze_distance.GetFloat(); int dir; - for (dir = 1; dir < 8; dir++) + for (dir = 1; dir <= 8; dir++) { + Vector Next; switch (dir) { - case 1: - { - Vector Next; - Next.x = WayVec.x + range; - Next.y = WayVec.y; - Next.z = WayVec.z; - - CreateWaypoint(Next, range, goalDist); - } - case 2: - { - Vector Next; - Next.x = WayVec.x - range; - Next.y = WayVec.y; - Next.z = WayVec.z; - - CreateWaypoint(Next, range, goalDist); - } - case 3: - { - Vector Next; - Next.x = WayVec.x; - Next.y = WayVec.y + range; - Next.z = WayVec.z; - - CreateWaypoint(Next, range, goalDist); - } - case 4: - { - Vector Next; - Next.x = WayVec.x; - Next.y = WayVec.y - range; - Next.z = WayVec.z; - - CreateWaypoint(Next, range, goalDist); - } - case 5: - { - Vector Next; - Next.x = WayVec.x + range; - Next.y = WayVec.y; - Next.z = WayVec.z + 128.0f; - - CreateWaypoint(Next, range, goalDist); - } - case 6: - { - Vector Next; - Next.x = WayVec.x - range; - Next.y = WayVec.y; - Next.z = WayVec.z + 128.0f; - - CreateWaypoint(Next, range, goalDist); - } - case 7: - { - Vector Next; - Next.x = WayVec.x; - Next.y = WayVec.y + range; - Next.z = WayVec.z + 128.0f; - - CreateWaypoint(Next, range, goalDist); - } - case 8: - { - Vector Next; - Next.x = WayVec.x; - Next.y = WayVec.y - range; - Next.z = WayVec.z + 128.0f; - - CreateWaypoint(Next, range, goalDist); - } + case 1: + Next.x = WayVec.x + range; + Next.y = WayVec.y; + Next.z = WayVec.z; + break; + case 2: + Next.x = WayVec.x - range; + Next.y = WayVec.y; + Next.z = WayVec.z; + break; + case 3: + Next.x = WayVec.x; + Next.y = WayVec.y + range; + Next.z = WayVec.z; + break; + case 4: + Next.x = WayVec.x; + Next.y = WayVec.y - range; + Next.z = WayVec.z; + break; + case 5: + Next.x = WayVec.x + range; + Next.y = WayVec.y; + Next.z = WayVec.z + 128.0f; + break; + case 6: + Next.x = WayVec.x - range; + Next.y = WayVec.y; + Next.z = WayVec.z + 128.0f; + break; + case 7: + Next.x = WayVec.x; + Next.y = WayVec.y + range; + Next.z = WayVec.z + 128.0f; + break; + case 8: + Next.x = WayVec.x; + Next.y = WayVec.y - range; + Next.z = WayVec.z + 128.0f; + break; } + CreateWaypoint(Next, range, goalDist); } g_expanded[i] = true; @@ -282,22 +235,19 @@ void AnalyzeThread(void) g_waypoint->Load(); ServerCommand("exec addons/ebot/ebot.cfg"); } - - return; } - - int i; - for (i = 0; i < g_numWaypoints; i++) + else { - if (IsValidWaypoint(i)) + int i; + for (i = 0; i < g_numWaypoints; i++) { - Vector WayVec = g_waypoint->GetPath(i)->origin; - float ran = ebot_analyze_distance.GetFloat(); + const Vector WayVec = g_waypoint->GetPath(i)->origin; + const float ran = ebot_analyze_distance.GetFloat(); Vector Start; - Start.x = WayVec.x + CRandomFloat(((-ran) - 5.0f), (ran + 5.0f)); - Start.y = WayVec.y + CRandomFloat(((-ran) - 5.0f), (ran + 5.0f)); - Start.z = WayVec.z + CRandomFloat(1, ran); + Start.x = WayVec.x + crandomfloat(((-ran) - 5.0f), (ran + 5.0f)); + Start.y = WayVec.y + crandomfloat(((-ran) - 5.0f), (ran + 5.0f)); + Start.z = WayVec.z + crandomfloat(1, ran); CreateWaypoint(Start, ran, goalDist); } @@ -428,13 +378,56 @@ void Waypoint::AddPath(const int addIndex, const int pathIndex, const int type) } } +bool Waypoint::CollectWaypoints(const int index, Array & wp) +{ + if (!IsValidWaypoint(index)) + return false; + + wp.Push(index); + + const Path* path = m_paths[index]; + if (path == nullptr) + return false; + + for (const auto link : path->index) + { + if (!IsValidWaypoint(link)) + continue; + + const Path* connection = m_paths[link]; + if (connection == nullptr) + continue; + + wp.Push(link); + + for (const auto link2 : connection->index) + { + if (!IsValidWaypoint(link2)) + continue; + + if (link2 == link) + continue; + + if (link2 == index) + continue; + + if (m_paths[link2] == nullptr) + continue; + + wp.Push(link2); + } + } + + return true; +} + // find the farest node to that origin, and return the index to this node -int Waypoint::FindFarest(const Vector& origin, float maxDistance) +void Waypoint::FindFarestThread(const Vector origin, const float maxDistance, int& index) { + mtx.lock(); int i; - int index = -1; float distance; - float squaredDistance = SquaredF(maxDistance); + float squaredDistance = squaredf(maxDistance); for (i = 0; i < g_numWaypoints; i++) { @@ -448,17 +441,64 @@ int Waypoint::FindFarest(const Vector& origin, float maxDistance) squaredDistance = distance; } } + mtx.unlock(); +} +int Waypoint::FindFarest(const Vector origin, const float maxDistance) +{ + int index = -1; +#ifdef WIN32 + thread core(&Waypoint::FindFarestThread, this, origin, maxDistance, ref(index)); +#else + const auto reff = ref(index); + cthread core([this, origin, maxDistance, reff]() { this->FindFarestThread(origin, maxDistance, reff); }); +#endif + core.join(); return index; } // find the farest node to that origin, and return the index to this node -int Waypoint::FindNearestInCircle(const Vector& origin, float maxDistance) +void Waypoint::FindNearestInCircleThread(const Vector origin, const float maxDistance, int& index) { + mtx.lock(); int i; + float distance; + float squaredDistance = squaredf(maxDistance); + + for (i = 0; i < g_numWaypoints; i++) + { + if (m_paths[i] == nullptr) + continue; + + distance = (m_paths[i]->origin - origin).GetLengthSquared(); + if (distance < squaredDistance) + { + index = i; + squaredDistance = distance; + } + } + mtx.unlock(); +} + +int Waypoint::FindNearestInCircle(const Vector origin, const float maxDistance) +{ int index = -1; +#ifdef WIN32 + thread core(&Waypoint::FindNearestInCircleThread, this, origin, maxDistance, ref(index)); +#else + const auto reff = ref(index); + cthread core([this, origin, maxDistance, reff]() { this->FindNearestInCircleThread(origin, maxDistance, reff); }); +#endif + core.join(); + return index; +} + +int Waypoint::FindNearestInCircleSingle(const Vector origin, const float maxDistance) +{ + int index = -1; + int i; float distance; - float squaredDistance = SquaredF(maxDistance); + float squaredDistance = squaredf(maxDistance); for (i = 0; i < g_numWaypoints; i++) { @@ -485,10 +525,11 @@ void Waypoint::ChangeZBCampPoint(Vector origin) if (!m_zmHmPoints.IsEmpty()) { int i; - for (i = m_zmHmPoints.GetElementNumber(); i >= 0; i--) + for (i = 0; i < m_zmHmPoints.GetElementNumber(); i++) { int wpIndex; - m_zmHmPoints.GetAt(i, wpIndex); + if (!m_zmHmPoints.GetAt(i, wpIndex)) + continue; if (IsValidWaypoint(wpIndex)) { @@ -510,7 +551,7 @@ void Waypoint::ChangeZBCampPoint(Vector origin) if (point[0] != -1) m_zmHmPoints.Push(point[0]); - const int newPoint = FindNearest(origin); + const int newPoint = FindNearestInCircle(origin); if (newPoint != -1 && newPoint != point[0] && newPoint != point[1]) m_zmHmPoints.Push(newPoint); } @@ -521,10 +562,11 @@ bool Waypoint::IsZBCampPoint(const int pointID, const bool checkMesh) return false; int i; - for (i = 0; i <= m_zmHmPoints.GetElementNumber(); i++) + for (i = 0; i < m_zmHmPoints.GetElementNumber(); i++) { int wpIndex; - m_zmHmPoints.GetAt(i, wpIndex); + if (!m_zmHmPoints.GetAt(i, wpIndex)) + continue; if (pointID == wpIndex) return true; @@ -532,10 +574,11 @@ bool Waypoint::IsZBCampPoint(const int pointID, const bool checkMesh) if (checkMesh && !g_waypoint->m_hmMeshPoints.IsEmpty()) { - for (i = 0; i <= m_hmMeshPoints.GetElementNumber(); i++) + for (i = 0; i < m_hmMeshPoints.GetElementNumber(); i++) { int wpIndex; - m_hmMeshPoints.GetAt(i, wpIndex); + if (!m_hmMeshPoints.GetAt(i, wpIndex)) + continue; if (pointID == wpIndex) return true; @@ -547,7 +590,7 @@ bool Waypoint::IsZBCampPoint(const int pointID, const bool checkMesh) int Waypoint::FindNearest(Vector origin, float minDistance, int flags, edict_t* entity, int* findWaypointPoint, int mode) { - float squaredMinDistance = SquaredF(minDistance); + float squaredMinDistance = squaredf(minDistance); const int checkPoint = 20; float wpDistance[checkPoint]; int wpIndex[checkPoint]; @@ -561,7 +604,7 @@ int Waypoint::FindNearest(Vector origin, float minDistance, int flags, edict_t* for (i = 0; i < g_numWaypoints; i++) { - if (!IsValidWaypoint(i) || m_paths[i] == nullptr) + if (m_paths[i] == nullptr) continue; if (flags != -1 && !(m_paths[i]->flags & flags)) @@ -573,7 +616,7 @@ int Waypoint::FindNearest(Vector origin, float minDistance, int flags, edict_t* const Vector dest = m_paths[i]->origin; const float distance2D = (dest - origin).GetLengthSquared2D(); - if (((dest.z > origin.z + 62.0f || dest.z < origin.z - 100.0f) && !(m_paths[i]->flags & WAYPOINT_LADDER)) && distance2D < SquaredF(30.0f)) + if (((dest.z > origin.z + 62.0f || dest.z < origin.z - 100.0f) && !(m_paths[i]->flags & WAYPOINT_LADDER)) && distance2D < squaredf(30.0f)) continue; int y; @@ -657,7 +700,7 @@ int Waypoint::FindNearest(Vector origin, float minDistance, int flags, edict_t* continue; // Use the path variable in the condition - if (wpDistance[i] > SquaredF(path->radius) && !Reachable(entity, wpIndex[i])) + if (wpDistance[i] > squaredf(path->radius) && !Reachable(entity, wpIndex[i])) continue; if (findWaypointPoint == (int*)-2) @@ -686,7 +729,7 @@ int Waypoint::FindNearest(Vector origin, float minDistance, int flags, edict_t* void Waypoint::FindInRadius(Vector origin, float radius, int* holdTab, int* count) { const int maxCount = *count; - const float rad = SquaredF(radius); + const float rad = squaredf(radius); *count = 0; int i; @@ -710,7 +753,7 @@ void Waypoint::FindInRadius(Vector origin, float radius, int* holdTab, int* coun void Waypoint::FindInRadius(Array & queueID, float radius, Vector origin) { - const float rad = SquaredF(radius); + const float rad = squaredf(radius); int i; for (i = 0; i < g_numWaypoints; i++) { @@ -822,10 +865,10 @@ void Waypoint::Add(int flags, Vector waypointOrigin) newOrigin = m_learnPosition; break; case 10: - index = FindNearest(GetEntityOrigin(g_hostEntity), 25.0f); + index = FindNearestInCircle(GetEntityOrigin(g_hostEntity), 25.0f); if (IsValidWaypoint(index)) { - if ((m_paths[index]->origin - GetEntityOrigin(g_hostEntity)).GetLengthSquared() <= SquaredF(25.0f)) + if ((m_paths[index]->origin - GetEntityOrigin(g_hostEntity)).GetLengthSquared() <= squaredf(25.0f)) { placeNew = false; path = m_paths[index]; @@ -1095,7 +1138,7 @@ void Waypoint::Delete(void) if (g_botManager->GetBotsNum() > 0) g_botManager->RemoveAll(); - const int index = FindNearest(GetEntityOrigin(g_hostEntity), 75.0f); + const int index = FindNearestInCircle(GetEntityOrigin(g_hostEntity), 75.0f); if (!IsValidWaypoint(index)) return; @@ -1209,7 +1252,7 @@ void Waypoint::DeleteByIndex(const int index) void Waypoint::DeleteFlags(void) { - const int index = FindNearest(GetEntityOrigin(g_hostEntity), 75.0f); + const int index = FindNearestInCircle(GetEntityOrigin(g_hostEntity), 75.0f); if (!IsValidWaypoint(index)) return; @@ -1223,7 +1266,7 @@ void Waypoint::DeleteFlags(void) // this function allow manually changing flags void Waypoint::ToggleFlags(const int toggleFlag) { - const int index = FindNearest(GetEntityOrigin(g_hostEntity), 75.0f); + const int index = FindNearestInCircle(GetEntityOrigin(g_hostEntity), 75.0f); if (!IsValidWaypoint(index)) return; @@ -1253,7 +1296,7 @@ void Waypoint::SetRadius(const int radius) if (radius < 0 || radius > 255) return; - const int index = FindNearest(GetEntityOrigin(g_hostEntity), 75.0f); + const int index = FindNearestInCircle(GetEntityOrigin(g_hostEntity), 75.0f); if (!IsValidWaypoint(index)) return; @@ -1282,7 +1325,7 @@ bool Waypoint::IsConnected(const int pointA, const int16 pointB) if (m_paths[pointA] == nullptr) return false; - for (const auto& connection : m_paths[pointA]->index) + for (const auto connection : m_paths[pointA]->index) { if (connection == pointB) return true; @@ -1299,7 +1342,7 @@ int Waypoint::GetFacingIndex(void) int pointedIndex = -1; float range = 5.32f; - const int nearestWaypoint = FindNearest(g_hostEntity->v.origin, 54.0f); + const int nearestWaypoint = FindNearestInCircle(g_hostEntity->v.origin, 54.0f); // check bounds from eyes of editor const Vector eyePosition = g_hostEntity->v.origin + g_hostEntity->v.view_ofs; @@ -1320,7 +1363,7 @@ int Waypoint::GetFacingIndex(void) angles.ClampAngles(); // skip the waypoints that are too far away from us, and we're not looking at them directly - if (to.GetLengthSquared() > SquaredF(500.0f) || cabsf(angles.y) > range) + if (to.GetLengthSquared() > squaredf(500.0f) || cabsf(angles.y) > range) continue; // check if visible, (we're not using visiblity tables here, as they not valid at time of waypoint editing) @@ -1350,14 +1393,14 @@ int Waypoint::GetFacingIndex(void) // this function allow player to manually create a path from one waypoint to another void Waypoint::CreatePath(char dir) { - const int nodeFrom = FindNearest(GetEntityOrigin(g_hostEntity), 75.0f); + const int nodeFrom = FindNearestInCircle(GetEntityOrigin(g_hostEntity), 75.0f); if (nodeFrom == -1) { CenterPrint("Unable to find nearest waypoint in 75 units"); return; } - int nodeTo = m_facingAtIndex; + int nodeTo = m_facingAtIndex; if (!IsValidWaypoint(nodeTo)) { if (IsValidWaypoint(m_cacheWaypointIndex)) @@ -1410,7 +1453,7 @@ void Waypoint::TeleportWaypoint(void) // this function allow player to manually remove a path from one waypoint to another void Waypoint::DeletePath(void) { - int nodeFrom = FindNearest(GetEntityOrigin(g_hostEntity), 75.0f); + int nodeFrom = FindNearestInCircle(GetEntityOrigin(g_hostEntity), 75.0f); int index = 0; if (!IsValidWaypoint(nodeFrom)) @@ -1475,7 +1518,7 @@ void Waypoint::DeletePath(void) void Waypoint::CacheWaypoint(void) { - const int node = FindNearest(GetEntityOrigin(g_hostEntity), 75.0f); + const int node = FindNearestInCircle(GetEntityOrigin(g_hostEntity), 75.0f); if (!IsValidWaypoint(node)) { m_cacheWaypointIndex = -1; @@ -1494,45 +1537,53 @@ void Waypoint::CalculateWayzone(const int index) if (path == nullptr) return; - Vector start, direction; - - TraceResult tr{}; - bool wayBlocked = false; - if ((path->flags & (WAYPOINT_LADDER | WAYPOINT_GOAL | WAYPOINT_CAMP | WAYPOINT_RESCUE | WAYPOINT_CROUCH)) || m_learnJumpWaypoint) { - path->radius = 0.0f; + path->radius = 0; return; } int i; for (i = 0; i < Const_MaxPathIndex; i++) { - if (path->index[i] != -1 && m_paths[path->index[i]] && (m_paths[path->index[i]]->flags & WAYPOINT_LADDER)) + if (!IsValidWaypoint(path->index[i])) + continue; + + const Path* pointer = m_paths[path->index[i]]; + if (pointer == nullptr) + continue; + + if (pointer->flags & WAYPOINT_LADDER) { - path->radius = 0.0f; + path->radius = 0; return; } } - float scanDistance; - float circleRadius; - for (scanDistance = 16.0f; scanDistance < 160.0f; scanDistance += 16.0f) + bool wayBlocked = false; + Vector start, direction; + TraceResult tr{}; + int finalRadius = 0; + + uint8_t scanDistance; + uint8_t circleRadius; + for (scanDistance = 16; scanDistance < 160; scanDistance += 16) { start = path->origin; MakeVectors(nullvec); - direction = g_pGlobals->v_forward * scanDistance; + const float sd = static_cast(scanDistance); + direction = g_pGlobals->v_forward * sd; direction = direction.ToAngles(); - path->radius = scanDistance; + finalRadius = static_cast(scanDistance); - for (circleRadius = 0.0f; circleRadius < 180.0f; circleRadius += 5.0f) + for (circleRadius = 0; circleRadius < 180; circleRadius += 5) { MakeVectors(direction); - const Vector radiusStart = start - g_pGlobals->v_forward * scanDistance; - Vector radiusEnd = start + g_pGlobals->v_forward * scanDistance; + const Vector radiusStart = start - g_pGlobals->v_forward * sd; + Vector radiusEnd = start + g_pGlobals->v_forward * sd; TraceHull(radiusStart, radiusEnd, true, head_hull, nullptr, &tr); @@ -1542,40 +1593,40 @@ void Waypoint::CalculateWayzone(const int index) if (FClassnameIs(tr.pHit, "func_door") || FClassnameIs(tr.pHit, "func_door_rotating")) { - path->radius = 0.0f; + finalRadius = 4; wayBlocked = true; break; } wayBlocked = true; - path->radius -= 16.0f; + finalRadius -= 16.0f; break; } - Vector dropStart = start + (g_pGlobals->v_forward * scanDistance); - Vector dropEnd = dropStart - Vector(0.0f, 0.0f, scanDistance + 60.0f); + Vector dropStart = start + (g_pGlobals->v_forward * sd); + Vector dropEnd = dropStart - Vector(0.0f, 0.0f, sd + 60.0f); TraceHull(dropStart, dropEnd, true, head_hull, nullptr, &tr); if (tr.flFraction >= 1.0f) { wayBlocked = true; - path->radius -= 16.0f; + finalRadius -= 16.0f; break; } - dropStart = start - (g_pGlobals->v_forward * scanDistance); - dropEnd = dropStart - Vector(0.0f, 0.0f, scanDistance + 60.0f); + dropStart = start - (g_pGlobals->v_forward * sd); + dropEnd = dropStart - Vector(0.0f, 0.0f, sd + 60.0f); TraceHull(dropStart, dropEnd, true, head_hull, nullptr, &tr); if (tr.flFraction >= 1.0f) { wayBlocked = true; - path->radius -= 16.0f; + finalRadius -= 16.0f; break; } @@ -1585,20 +1636,22 @@ void Waypoint::CalculateWayzone(const int index) if (tr.flFraction < 1.0f) { wayBlocked = true; - path->radius -= 16.0f; + finalRadius -= 16.0f; break; } - direction.y = AngleNormalize(direction.y + circleRadius); + direction.y = AngleNormalize(direction.y + static_cast(circleRadius)); } if (wayBlocked) break; } - path->radius -= 16.0f; - if (path->radius < 0.0f) - path->radius = 0.0f; + finalRadius -= 16; + if (finalRadius < 0) + finalRadius = 0; + + path->radius = static_cast(cclamp(finalRadius, 0, 255)); } Vector Waypoint::GetBottomOrigin(const Path* waypoint) @@ -1623,7 +1676,6 @@ void Waypoint::InitTypes() m_visitedGoals.Destroy(); m_zmHmPoints.Destroy(); m_hmMeshPoints.Destroy(); - m_otherPoints.Destroy(); int i; for (i = 0; i < g_numWaypoints; i++) @@ -1647,8 +1699,6 @@ void Waypoint::InitTypes() m_terrorPoints.Push(i); else if (m_paths[i]->flags & WAYPOINT_COUNTER) m_ctPoints.Push(i); - else if (m_paths[i]->flags == 0) - m_otherPoints.Push(i); } } @@ -1656,28 +1706,31 @@ bool Waypoint::Download(void) { #ifdef PLATFORM_WIN32 // could be missing or corrupted? then avoid crash... - HMODULE hUrlMon = LoadLibrary("urlmon.dll"); + const HMODULE hUrlMon = LoadLibrary("urlmon.dll"); if (hUrlMon != nullptr) { - ServerPrint("UrlMon loaded successfully\n"); + ServerPrint("UrlMon found on the machine"); typedef HRESULT(WINAPI* URLDownloadToFileFn)(LPUNKNOWN, LPCSTR, LPCSTR, DWORD, LPBINDSTATUSCALLBACK); - URLDownloadToFileFn pURLDownloadToFile = reinterpret_cast(GetProcAddress(hUrlMon, "URLDownloadToFileA")); + const URLDownloadToFileFn pURLDownloadToFile = reinterpret_cast(GetProcAddress(hUrlMon, "URLDownloadToFileA")); if (pURLDownloadToFile != nullptr) { - ServerPrint("UrlMon loaded successfully\n"); + ServerPrint("UrlMon loaded successfully"); if (SUCCEEDED(pURLDownloadToFile(nullptr, FormatBuffer("%s/%s.ewp", ebot_download_waypoints_from.GetString(), GetMapName()), (char*)CheckSubfolderFile(), 0, nullptr))) { - ServerPrint("Download successful\n"); + ServerPrint("UrlMon downloaded successfully"); FreeLibrary(hUrlMon); return true; } } else - ServerPrint("Error: Could not find URLDownloadToFileA in UrlMon, could be courrupted\n"); + ServerPrint("Error: Could not find URLDownloadToFileA in UrlMon, UrlMon is courrupted!\n"); - FreeLibrary(hUrlMon); + if (FreeLibrary(hUrlMon)) + ServerPrint("UrlMon unloaded successfully"); + else + ServerPrint("Cannot able to unload UrlMon!"); } else ServerPrint("Error: Could not load UrlMon, could be missing or courrupted\n"); @@ -1693,22 +1746,22 @@ bool Waypoint::Download(void) char command[512]; snprintf(command, sizeof(command), "wget -O %s %s", filepath, downloadURL); - printf("Executing command: %s\n", command); + printf("Executing wget command: %s", command); const int result = system(command); if (result == 0) { - ServerPrint("Download successful wget\n"); + ServerPrint("WGET Download successful"); return true; } else { - ServerPrint("Error: wget command failed with code %d\n", result); + ServerPrint("Error: wget command failed with code %d", result); return false; } } else - ServerPrint("Error: Neither curl nor wget is available\n"); + ServerPrint("Error: Neither curl nor wget is available"); #endif return false; } @@ -1756,9 +1809,9 @@ bool Waypoint::Load(void) continue; m_paths[i]->origin = paths[i]->origin; - m_paths[i]->radius = static_cast(paths[i]->radius); - m_paths[i]->flags = static_cast(paths[i]->flags); - m_paths[i]->mesh = static_cast(paths[i]->mesh); + m_paths[i]->radius = static_cast(cclamp(paths[i]->radius, 0, 255)); + m_paths[i]->flags = static_cast(cmax(0, paths[i]->flags)); + m_paths[i]->mesh = static_cast(cclamp(paths[i]->mesh, 0, 255)); m_paths[i]->gravity = paths[i]->gravity; int C; @@ -1787,9 +1840,9 @@ bool Waypoint::Load(void) continue; m_paths[i]->origin = paths[i]->origin; - m_paths[i]->radius = static_cast(paths[i]->radius); - m_paths[i]->flags = static_cast(paths[i]->flags); - m_paths[i]->mesh = static_cast(paths[i]->campStartX); + m_paths[i]->radius = static_cast(cclampf(paths[i]->radius, 0.0f, 255.0f)); + m_paths[i]->flags = static_cast(cmax(0, paths[i]->flags)); + m_paths[i]->mesh = static_cast(cclampf(paths[i]->campStartX, 0.0f, 255.0f)); m_paths[i]->gravity = paths[i]->campStartY; int C; @@ -1850,9 +1903,6 @@ bool Waypoint::Load(void) g_botManager->InitQuota(); - extern ConVar ebot_debuggoal; - ebot_debuggoal.SetInt(-1); - return true; } @@ -2003,10 +2053,10 @@ void Waypoint::SaveOLD(void) if (paths[i]->connectionFlags[x] & PATHFLAG_JUMP) { - const float timeToReachWaypoint = csqrtf(SquaredF(waypointOrigin.x - myOrigin.x) + SquaredF(waypointOrigin.y - myOrigin.y)) / 250.0f; + const float timeToReachWaypoint = csqrtf(squaredf(waypointOrigin.x - myOrigin.x) + squaredf(waypointOrigin.y - myOrigin.y)) / 250.0f; paths[i]->connectionVelocity[x].x = (waypointOrigin.x - myOrigin.x) / timeToReachWaypoint; paths[i]->connectionVelocity[x].y = (waypointOrigin.y - myOrigin.y) / timeToReachWaypoint; - paths[i]->connectionVelocity[x].z = 2.0f * (waypointOrigin.z - myOrigin.z - 0.5f * 1.0f * SquaredF(timeToReachWaypoint)) / timeToReachWaypoint; + paths[i]->connectionVelocity[x].z = 2.0f * (waypointOrigin.z - myOrigin.z - 0.5f * 1.0f * squaredf(timeToReachWaypoint)) / timeToReachWaypoint; if (paths[i]->connectionVelocity[x].z > 250.0f) paths[i]->connectionVelocity[x].z = 250.0f; @@ -2053,14 +2103,14 @@ String Waypoint::CheckSubfolderFileOLD(void) return FormatBuffer("%s%s.pwf", GetWaypointDir(), GetMapName()); } -// this function returns 2D traveltime to a position +// this function returns traveltime to a position float Waypoint::GetTravelTime(const float maxSpeed, const Vector src, const Vector origin) { // give 10 sec... if (src == nullvec || origin == nullvec) return 10.0f; - return (origin - src).GetLengthSquared2D() / SquaredF(cabsf(maxSpeed)); + return (origin - src).GetLength() / cabsf(maxSpeed); } bool Waypoint::Reachable(edict_t* entity, const int index) @@ -2077,12 +2127,12 @@ bool Waypoint::Reachable(edict_t* entity, const int index) const Vector src = GetEntityOrigin(entity); const Vector dest = m_paths[index]->origin; - if ((dest - src).GetLengthSquared() > SquaredF(1200.0f)) + if ((dest - src).GetLengthSquared() > squaredf(1200.0f)) return false; if (entity->v.waterlevel != 2 && entity->v.waterlevel != 3) { - if ((dest.z > src.z + 62.0f || dest.z < src.z - 100.0f) && (!(GetPath(index)->flags & WAYPOINT_LADDER) || (dest - src).GetLengthSquared2D() > SquaredF(120.0f))) + if ((dest.z > src.z + 62.0f || dest.z < src.z - 100.0f) && (!(GetPath(index)->flags & WAYPOINT_LADDER) || (dest - src).GetLengthSquared2D() > squaredf(120.0f))) return false; } @@ -2099,7 +2149,7 @@ bool Waypoint::IsNodeReachable(const Vector src, const Vector destination) float distance = (destination - src).GetLengthSquared(); // is the destination not close enough? - if (distance > SquaredF(g_autoPathDistance)) + if (distance > squaredf(g_autoPathDistance)) return false; TraceResult tr{}; @@ -2155,7 +2205,7 @@ bool Waypoint::IsNodeReachable(const Vector src, const Vector destination) float lastHeight = tr.flFraction * 1000.0f; // height from ground distance = (destination - check).GetLengthSquared(); // distance from goal - while (distance > SquaredF(10.0f)) + while (distance > squaredf(10.0f)) { // move 10 units closer to the goal... check = check + (direction * 10.0f); @@ -2189,7 +2239,7 @@ bool Waypoint::IsNodeReachableWithJump(const Vector src, const Vector destinatio float distance = (destination - src).GetLengthSquared(); // is the destination not close enough? - if (distance > SquaredF(g_autoPathDistance)) + if (distance > squaredf(g_autoPathDistance)) return false; TraceResult tr{}; @@ -2244,7 +2294,7 @@ bool Waypoint::IsNodeReachableWithJump(const Vector src, const Vector destinatio float lastHeight = tr.flFraction * 1000.0f; // height from ground distance = (destination - check).GetLengthSquared(); // distance from goal - while (distance > SquaredF(10.0f)) + while (distance > squaredf(10.0f)) { // move 10 units closer to the goal... check = check + (direction * 10.0f); @@ -2444,7 +2494,7 @@ void Waypoint::Think(void) float distance = (m_lastWaypoint - GetEntityOrigin(g_hostEntity)).GetLengthSquared(); int newWaypointDistance = (g_numWaypoints >= 800) ? 16384 : 12000; - if (g_waypoint->GetPath(g_waypoint->FindNearest(m_lastWaypoint, 10.0f))->radius == 0.0f) + if (g_waypoint->GetPath(g_waypoint->FindNearestInCircle(m_lastWaypoint, 10.0f))->radius == 0.0f) newWaypointDistance = 10000; if (distance > newWaypointDistance) @@ -2506,7 +2556,7 @@ void Waypoint::Think(void) } // make sure nearest waypoint is far enough away... - if (nearestDistance >= 16384) + if (nearestDistance > 16384) Add(0); // place a waypoint here } } @@ -2528,7 +2578,7 @@ void Waypoint::ShowWaypointMsg(void) const float distance = (m_paths[i]->origin - GetEntityOrigin(g_hostEntity)).GetLengthSquared(); // check if waypoint is whitin a distance, and is visible - if ((distance < SquaredF(640.0f) && ::IsVisible(m_paths[i]->origin, g_hostEntity) && IsInViewCone(m_paths[i]->origin, g_hostEntity)) || distance < SquaredF(48.0f)) + if ((distance < squaredf(640.0f) && ::IsVisible(m_paths[i]->origin, g_hostEntity) && IsInViewCone(m_paths[i]->origin, g_hostEntity)) || distance < squaredf(48.0f)) { // check the distance if (distance < nearestDistance) @@ -2660,7 +2710,7 @@ void Waypoint::ShowWaypointMsg(void) }; // now iterate through all waypoints in a map, and draw required ones - const int random = CRandomInt(1, 2); + const int random = crandomint(1, 2); if (random == 1) { int i; @@ -2707,7 +2757,7 @@ void Waypoint::ShowWaypointMsg(void) return; // draw a paths, camplines and danger directions for nearest waypoint - if (nearestDistance < SquaredF(2048) && m_pathDisplayTime < engine->GetTime()) + if (nearestDistance < squaredf(2048) && m_pathDisplayTime < engine->GetTime()) { m_pathDisplayTime = engine->GetTime() + 1.0f; @@ -3009,7 +3059,7 @@ void Waypoint::SetGoalVisited(const int index) if (!IsGoalVisited(index) && (m_paths[index]->flags & WAYPOINT_GOAL)) { - const int bombPoint = FindNearest(GetBombPosition()); + const int bombPoint = FindNearestInCircle(GetBombPosition()); if (IsValidWaypoint(bombPoint) && bombPoint != index) m_visitedGoals.Push(index); } @@ -3041,7 +3091,7 @@ void Waypoint::CreateBasic(void) TraceResult tr{}; Vector up, down, front, back; - Vector diff = (ladderLeft - ladderRight) * 15.0f; + const Vector diff = ((ladderLeft - ladderRight) ^ Vector(0.0f, 0.0f, 1.0f)).Normalize() * 15.0f; front = back = GetEntityOrigin(ent); front = front + diff; // front @@ -3050,7 +3100,7 @@ void Waypoint::CreateBasic(void) up = down = front; down.z = ent->v.absmax.z; - TraceHull(down, up, true, point_hull, g_hostEntity, &tr); + TraceHull(down, up, true, point_hull, nullptr, &tr); if (tr.flFraction != 1.0f || POINT_CONTENTS(up) == CONTENTS_SOLID) { @@ -3058,24 +3108,23 @@ void Waypoint::CreateBasic(void) down.z = ent->v.absmax.z; } - TraceHull(down, up - Vector(0.0f, 0.0f, 1000.0f), true, point_hull, g_hostEntity, &tr); + TraceHull(down, up - Vector(0.0f, 0.0f, 1000.0f), true, point_hull, nullptr, &tr); up = tr.vecEndPos; - Vector pointOrigin = up + Vector(0.0f, 0.0f, 39.0f); + Vector point = up + Vector(0.0f, 0.0f, 39.0f); m_isOnLadder = true; do { - if (FindNearest(pointOrigin, 50.0f) == -1) - Add(-1, pointOrigin); - - pointOrigin.z += 160.0f; - } while (pointOrigin.z < down.z - 40.0f); + if (FindNearestInCircleSingle(point, 50.0f) == -1) + Add(-1, point); + point.z += 160.0f; + } while (point.z < down.z - 40.0f); - pointOrigin = down + Vector(0.0f, 0.0f, 38.0f); + point = down + Vector(0.0f, 0.0f, 38.0f); - if (FindNearest(pointOrigin, 50.0f) == -1) - Add(-1, pointOrigin); + if (FindNearestInCircleSingle(point, 50.0f) == -1) + Add(-1, point); m_isOnLadder = false; } @@ -3085,7 +3134,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetWalkablePosition(GetEntityOrigin(ent), ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(0, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3094,7 +3143,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetWalkablePosition(GetEntityOrigin(ent), ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(0, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3103,7 +3152,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetWalkablePosition(GetEntityOrigin(ent), ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(0, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3112,7 +3161,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetWalkablePosition(GetEntityOrigin(ent), ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(4, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3121,7 +3170,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetWalkablePosition(GetEntityOrigin(ent), ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(4, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3130,7 +3179,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetWalkablePosition(GetEntityOrigin(ent), ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(100, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3139,7 +3188,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetWalkablePosition(GetEntityOrigin(ent), ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(100, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3152,9 +3201,9 @@ void Waypoint::CreateBasic(void) Vector origin = GetEntityOrigin(ent); - if (g_analyzewaypoints && FindNearest(origin, 250.0f) == -1) + if (g_analyzewaypoints && FindNearestInCircleSingle(origin, 250.0f) == -1) Add(2, Vector(origin.x, origin.y, (origin.z + 36.0f))); // goal waypoints will be added by analyzer - else if (FindNearest(origin, 50.0f) == -1) + else if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(100, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3163,7 +3212,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetWalkablePosition(GetEntityOrigin(ent), ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(100, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3172,7 +3221,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetWalkablePosition(GetEntityOrigin(ent), ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(100, Vector(origin.x, origin.y, (origin.z + 36.0f))); } @@ -3181,7 +3230,7 @@ void Waypoint::CreateBasic(void) { Vector origin = GetEntityOrigin(ent); - if (FindNearest(origin, 50.0f) == -1) + if (FindNearestInCircleSingle(origin, 50.0f) == -1) Add(0, Vector(origin.x, origin.y, (origin.z + 36.0f))); } } @@ -3189,7 +3238,7 @@ void Waypoint::CreateBasic(void) Path* Waypoint::GetPath(const int id) { if (!IsValidWaypoint(id)) - return m_paths[CRandomInt(0, g_numWaypoints - 1)]; + return m_paths[crandomint(0, g_numWaypoints - 1)]; return m_paths[id]; } @@ -3232,43 +3281,6 @@ void Waypoint::SetFindIndex(const int index) } } -int Waypoint::AddGoalScore(int index, int other[4]) -{ - Array left; - - if (m_goalsScore[index] < 1024.0f) - left.Push(index); - - int i; - for (i = 0; i < 3; i++) - { - if (m_goalsScore[other[i]] < 1024.0f) - left.Push(other[i]); - } - - if (left.IsEmpty()) - index = other[CRandomInt(0, 3)]; - else - index = left.GetRandomElement(); - - if (m_paths[index]->flags & WAYPOINT_GOAL) - m_goalsScore[index] += 384.0f; - else if (m_paths[index]->flags & (WAYPOINT_COUNTER | WAYPOINT_TERRORIST)) - m_goalsScore[index] += 768.0f; - else if (m_paths[index]->flags & WAYPOINT_CAMP) - m_goalsScore[index] += 1024.0f; - - return index; -} - -void Waypoint::ClearGoalScore(void) -{ - // iterate though all waypoints - int i; - for (i = 0; i < g_numWaypoints; i++) - m_goalsScore[i] = 0.0f; -} - Waypoint::Waypoint(void) { m_waypointPaths = false; @@ -3296,7 +3308,6 @@ Waypoint::Waypoint(void) m_campPoints.Destroy(); m_rescuePoints.Destroy(); m_sniperPoints.Destroy(); - m_otherPoints.Destroy(); } Waypoint::~Waypoint(void)