diff --git a/include/core.h b/include/core.h index 630e96e..c098269 100644 --- a/include/core.h +++ b/include/core.h @@ -122,7 +122,8 @@ enum ClientFlags { CF_USED = (1 << 0), CF_ALIVE = (1 << 1), - CF_ADMIN = (1 << 2) + CF_ADMIN = (1 << 2), + CF_CHATTER = (1 << 3) }; // radio messages @@ -870,6 +871,7 @@ private: bool CanDuckUnder (const Vector &normal); bool CanJumpUp (const Vector &normal); + bool FinishCanJumpUp (const Vector &normal); bool CantMoveForward (const Vector &normal, TraceResult *tr); // split RunTask into RunTask_* functions @@ -937,6 +939,7 @@ private: int FindCoverWaypoint (float maxDistance); int FindDefendWaypoint (const Vector &origin); int FindGoal (void); + int FinishFindGoal (int tactic, Array *defensive, Array *offsensive); void FilterGoals (const Array &goals, int *result); void FindItem (void); void CheckTerrain (float movedDistance, const Vector &dirNormal); @@ -1003,6 +1006,7 @@ private: bool LookupEnemy (void); bool IsEnemyHiddenByRendering (edict_t *enemy); void FireWeapon (void); + void FinishWeaponSelection (float distance, int index, int id, int choosen); void FocusEnemy (void); void SelectBestWeapon (void); diff --git a/source/basecode.cpp b/source/basecode.cpp index 5fe4a75..c4d0719 100644 --- a/source/basecode.cpp +++ b/source/basecode.cpp @@ -968,9 +968,19 @@ void Bot::SwitchChatterIcon (bool show) for (int i = 0; i < engine.MaxClients (); i++) { - if (!(g_clients[i].flags & CF_USED) || (g_clients[i].ent->v.flags & FL_FAKECLIENT) || g_clients[i].team != m_team) + Client &client = g_clients[i]; + + if ((show && !(client.flags & CF_CHATTER)) || (!show && (client.flags & CF_CHATTER))) continue; + if (!(client.flags & CF_USED) || (client.ent->v.flags & FL_FAKECLIENT) || client.team != m_team) + continue; + + if (show) + client.flags |= CF_CHATTER; + else + client.flags &= ~CF_CHATTER; + MESSAGE_BEGIN (MSG_ONE, engine.FindMessageId (NETMSG_BOTVOICE), NULL, g_clients[i].ent); // begin message WRITE_BYTE (show); // switch on/off WRITE_BYTE (GetIndex ()); diff --git a/source/combat.cpp b/source/combat.cpp index b24cc31..0cd2ccb 100644 --- a/source/combat.cpp +++ b/source/combat.cpp @@ -48,7 +48,7 @@ int Bot::GetNearbyEnemiesNearPosition(const Vector &origin, float radius) bool Bot::IsEnemyHiddenByRendering (edict_t *enemy) { - if (engine.IsNullEntity (enemy) || !yb_check_enemy_rendering.GetBool ()) + if (!yb_check_enemy_rendering.GetBool () || engine.IsNullEntity (enemy)) return false; entvars_t &v = enemy->v; @@ -718,92 +718,10 @@ bool Bot::DoFirePause (float distance) return false; } -void Bot::FireWeapon (void) +void Bot::FinishWeaponSelection (float distance, int index, int id, int choosen) { - // this function will return true if weapon was fired, false otherwise - float distance = (m_lookAt - EyePosition ()).GetLength (); // how far away is the enemy? - - // if using grenade stop this - if (m_isUsingGrenade) - { - m_shootTime = engine.Time () + 0.1f; - return; - } - - // or if friend in line of fire, stop this too but do not update shoot time - if (!engine.IsNullEntity (m_enemy)) - { - if (IsFriendInLineOfFire (distance)) - { - m_fightStyle = FIGHT_STRAFE; - m_lastFightStyleCheck = engine.Time (); - - return; - } - } WeaponSelect *tab = &g_weaponSelect[0]; - edict_t *enemy = m_enemy; - - int selectId = WEAPON_KNIFE, selectIndex = 0, chosenWeaponIndex = 0; - int weapons = pev->weapons; - - // if jason mode use knife only - if (yb_jasonmode.GetBool ()) - goto WeaponSelectEnd; - - // use knife if near and good difficulty (l33t dude!) - if (m_difficulty >= 3 && pev->health > 80.0f && !engine.IsNullEntity (enemy) && pev->health >= enemy->v.health && distance < 100.0f && !IsOnLadder () && !IsGroupOfEnemies (pev->origin)) - goto WeaponSelectEnd; - - // loop through all the weapons until terminator is found... - while (tab[selectIndex].id) - { - // is the bot carrying this weapon? - if (weapons & (1 << tab[selectIndex].id)) - { - // is enough ammo available to fire AND check is better to use pistol in our current situation... - if (m_ammoInClip[tab[selectIndex].id] > 0 && !IsWeaponBadInDistance (selectIndex, distance)) - chosenWeaponIndex = selectIndex; - } - selectIndex++; - } - selectId = tab[chosenWeaponIndex].id; - - // if no available weapon... - if (chosenWeaponIndex == 0) - { - selectIndex = 0; - - // loop through all the weapons until terminator is found... - while (tab[selectIndex].id) - { - int id = tab[selectIndex].id; - - // is the bot carrying this weapon? - if (weapons & (1 << id)) - { - if ( g_weaponDefs[id].ammo1 != -1 && g_weaponDefs[id].ammo1 < 32 && m_ammo[g_weaponDefs[id].ammo1] >= tab[selectIndex].minPrimaryAmmo) - { - // available ammo found, reload weapon - if (m_reloadState == RELOAD_NONE || m_reloadCheckTime > engine.Time ()) - { - m_isReloading = true; - m_reloadState = RELOAD_PRIMARY; - m_reloadCheckTime = engine.Time (); - - RadioMessage (Radio_NeedBackup); - } - return; - } - } - selectIndex++; - } - selectId = WEAPON_KNIFE; // no available ammo, use knife! - } - -WeaponSelectEnd: - // we want to fire weapon, don't reload now if (!m_isReloading) { @@ -812,9 +730,9 @@ WeaponSelectEnd: } // select this weapon if it isn't already selected - if (m_currentWeapon != selectId) + if (m_currentWeapon != id) { - SelectWeaponByName (g_weaponDefs[selectId].className); + SelectWeaponByName (g_weaponDefs[id].className); // reset burst fire variables m_firePause = 0.0f; @@ -823,17 +741,17 @@ WeaponSelectEnd: return; } - if (tab[chosenWeaponIndex].id != selectId) + if (tab[choosen].id != id) { - chosenWeaponIndex = 0; + choosen = 0; // loop through all the weapons until terminator is found... - while (tab[chosenWeaponIndex].id) + while (tab[choosen].id) { - if (tab[chosenWeaponIndex].id == selectId) + if (tab[choosen].id == id) break; - chosenWeaponIndex++; + choosen++; } } @@ -844,7 +762,7 @@ WeaponSelectEnd: { if (distance >= 750.0f && !IsShieldDrawn ()) pev->button |= IN_ATTACK2; // draw the shield - else if (IsShieldDrawn () || (!engine.IsNullEntity (m_enemy) && ((m_enemy->v.button & IN_RELOAD) || !IsEnemyViewable(m_enemy)))) + else if (IsShieldDrawn () || (!engine.IsNullEntity (m_enemy) && ((m_enemy->v.button & IN_RELOAD) || !IsEnemyViewable (m_enemy)))) pev->button |= IN_ATTACK2; // draw out the shield m_shieldCheckTime = engine.Time () + 1.0f; @@ -884,23 +802,23 @@ WeaponSelectEnd: // need to care for burst fire? if (distance < 256.0f || m_blindTime > engine.Time ()) { - if (selectId == WEAPON_KNIFE) + if (id == WEAPON_KNIFE) { if (distance < 64.0f) - { + { if (Random.Long (1, 100) < 30 || HasShield ()) pev->button |= IN_ATTACK; // use primary attack else pev->button |= IN_ATTACK2; // use secondary attack } - } + } else { - if (tab[chosenWeaponIndex].primaryFireHold && m_ammo[g_weaponDefs[tab[selectIndex].id].ammo1] > tab[selectIndex].minPrimaryAmmo) // if automatic weapon, just press attack + if (tab[choosen].primaryFireHold && m_ammo[g_weaponDefs[tab[index].id].ammo1] > tab[index].minPrimaryAmmo) // if automatic weapon, just press attack pev->button |= IN_ATTACK; else // if not, toggle buttons - { - if ((pev->oldbuttons & IN_ATTACK) == 0) + { + if ((pev->oldbuttons & IN_ATTACK) == 0) pev->button |= IN_ATTACK; } } @@ -912,17 +830,17 @@ WeaponSelectEnd: return; // don't attack with knife over long distance - if (selectId == WEAPON_KNIFE) + if (id == WEAPON_KNIFE) { m_shootTime = engine.Time (); return; } - if (tab[chosenWeaponIndex].primaryFireHold) + if (tab[choosen].primaryFireHold) { m_shootTime = engine.Time (); m_zoomCheckTime = engine.Time (); - + pev->button |= IN_ATTACK; // use primary attack } else @@ -935,6 +853,98 @@ WeaponSelectEnd: } } +void Bot::FireWeapon (void) +{ + // this function will return true if weapon was fired, false otherwise + float distance = (m_lookAt - EyePosition ()).GetLength (); // how far away is the enemy? + + // if using grenade stop this + if (m_isUsingGrenade) + { + m_shootTime = engine.Time () + 0.1f; + return; + } + + // or if friend in line of fire, stop this too but do not update shoot time + if (!engine.IsNullEntity (m_enemy)) + { + if (IsFriendInLineOfFire (distance)) + { + m_fightStyle = FIGHT_STRAFE; + m_lastFightStyleCheck = engine.Time (); + + return; + } + } + WeaponSelect *tab = &g_weaponSelect[0]; + + edict_t *enemy = m_enemy; + + int selectId = WEAPON_KNIFE, selectIndex = 0, choosenWeapon = 0; + int weapons = pev->weapons; + + // if jason mode use knife only + if (yb_jasonmode.GetBool ()) + { + FinishWeaponSelection (distance, selectIndex, selectId, choosenWeapon); + return; + } + + // use knife if near and good difficulty (l33t dude!) + if (m_difficulty >= 3 && pev->health > 80.0f && !engine.IsNullEntity (enemy) && pev->health >= enemy->v.health && distance < 100.0f && !IsOnLadder () && !IsGroupOfEnemies (pev->origin)) + { + FinishWeaponSelection (distance, selectIndex, selectId, choosenWeapon); + return; + } + + // loop through all the weapons until terminator is found... + while (tab[selectIndex].id) + { + // is the bot carrying this weapon? + if (weapons & (1 << tab[selectIndex].id)) + { + // is enough ammo available to fire AND check is better to use pistol in our current situation... + if (m_ammoInClip[tab[selectIndex].id] > 0 && !IsWeaponBadInDistance (selectIndex, distance)) + choosenWeapon = selectIndex; + } + selectIndex++; + } + selectId = tab[choosenWeapon].id; + + // if no available weapon... + if (choosenWeapon == 0) + { + selectIndex = 0; + + // loop through all the weapons until terminator is found... + while (tab[selectIndex].id) + { + int id = tab[selectIndex].id; + + // is the bot carrying this weapon? + if (weapons & (1 << id)) + { + if ( g_weaponDefs[id].ammo1 != -1 && g_weaponDefs[id].ammo1 < 32 && m_ammo[g_weaponDefs[id].ammo1] >= tab[selectIndex].minPrimaryAmmo) + { + // available ammo found, reload weapon + if (m_reloadState == RELOAD_NONE || m_reloadCheckTime > engine.Time ()) + { + m_isReloading = true; + m_reloadState = RELOAD_PRIMARY; + m_reloadCheckTime = engine.Time (); + + RadioMessage (Radio_NeedBackup); + } + return; + } + } + selectIndex++; + } + selectId = WEAPON_KNIFE; // no available ammo, use knife! + } + FinishWeaponSelection (distance, selectIndex, selectId, choosenWeapon); +} + bool Bot::IsWeaponBadInDistance (int weaponIndex, float distance) { // this function checks, is it better to use pistol instead of current primary weapon diff --git a/source/navigate.cpp b/source/navigate.cpp index e610d4d..cae6b74 100644 --- a/source/navigate.cpp +++ b/source/navigate.cpp @@ -31,13 +31,13 @@ int Bot::FindGoal (void) } } - // forcing terrorist bot to not move to another bombspot + // forcing terrorist bot to not move to another bomb spot if (m_inBombZone && !m_hasProgressBar && m_hasC4) return waypoints.FindNearest (pev->origin, 400.0f, FLAG_GOAL); } int tactic = 0; - // path finding behaviour depending on map type + // path finding behavior depending on map type float offensive = 0.0f; float defensive = 0.0f; @@ -68,14 +68,14 @@ int Bot::FindGoal (void) if (m_hasC4 || m_isVIP) { tactic = 3; - goto TacticChoosen; + return FinishFindGoal (tactic, defensiveWpts, offensiveWpts); } else if (m_team == CT && HasHostage ()) { tactic = 2; offensiveWpts = &waypoints.m_rescuePoints; - goto TacticChoosen; + return FinishFindGoal (tactic, defensiveWpts, offensiveWpts); } offensive = m_agressionLevel * 100.0f; @@ -153,11 +153,15 @@ int Bot::FindGoal (void) if (goalDesire > tacticChoice) tactic = 3; -TacticChoosen: - int goalChoices[4] = {-1, -1, -1, -1}; + return FinishFindGoal (tactic, defensiveWpts, offensiveWpts); +} - if (tactic == 0 && !(*defensiveWpts).IsEmpty ()) // careful goal - FilterGoals (*defensiveWpts, goalChoices); +int Bot::FinishFindGoal (int tactic, Array *defensive, Array *offsensive) +{ + int goalChoices[4] = { -1, -1, -1, -1 }; + + if (tactic == 0 && !(*defensive).IsEmpty ()) // careful goal + FilterGoals (*defensive, goalChoices); else if (tactic == 1 && !waypoints.m_campPoints.IsEmpty ()) // camp waypoint goal { // pickup sniper points if possible for sniping bots @@ -166,8 +170,8 @@ TacticChoosen: else FilterGoals (waypoints.m_campPoints, goalChoices); } - else if (tactic == 2 && !(*offensiveWpts).IsEmpty ()) // offensive goal - FilterGoals (*offensiveWpts, goalChoices); + else if (tactic == 2 && !(*offsensive).IsEmpty ()) // offensive goal + FilterGoals (*offsensive, goalChoices); else if (tactic == 3 && !waypoints.m_goalPoints.IsEmpty ()) // map goal waypoint { // force bomber to select closest goal, if round-start goal was reset by something @@ -213,7 +217,7 @@ TacticChoosen: m_currentWaypointIndex = ChangeWptIndex (waypoints.FindNearest (pev->origin)); if (goalChoices[0] == -1) - return m_chosenGoalIndex = Random.Long (0, g_numWaypoints - 1); + return m_chosenGoalIndex = Random.Long (0, g_numWaypoints - 1); bool isSorting = false; @@ -2712,7 +2716,7 @@ bool Bot::CanJumpUp (const Vector &normal) engine.TestLine (src, dest, TRACE_IGNORE_MONSTERS, GetEntity (), &tr); if (tr.flFraction < 1.0f) - goto CheckDuckJump; + return FinishCanJumpUp (normal); else { // now trace from jump height upward to check for obstructions... @@ -2734,7 +2738,7 @@ bool Bot::CanJumpUp (const Vector &normal) // if trace hit something, return false if (tr.flFraction < 1.0f) - goto CheckDuckJump; + return FinishCanJumpUp (normal); // now trace from jump height upward to check for obstructions... src = dest; @@ -2755,7 +2759,7 @@ bool Bot::CanJumpUp (const Vector &normal) // if trace hit something, return false if (tr.flFraction < 1.0f) - goto CheckDuckJump; + return FinishCanJumpUp (normal); // now trace from jump height upward to check for obstructions... src = dest; @@ -2765,13 +2769,15 @@ bool Bot::CanJumpUp (const Vector &normal) // if trace hit something, return false return tr.flFraction > 1.0f; +} - // here we check if a duck jump would work... -CheckDuckJump: - +bool Bot::FinishCanJumpUp (const Vector &normal) +{ // use center of the body first... maximum duck jump height is 62, so check one unit above that (63) - src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 63.0f); - dest = src + normal * 32.0f; + Vector src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 63.0f); + Vector dest = src + normal * 32.0f; + + TraceResult tr; // trace a line forward at maximum jump height... engine.TestLine (src, dest, TRACE_IGNORE_MONSTERS, GetEntity (), &tr);