From c6422c19a9ceb2f8482f829f182a1bf435d68e14 Mon Sep 17 00:00:00 2001 From: jeefo Date: Tue, 12 Jan 2016 15:53:14 +0300 Subject: [PATCH 1/3] autovacate remove for test --- source/interface.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/source/interface.cpp b/source/interface.cpp index cbf1b96..d1778ce 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -1105,11 +1105,6 @@ int ClientConnect (edict_t *ent, const char *name, const char *addr, char reject if (strcmp (addr, "loopback") == 0) g_hostEntity = ent; // save the edict of the listen server client... - extern ConVar yb_autovacate; - - if (IsDedicatedServer () && yb_autovacate.GetBool () && !IsValidBot (ent) && ent != g_hostEntity) - bots.RemoveRandom (); - if (g_isMetamod) RETURN_META_VALUE (MRES_IGNORED, 0); @@ -1129,12 +1124,6 @@ void ClientDisconnect (edict_t *ent) // to reset his entity pointer for safety. There are still a few server frames to go once a // listen server client disconnects, and we don't want to send him any sort of message then. - extern ConVar yb_autovacate; - extern ConVar yb_quota; - - if (yb_autovacate.GetBool () && IsValidPlayer (ent) && !IsValidBot (ent) && ent != g_hostEntity && yb_quota.GetInt () < GetMaxClients () - 1) - bots.AddRandom (); - int i = IndexOfEntity (ent) - 1; InternalAssert (i >= 0 && i < 32); From c850e45ed2ba8884bec6a84a2d3fb449c9d57753 Mon Sep 17 00:00:00 2001 From: jeefo Date: Tue, 12 Jan 2016 23:57:02 +0300 Subject: [PATCH 2/3] some rework of autovacate... again --- include/core.h | 11 ++++++ source/interface.cpp | 22 ++++++++++++ source/manager.cpp | 80 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 96 insertions(+), 17 deletions(-) diff --git a/include/core.h b/include/core.h index f712265..cd0ebc8 100644 --- a/include/core.h +++ b/include/core.h @@ -203,6 +203,14 @@ enum TaskID TASK_MAX }; +// autovacate state +enum QuotaOption +{ + QUOTA_NONE, + QUOTA_INCREMENT, + QUOTA_DECREMENT +}; + // supported cs's enum CSVersion { @@ -1367,6 +1375,8 @@ private: Array m_activeGrenades; edict_t *m_killerEntity; // killer entity for bots + int m_quotaOption; + protected: int CreateBot (const String &name, int difficulty, int personality, int team, int member); @@ -1411,6 +1421,7 @@ public: void RemoveMenu (edict_t *ent, int selection); void KillAll (int team = -1); void MaintainBotQuota (void); + void AdjustQuota (bool isPlayerConnection, edict_t *ent); void InitQuota (void); void ListBots (void); diff --git a/source/interface.cpp b/source/interface.cpp index d1778ce..3d3cd93 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -1111,6 +1111,25 @@ int ClientConnect (edict_t *ent, const char *name, const char *addr, char reject return (*g_functionTable.pfnClientConnect) (ent, name, addr, rejectReason); } +void ClientPutInServer (edict_t *ent) +{ + // this function is called once a just connected client actually enters the game, after + // having downloaded and synchronized its resources with the of the server's. It's the + // perfect place to hook for client connecting, since a client can always try to connect + // passing the ClientConnect() step, and not be allowed by the server later (because of a + // latency timeout or whatever reason). We can here keep track of both bots and players + // counts on occurence, since bots connect the server just like the way normal client do, + // and their third party bot flag is already supposed to be set then. If it's a bot which + // is connecting, we also have to awake its brain(s) by reading them from the disk. + + bots.AdjustQuota (true, ent); + + if (g_isMetamod) + RETURN_META (MRES_IGNORED); + + (*g_functionTable.pfnClientPutInServer) (ent); +} + void ClientDisconnect (edict_t *ent) { // this function is called whenever a client is VOLUNTARILY disconnected from the server, @@ -1124,6 +1143,8 @@ void ClientDisconnect (edict_t *ent) // to reset his entity pointer for safety. There are still a few server frames to go once a // listen server client disconnects, and we don't want to send him any sort of message then. + bots.AdjustQuota (false, ent); + int i = IndexOfEntity (ent) - 1; InternalAssert (i >= 0 && i < 32); @@ -2819,6 +2840,7 @@ export int GetEntityAPI2 (gamefuncs_t *functionTable, int *) functionTable->pfnTouch = Touch; functionTable->pfnClientConnect = ClientConnect; functionTable->pfnClientDisconnect = ClientDisconnect; + functionTable->pfnClientPutInServer = ClientPutInServer; functionTable->pfnClientUserInfoChanged = ClientUserInfoChanged; functionTable->pfnClientCommand = ClientCommand; functionTable->pfnServerActivate = ServerActivate; diff --git a/source/manager.cpp b/source/manager.cpp index 2612f64..979db9a 100644 --- a/source/manager.cpp +++ b/source/manager.cpp @@ -9,11 +9,10 @@ #include -ConVar yb_autovacate ("yb_autovacate", "-1"); +ConVar yb_autovacate ("yb_autovacate", "0"); -ConVar yb_quota ("yb_quota", "0"); -ConVar yb_quota_match ("yb_quota_match", "0"); -ConVar yb_quota_match_max ("yb_quota_match_max", "0"); +ConVar yb_quota ("yb_quota", "0", VT_NORMAL); +ConVar yb_quota_mode ("yb_quota_mode", "normal"); ConVar yb_join_after_player ("yb_join_after_player", "0"); ConVar yb_join_team ("yb_join_team", "any"); @@ -333,9 +332,21 @@ void BotManager::AddBot (const String &name, const String &difficulty, const Str m_creationTab.Push (bot); + int newBotsNum = GetBotsNum () + 1; + // keep quota number up to date - if (GetBotsNum () + 1 > yb_quota.GetInt ()) - yb_quota.SetInt (GetBotsNum () + 1); + if (newBotsNum < GetMaxClients () && newBotsNum > yb_quota.GetInt ()) + yb_quota.SetInt (newBotsNum); +} + +void BotManager::AdjustQuota (bool isPlayerConnection, edict_t *ent) +{ + // this function increases or decreases bot quota amount depending on autovacate variables + + if (!IsDedicatedServer () || !yb_autovacate.GetBool () || GetBot (ent) != NULL) + return; + + m_quotaOption = isPlayerConnection ? QUOTA_DECREMENT : QUOTA_INCREMENT; } void BotManager::MaintainBotQuota (void) @@ -346,12 +357,7 @@ void BotManager::MaintainBotQuota (void) if (g_numWaypoints < 1 || g_waypointsChanged) return; - if (yb_join_after_player.GetInt () > 0 && GetHumansJoinedTeam () == 0) - { - RemoveAll (false); - return; - } - + // bot's creation update if (!m_creationTab.IsEmpty () && m_maintainTime < GetWorldTime ()) { CreateQueue last = m_creationTab.Pop (); @@ -374,6 +380,46 @@ void BotManager::MaintainBotQuota (void) // now keep bot number up to date if (m_maintainTime < GetWorldTime ()) { + // don't allow that quota is below zero + if (yb_quota.GetInt () < 0) + yb_quota.SetInt (0); + + int numBots = GetBotsNum (); + int numHumans = GetHumansJoinedTeam (); + int desiredCount = yb_quota.GetInt (); + + if (yb_join_after_player.GetInt () > 0 && !numHumans) + desiredCount = 0; + + if (m_quotaOption != QUOTA_NONE && numBots > 1 && desiredCount > 1) + { + if (m_quotaOption == QUOTA_INCREMENT) + desiredCount++; + else + desiredCount--; + } + + // quota mode + char mode = yb_quota_mode.GetString ()[0]; + + if (mode == 'f') // fill + desiredCount = max (0, desiredCount - numHumans); + else if (mode == 'm') // match + desiredCount = max (0, yb_quota.GetInt () * numHumans); + + if (yb_autovacate.GetBool ()) + desiredCount = min (desiredCount, GetMaxClients () - (numHumans + 1)); + else + desiredCount = min (desiredCount, GetMaxClients () - numHumans); + + m_quotaOption = QUOTA_NONE; + + if (desiredCount > numBots) + AddRandom (); + else if (desiredCount < numBots) + RemoveRandom (); + +#if 0 int botNumber = GetBotsNum (); int humanNumber = GetHumansNum (); @@ -396,7 +442,7 @@ void BotManager::MaintainBotQuota (void) if (yb_autovacate.GetBool ()) { - if (botNumber < yb_quota.GetInt () && botNumber < GetMaxClients () - 1) + if (botNumber < yb_quota.GetInt () && humanNumber < GetMaxClients () - 1) AddRandom (); if (humanNumber >= GetMaxClients ()) @@ -404,11 +450,11 @@ void BotManager::MaintainBotQuota (void) } else { - if (botNumber < yb_quota.GetInt () && botNumber < GetMaxClients ()) + if (botNumber < yb_quota.GetInt () && humanNumber < GetMaxClients ()) AddRandom (); } - int botQuota = yb_autovacate.GetBool () ? (GetMaxClients () - 1 - (humanNumber + 1)) : GetMaxClients (); + int botQuota = yb_autovacate.GetBool () ? GetMaxClients () - humanNumber : GetMaxClients (); // check valid range of quota if (yb_quota.GetInt () > botQuota) @@ -416,7 +462,7 @@ void BotManager::MaintainBotQuota (void) else if (yb_quota.GetInt () < 0) yb_quota.SetInt (0); - +#endif m_maintainTime = GetWorldTime () + 0.15f; } } @@ -425,6 +471,7 @@ void BotManager::InitQuota (void) { m_maintainTime = GetWorldTime () + 3.0f; m_creationTab.RemoveAll (); + m_quotaOption = QUOTA_NONE; } void BotManager::FillServer (int selection, int personality, int difficulty, int numToAdd) @@ -458,7 +505,6 @@ void BotManager::FillServer (int selection, int personality, int difficulty, int AddBot ("", difficulty, personality, selection, -1); yb_quota.SetInt (toAdd); - yb_quota_match.SetInt (0); CenterPrint ("Fill Server with %s bots...", &teamDesc[selection][0]); } From 04365ab2022892bed7f2c89699ec26f572134457 Mon Sep 17 00:00:00 2001 From: jeefo Date: Thu, 14 Jan 2016 23:32:38 +0300 Subject: [PATCH 3/3] fixed bot's don't shoot thru walls added some knife-mode movement some codestyle fixes --- include/core.h | 2 + source/basecode.cpp | 590 ++++++++++++++++++++++--------------------- source/combat.cpp | 39 +-- source/interface.cpp | 24 +- source/manager.cpp | 86 ++----- 5 files changed, 342 insertions(+), 399 deletions(-) diff --git a/include/core.h b/include/core.h index cd0ebc8..ec376d4 100644 --- a/include/core.h +++ b/include/core.h @@ -1110,6 +1110,7 @@ private: void ResetCollideState (void); void IgnoreCollisionShortly (void); void SetConditions (void); + void SetConditionsOverride (void); void UpdateEmotions (void); void SetStrafeSpeed (const Vector &moveDir, float strafeSpeed); void StartGame (void); @@ -1301,6 +1302,7 @@ public: /// the things that can be executed while skipping frames void ThinkDelayed (void); + void DisplayDebugOverlay (void); void NewRound (void); void EquipInBuyzone (int buyCount); void PushMessageQueue (int message); diff --git a/source/basecode.cpp b/source/basecode.cpp index 3782a21..3578c66 100644 --- a/source/basecode.cpp +++ b/source/basecode.cpp @@ -1786,6 +1786,42 @@ void Bot::UpdateEmotions (void) m_nextEmotionUpdate = GetWorldTime () + 1.0f; } +void Bot::SetConditionsOverride (void) +{ + if (m_currentWeapon != WEAPON_KNIFE && m_difficulty > 3 && ((m_aimFlags & AIM_ENEMY) || (m_states & (STATE_SEEING_ENEMY | STATE_SUSPECT_ENEMY)) || (GetTaskId () == TASK_SEEKCOVER && (m_isReloading || m_isVIP))) && !yb_jasonmode.GetBool () && GetTaskId () != TASK_CAMP && !IsOnLadder ()) + { + m_moveToGoal = false; // don't move to goal + m_navTimeset = GetWorldTime (); + + if (IsValidPlayer (m_enemy)) + CombatFight (); + } + + // check if we need to escape from bomb + if ((g_mapType & MAP_DE) && g_bombPlanted && m_notKilled && GetTaskId () != TASK_ESCAPEFROMBOMB && GetTaskId () != TASK_CAMP && OutOfBombTimer ()) + { + TaskComplete (); // complete current task + + // then start escape from bomb immidiate + PushTask (TASK_ESCAPEFROMBOMB, TASKPRI_ESCAPEFROMBOMB, -1, 0.0f, true); + } + + // special handling, if we have a knife in our hands + if (m_currentWeapon == WEAPON_KNIFE && IsValidPlayer (m_enemy) && (GetTaskId () != TASK_MOVETOPOSITION || GetTask ()->desire != TASKPRI_HIDE)) + { + if ((pev->origin - m_enemy->v.origin).GetLength2D () > 100.0f && (m_states & STATE_SEEING_ENEMY)) + { + int nearestToEnemyPoint = waypoints.FindNearest (m_enemy->v.origin); + + if (nearestToEnemyPoint != -1 && nearestToEnemyPoint != m_currentWaypointIndex && fabsf (waypoints.GetPath (nearestToEnemyPoint)->origin.z - m_enemy->v.origin.z) < 16.0f) + { + PushTask (TASK_MOVETOPOSITION, TASKPRI_HIDE, nearestToEnemyPoint, GetWorldTime () + Random.Float (5.0f, 10.0f), true); + m_enemy = NULL; + } + } + } +} + void Bot::SetConditions (void) { // this function carried out each frame. does all of the sensing, calculates emotions and finally sets the desired @@ -1988,7 +2024,7 @@ void Bot::ApplyTaskFilters (void) ratio = timeHeard * 0.1f; } - if (g_bombPlanted || m_isStuck) + if (g_bombPlanted || m_isStuck || m_currentWeapon == WEAPON_KNIFE) ratio /= 3.0f; // reduce the seek cover desire if bomb is planted else if (m_isVIP || m_isReloading) ratio *= 3.0f; // triple the seek cover desire if bot is VIP or reloading @@ -2194,14 +2230,12 @@ bool Bot::EnemyIsThreat (void) if (IsEntityNull (m_enemy) || GetTaskId () == TASK_SEEKCOVER) return false; - float distance = (m_enemy->v.origin - pev->origin).GetLength (); - // if bot is camping, he should be firing anyway and not leaving his position if (GetTaskId () == TASK_CAMP) return false; // if enemy is near or facing us directly - if (distance < 256.0f || IsInViewCone (m_enemy->v.origin)) + if ((m_enemy->v.origin - pev->origin).GetLength () < 256.0f || IsInViewCone (m_enemy->v.origin)) return true; return false; @@ -2241,7 +2275,7 @@ bool Bot::ReactOnEnemy (void) bool Bot::LastEnemyShootable (void) { // don't allow shooting through walls - if (!(m_aimFlags & AIM_LAST_ENEMY) || !m_lastEnemyOrigin.IsZero () || IsEntityNull (m_lastEnemy)) + if (!(m_aimFlags & AIM_LAST_ENEMY) || m_lastEnemyOrigin.IsZero () || IsEntityNull (m_lastEnemy)) return false; return GetShootingConeDeviation (GetEntity (), &m_lastEnemyOrigin) >= 0.90f && IsShootableThruObstacle (m_lastEnemyOrigin); @@ -2554,6 +2588,7 @@ void Bot::CheckRadioCommands (void) if (curDist < nearestDistance) { nearestDistance = curDist; + m_lastEnemy = enemy; m_lastEnemyOrigin = enemy->v.origin; } @@ -3049,8 +3084,11 @@ void Bot::RunTask_Normal (void) m_prevGoalIndex = -1; // spray logo sometimes if allowed to do so - if (m_timeLogoSpray < GetWorldTime () && yb_spraypaints.GetBool () && Random.Long (1, 100) < 60 && m_moveSpeed > GetWalkSpeed () && IsEntityNull (m_pickupItem)) - PushTask (TASK_SPRAY, TASKPRI_SPRAYLOGO, -1, GetWorldTime () + 1.0f, false); + if (!g_bombPlanted && m_timeLogoSpray < GetWorldTime () && yb_spraypaints.GetBool () && Random.Long (1, 100) < 60 && m_moveSpeed > GetWalkSpeed () && IsEntityNull (m_pickupItem)) + { + if (!((g_mapType & MAP_DE) && g_bombPlanted && m_team == TEAM_CF)) + PushTask (TASK_SPRAY, TASKPRI_SPRAYLOGO, -1, GetWorldTime () + 1.0f, false); + } // reached waypoint is a camp waypoint if ((m_currentPath->flags & FLAG_CAMP) && !yb_csdm_mode.GetBool () && yb_camping_allowed.GetBool ()) @@ -3108,8 +3146,8 @@ void Bot::RunTask_Normal (void) m_moveToGoal = false; m_checkTerrain = false; - m_moveSpeed = 0; - m_strafeSpeed = 0; + m_moveSpeed = 0.0f; + m_strafeSpeed = 0.0f; } } } @@ -3182,7 +3220,7 @@ void Bot::RunTask_Normal (void) // no more nodes to follow - search new ones (or we have a bomb) else if (!GoalIsValid ()) { - m_moveSpeed = pev->maxspeed; + m_moveSpeed = 0.0f; DeleteSearchNodes (); int destIndex = -1; @@ -3433,6 +3471,9 @@ void Bot::RunTask_Attack (void) DeleteSearchNodes (); } CombatFight (); + + if (m_currentWeapon == WEAPON_KNIFE && !m_lastEnemyOrigin.IsZero ()) + m_destOrigin = m_lastEnemyOrigin; } else { @@ -3729,8 +3770,8 @@ void Bot::RunTask_PlantBomb (void) else pev->button |= IN_ATTACK; - m_moveSpeed = 0; - m_strafeSpeed = 0; + m_moveSpeed = 0.0f; + m_strafeSpeed = 0.0f; } } else // done with planting @@ -4483,8 +4524,8 @@ void Bot::RunTask_PickupItem () m_moveToGoal = false; m_checkTerrain = false; - m_moveSpeed = 0; - m_strafeSpeed = 0; + m_moveSpeed = 0.0f; + m_strafeSpeed = 0.0f; PushTask (TASK_DEFUSEBOMB, TASKPRI_DEFUSEBOMB, -1, 0.0f, false); } @@ -4846,23 +4887,7 @@ void Bot::BotAI (void) m_moveAngles.ClampAngles (); m_moveAngles.x *= -1.0f; // invert for engine - if (m_difficulty > 3 && ((m_aimFlags & AIM_ENEMY) || (m_states & (STATE_SEEING_ENEMY | STATE_SUSPECT_ENEMY)) || (GetTaskId () == TASK_SEEKCOVER && (m_isReloading || m_isVIP))) && !yb_jasonmode.GetBool () && GetTaskId () != TASK_CAMP && !IsOnLadder ()) - { - m_moveToGoal = false; // don't move to goal - m_navTimeset = GetWorldTime (); - - if (IsValidPlayer (m_enemy)) - CombatFight (); - } - - // check if we need to escape from bomb - if ((g_mapType & MAP_DE) && g_bombPlanted && m_notKilled && GetTaskId () != TASK_ESCAPEFROMBOMB && GetTaskId () != TASK_CAMP && OutOfBombTimer ()) - { - TaskComplete (); // complete current task - - // then start escape from bomb immidiate - PushTask (TASK_ESCAPEFROMBOMB, TASKPRI_ESCAPEFROMBOMB, -1, 0.0f, true); - } + SetConditionsOverride (); // allowed to move to a destination position? if (m_moveToGoal) @@ -4946,257 +4971,10 @@ void Bot::BotAI (void) pev->button |= IN_MOVELEFT; } - + // display some debugging thingy to host entity if (!IsEntityNull (g_hostEntity) && yb_debug.GetInt () >= 1) - { - bool displayDebugOverlay = false; - - if (g_hostEntity->v.iuser2 == IndexOfEntity (GetEntity ())) - displayDebugOverlay = true; - - if (!displayDebugOverlay && yb_debug.GetInt () >= 2) - { - Bot *nearest = NULL; - - if (FindNearestPlayer (reinterpret_cast (&nearest), g_hostEntity, 128.0f, true, true, true, true) && nearest == this) - displayDebugOverlay = true; - } - - if (displayDebugOverlay) - { - static float timeDebugUpdate = 0.0f; - static int index, goal, taskID; - - if (!m_tasks.IsEmpty ()) - { - if (taskID != GetTaskId () || index != m_currentWaypointIndex || goal != GetTask ()->data || timeDebugUpdate < GetWorldTime ()) - { - taskID = GetTaskId (); - index = m_currentWaypointIndex; - goal = GetTask ()->data; - - char taskName [80]; - memset (taskName, 0, sizeof (taskName)); - - switch (taskID) - { - case TASK_NORMAL: - sprintf (taskName, "Normal"); - break; - - case TASK_PAUSE: - sprintf (taskName, "Pause"); - break; - - case TASK_MOVETOPOSITION: - sprintf (taskName, "MoveToPosition"); - break; - - case TASK_FOLLOWUSER: - sprintf (taskName, "FollowUser"); - break; - - case TASK_WAITFORGO: - sprintf (taskName, "WaitForGo"); - break; - - case TASK_PICKUPITEM: - sprintf (taskName, "PickupItem"); - break; - - case TASK_CAMP: - sprintf (taskName, "Camp"); - break; - - case TASK_PLANTBOMB: - sprintf (taskName, "PlantBomb"); - break; - - case TASK_DEFUSEBOMB: - sprintf (taskName, "DefuseBomb"); - break; - - case TASK_ATTACK: - sprintf (taskName, "AttackEnemy"); - break; - - case TASK_HUNTENEMY: - sprintf (taskName, "HuntEnemy"); - break; - - case TASK_SEEKCOVER: - sprintf (taskName, "SeekCover"); - break; - - case TASK_THROWHEGRENADE: - sprintf (taskName, "ThrowExpGrenade"); - break; - - case TASK_THROWFLASHBANG: - sprintf (taskName, "ThrowFlashGrenade"); - break; - - case TASK_THROWSMOKE: - sprintf (taskName, "ThrowSmokeGrenade"); - break; - - case TASK_DOUBLEJUMP: - sprintf (taskName, "PerformDoubleJump"); - break; - - case TASK_ESCAPEFROMBOMB: - sprintf (taskName, "EscapeFromBomb"); - break; - - case TASK_SHOOTBREAKABLE: - sprintf (taskName, "ShootBreakable"); - break; - - case TASK_HIDE: - sprintf (taskName, "Hide"); - break; - - case TASK_BLINDED: - sprintf (taskName, "Blinded"); - break; - - case TASK_SPRAY: - sprintf (taskName, "SprayLogo"); - break; - } - - char enemyName[80], weaponName[80], aimFlags[64], botType[32]; - - if (!IsEntityNull (m_enemy)) - strncpy (enemyName, STRING (m_enemy->v.netname), SIZEOF_CHAR (enemyName)); - else if (!IsEntityNull (m_lastEnemy)) - { - strcpy (enemyName, " (L)"); - strncat (enemyName, STRING (m_lastEnemy->v.netname), SIZEOF_CHAR (enemyName)); - } - else - strcpy (enemyName, " (null)"); - - char pickupName[80]; - memset (pickupName, 0, sizeof (pickupName)); - - if (!IsEntityNull (m_pickupItem)) - strncpy (pickupName, STRING (m_pickupItem->v.classname), SIZEOF_CHAR (pickupName)); - else - strcpy (pickupName, " (null)"); - - WeaponSelect *selectTab = &g_weaponSelect[0]; - char weaponCount = 0; - - while (m_currentWeapon != selectTab->id && weaponCount < NUM_WEAPONS) - { - selectTab++; - weaponCount++; - } - memset (aimFlags, 0, sizeof (aimFlags)); - - // set the aim flags - sprintf (aimFlags, "%s%s%s%s%s%s%s%s", - (m_aimFlags & AIM_NAVPOINT) ? " NavPoint" : "", - (m_aimFlags & AIM_CAMP) ? " CampPoint" : "", - (m_aimFlags & AIM_PREDICT_PATH) ? " PredictPath" : "", - (m_aimFlags & AIM_LAST_ENEMY) ? " LastEnemy" : "", - (m_aimFlags & AIM_ENTITY) ? " Entity" : "", - (m_aimFlags & AIM_ENEMY) ? " Enemy" : "", - (m_aimFlags & AIM_GRENADE) ? " Grenade" : "", - (m_aimFlags & AIM_OVERRIDE) ? " Override" : ""); - - // set the bot type - sprintf (botType, "%s%s%s", m_personality == PERSONALITY_RUSHER ? " Rusher" : "", - m_personality == PERSONALITY_CAREFUL ? " Careful" : "", - m_personality == PERSONALITY_NORMAL ? " Normal" : ""); - - if (weaponCount >= NUM_WEAPONS) - { - // prevent printing unknown message from known weapons - switch (m_currentWeapon) - { - case WEAPON_EXPLOSIVE: - strcpy (weaponName, "weapon_hegrenade"); - break; - - case WEAPON_FLASHBANG: - strcpy (weaponName, "weapon_flashbang"); - break; - - case WEAPON_SMOKE: - strcpy (weaponName, "weapon_smokegrenade"); - break; - - case WEAPON_C4: - strcpy (weaponName, "weapon_c4"); - break; - - default: - sprintf (weaponName, "Unknown! (%d)", m_currentWeapon); - } - } - else - strncpy (weaponName, selectTab->weaponName, SIZEOF_CHAR (weaponName)); - - char outputBuffer[512]; - memset (outputBuffer, 0, sizeof (outputBuffer)); - - sprintf (outputBuffer, "\n\n\n\n%s (H:%.1f/A:%.1f)- Task: %d=%s Desire:%.02f\nItem: %s Clip: %d Ammo: %d%s Money: %d AimFlags: %s\nSP=%.02f SSP=%.02f I=%d PG=%d G=%d T: %.02f MT: %d\nEnemy=%s Pickup=%s Type=%s\n", STRING (pev->netname), pev->health, pev->armorvalue, taskID, taskName, GetTask ()->desire, &weaponName[7], GetAmmoInClip (), GetAmmo (), m_isReloading ? " (R)" : "", m_moneyAmount, aimFlags, m_moveSpeed, m_strafeSpeed, index, m_prevGoalIndex, goal, m_navTimeset - GetWorldTime (), pev->movetype, enemyName, pickupName, botType); - - MESSAGE_BEGIN (MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, NULL, g_hostEntity); - WRITE_BYTE (TE_TEXTMESSAGE); - WRITE_BYTE (1); - WRITE_SHORT (FixedSigned16 (-1, 1 << 13)); - WRITE_SHORT (FixedSigned16 (0, 1 << 13)); - WRITE_BYTE (0); - WRITE_BYTE (m_team == TEAM_CF ? 0 : 255); - WRITE_BYTE (100); - WRITE_BYTE (m_team != TEAM_CF ? 0 : 255); - WRITE_BYTE (0); - WRITE_BYTE (255); - WRITE_BYTE (255); - WRITE_BYTE (255); - WRITE_BYTE (0); - WRITE_SHORT (FixedUnsigned16 (0, 1 << 8)); - WRITE_SHORT (FixedUnsigned16 (0, 1 << 8)); - WRITE_SHORT (FixedUnsigned16 (1.0, 1 << 8)); - WRITE_STRING (const_cast (&outputBuffer[0])); - MESSAGE_END (); - - timeDebugUpdate = GetWorldTime () + 1.0; - } - - // green = destination origin - // blue = ideal angles - // red = view angles - - DrawArrow (g_hostEntity, EyePosition (), m_destOrigin, 10, 0, 0, 255, 0, 250, 5, 1); - - MakeVectors (m_idealAngles); - DrawArrow (g_hostEntity, EyePosition (), EyePosition () + g_pGlobals->v_forward * 300.0f, 10, 0, 0, 0, 255, 250, 5, 1); - - MakeVectors (pev->v_angle); - DrawArrow (g_hostEntity, EyePosition (), EyePosition () + g_pGlobals->v_forward * 300.0f, 10, 0, 255, 0, 0, 250, 5, 1); - - // now draw line from source to destination - PathNode *node = &m_navNode[0]; - - while (node != NULL) - { - const Vector &srcPath = waypoints.GetPath (node->index)->origin; - node = node->next; - - if (node != NULL) - { - const Vector &dstPath = waypoints.GetPath (node->index)->origin; - DrawArrow (g_hostEntity, srcPath, dstPath, 15, 0, 255, 100, 55, 200, 5, 1); - } - } - } - } - } - + DisplayDebugOverlay (); + // save the previous speed (for checking if stuck) m_prevSpeed = fabsf (m_moveSpeed); m_lastDamageType = -1; // reset damage @@ -5205,6 +4983,256 @@ void Bot::BotAI (void) pev->v_angle.ClampAngles (); } +void Bot::DisplayDebugOverlay (void) +{ + bool displayDebugOverlay = false; + + if (g_hostEntity->v.iuser2 == IndexOfEntity (GetEntity ())) + displayDebugOverlay = true; + + if (!displayDebugOverlay && yb_debug.GetInt () >= 2) + { + Bot *nearest = NULL; + + if (FindNearestPlayer (reinterpret_cast (&nearest), g_hostEntity, 128.0f, true, true, true, true) && nearest == this) + displayDebugOverlay = true; + } + + if (displayDebugOverlay) + { + static float timeDebugUpdate = 0.0f; + static int index, goal, taskID; + + if (!m_tasks.IsEmpty ()) + { + if (taskID != GetTaskId () || index != m_currentWaypointIndex || goal != GetTask ()->data || timeDebugUpdate < GetWorldTime ()) + { + taskID = GetTaskId (); + index = m_currentWaypointIndex; + goal = GetTask ()->data; + + char taskName[80]; + memset (taskName, 0, sizeof (taskName)); + + switch (taskID) + { + case TASK_NORMAL: + sprintf (taskName, "Normal"); + break; + + case TASK_PAUSE: + sprintf (taskName, "Pause"); + break; + + case TASK_MOVETOPOSITION: + sprintf (taskName, "MoveToPosition"); + break; + + case TASK_FOLLOWUSER: + sprintf (taskName, "FollowUser"); + break; + + case TASK_WAITFORGO: + sprintf (taskName, "WaitForGo"); + break; + + case TASK_PICKUPITEM: + sprintf (taskName, "PickupItem"); + break; + + case TASK_CAMP: + sprintf (taskName, "Camp"); + break; + + case TASK_PLANTBOMB: + sprintf (taskName, "PlantBomb"); + break; + + case TASK_DEFUSEBOMB: + sprintf (taskName, "DefuseBomb"); + break; + + case TASK_ATTACK: + sprintf (taskName, "AttackEnemy"); + break; + + case TASK_HUNTENEMY: + sprintf (taskName, "HuntEnemy"); + break; + + case TASK_SEEKCOVER: + sprintf (taskName, "SeekCover"); + break; + + case TASK_THROWHEGRENADE: + sprintf (taskName, "ThrowExpGrenade"); + break; + + case TASK_THROWFLASHBANG: + sprintf (taskName, "ThrowFlashGrenade"); + break; + + case TASK_THROWSMOKE: + sprintf (taskName, "ThrowSmokeGrenade"); + break; + + case TASK_DOUBLEJUMP: + sprintf (taskName, "PerformDoubleJump"); + break; + + case TASK_ESCAPEFROMBOMB: + sprintf (taskName, "EscapeFromBomb"); + break; + + case TASK_SHOOTBREAKABLE: + sprintf (taskName, "ShootBreakable"); + break; + + case TASK_HIDE: + sprintf (taskName, "Hide"); + break; + + case TASK_BLINDED: + sprintf (taskName, "Blinded"); + break; + + case TASK_SPRAY: + sprintf (taskName, "SprayLogo"); + break; + } + + char enemyName[80], weaponName[80], aimFlags[64], botType[32]; + + if (!IsEntityNull (m_enemy)) + strncpy (enemyName, STRING (m_enemy->v.netname), SIZEOF_CHAR (enemyName)); + else if (!IsEntityNull (m_lastEnemy)) + { + strcpy (enemyName, " (L)"); + strncat (enemyName, STRING (m_lastEnemy->v.netname), SIZEOF_CHAR (enemyName)); + } + else + strcpy (enemyName, " (null)"); + + char pickupName[80]; + memset (pickupName, 0, sizeof (pickupName)); + + if (!IsEntityNull (m_pickupItem)) + strncpy (pickupName, STRING (m_pickupItem->v.classname), SIZEOF_CHAR (pickupName)); + else + strcpy (pickupName, " (null)"); + + WeaponSelect *selectTab = &g_weaponSelect[0]; + char weaponCount = 0; + + while (m_currentWeapon != selectTab->id && weaponCount < NUM_WEAPONS) + { + selectTab++; + weaponCount++; + } + memset (aimFlags, 0, sizeof (aimFlags)); + + // set the aim flags + sprintf (aimFlags, "%s%s%s%s%s%s%s%s", + (m_aimFlags & AIM_NAVPOINT) ? " NavPoint" : "", + (m_aimFlags & AIM_CAMP) ? " CampPoint" : "", + (m_aimFlags & AIM_PREDICT_PATH) ? " PredictPath" : "", + (m_aimFlags & AIM_LAST_ENEMY) ? " LastEnemy" : "", + (m_aimFlags & AIM_ENTITY) ? " Entity" : "", + (m_aimFlags & AIM_ENEMY) ? " Enemy" : "", + (m_aimFlags & AIM_GRENADE) ? " Grenade" : "", + (m_aimFlags & AIM_OVERRIDE) ? " Override" : ""); + + // set the bot type + sprintf (botType, "%s%s%s", m_personality == PERSONALITY_RUSHER ? " Rusher" : "", + m_personality == PERSONALITY_CAREFUL ? " Careful" : "", + m_personality == PERSONALITY_NORMAL ? " Normal" : ""); + + if (weaponCount >= NUM_WEAPONS) + { + // prevent printing unknown message from known weapons + switch (m_currentWeapon) + { + case WEAPON_EXPLOSIVE: + strcpy (weaponName, "weapon_hegrenade"); + break; + + case WEAPON_FLASHBANG: + strcpy (weaponName, "weapon_flashbang"); + break; + + case WEAPON_SMOKE: + strcpy (weaponName, "weapon_smokegrenade"); + break; + + case WEAPON_C4: + strcpy (weaponName, "weapon_c4"); + break; + + default: + sprintf (weaponName, "Unknown! (%d)", m_currentWeapon); + } + } + else + strncpy (weaponName, selectTab->weaponName, SIZEOF_CHAR (weaponName)); + + char outputBuffer[512]; + memset (outputBuffer, 0, sizeof (outputBuffer)); + + sprintf (outputBuffer, "\n\n\n\n%s (H:%.1f/A:%.1f)- Task: %d=%s Desire:%.02f\nItem: %s Clip: %d Ammo: %d%s Money: %d AimFlags: %s\nSP=%.02f SSP=%.02f I=%d PG=%d G=%d T: %.02f MT: %d\nEnemy=%s Pickup=%s Type=%s\n", STRING (pev->netname), pev->health, pev->armorvalue, taskID, taskName, GetTask ()->desire, &weaponName[7], GetAmmoInClip (), GetAmmo (), m_isReloading ? " (R)" : "", m_moneyAmount, aimFlags, m_moveSpeed, m_strafeSpeed, index, m_prevGoalIndex, goal, m_navTimeset - GetWorldTime (), pev->movetype, enemyName, pickupName, botType); + + MESSAGE_BEGIN (MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, NULL, g_hostEntity); + WRITE_BYTE (TE_TEXTMESSAGE); + WRITE_BYTE (1); + WRITE_SHORT (FixedSigned16 (-1, 1 << 13)); + WRITE_SHORT (FixedSigned16 (0, 1 << 13)); + WRITE_BYTE (0); + WRITE_BYTE (m_team == TEAM_CF ? 0 : 255); + WRITE_BYTE (100); + WRITE_BYTE (m_team != TEAM_CF ? 0 : 255); + WRITE_BYTE (0); + WRITE_BYTE (255); + WRITE_BYTE (255); + WRITE_BYTE (255); + WRITE_BYTE (0); + WRITE_SHORT (FixedUnsigned16 (0, 1 << 8)); + WRITE_SHORT (FixedUnsigned16 (0, 1 << 8)); + WRITE_SHORT (FixedUnsigned16 (1.0, 1 << 8)); + WRITE_STRING (const_cast (&outputBuffer[0])); + MESSAGE_END (); + + timeDebugUpdate = GetWorldTime () + 1.0; + } + + // green = destination origin + // blue = ideal angles + // red = view angles + + DrawArrow (g_hostEntity, EyePosition (), m_destOrigin, 10, 0, 0, 255, 0, 250, 5, 1); + + MakeVectors (m_idealAngles); + DrawArrow (g_hostEntity, EyePosition () - Vector (0.0f, 0.0f, 16.0f), EyePosition () + g_pGlobals->v_forward * 300.0f, 10, 0, 0, 0, 255, 250, 5, 1); + + MakeVectors (pev->v_angle); + DrawArrow (g_hostEntity, EyePosition () - Vector (0.0f, 0.0f, 32.0f), EyePosition () + g_pGlobals->v_forward * 300.0f, 10, 0, 255, 0, 0, 250, 5, 1); + + // now draw line from source to destination + PathNode *node = &m_navNode[0]; + + while (node != NULL) + { + const Vector &srcPath = waypoints.GetPath (node->index)->origin; + node = node->next; + + if (node != NULL) + { + const Vector &dstPath = waypoints.GetPath (node->index)->origin; + DrawArrow (g_hostEntity, srcPath, dstPath, 15, 0, 255, 100, 55, 200, 5, 1); + } + } + } + } +} + bool Bot::HasHostage (void) { for (int i = 0; i < MAX_HOSTAGES; i++) diff --git a/source/combat.cpp b/source/combat.cpp index fd0a6a2..5b54f0e 100644 --- a/source/combat.cpp +++ b/source/combat.cpp @@ -913,7 +913,7 @@ WeaponSelectEnd: { if (distance < 64.0f) { - if (Random.Long (1, 100) < 15 || HasShield ()) + if (Random.Long (1, 100) < 30 || HasShield ()) pev->button |= IN_ATTACK; // use primary attack else pev->button |= IN_ATTACK2; // use secondary attack @@ -921,8 +921,6 @@ WeaponSelectEnd: } else { - LookupEnemy (); - if (selectTab[chosenWeaponIndex].primaryFireHold && m_ammo[g_weaponDefs[selectTab[selectIndex].id].ammo1] > selectTab[selectIndex].minPrimaryAmmo) // if automatic weapon, just press attack pev->button |= IN_ATTACK; else // if not, toggle buttons @@ -993,15 +991,12 @@ bool Bot::IsWeaponBadInDistance (int weaponIndex, float distance) void Bot::FocusEnemy (void) { // aim for the head and/or body - Vector enemyOrigin = GetAimPosition (); - m_lookAt = enemyOrigin; + m_lookAt = GetAimPosition (); if (m_enemySurpriseTime > GetWorldTime ()) return; - enemyOrigin = (enemyOrigin - EyePosition ()).Get2D (); - - float distance = enemyOrigin.GetLength (); // how far away is the enemy scum? + float distance = (m_lookAt - EyePosition ()).GetLength2D (); // how far away is the enemy scum? if (distance < 128.0f) { @@ -1044,25 +1039,18 @@ void Bot::CombatFight (void) if (IsEntityNull (m_enemy)) return; - Vector enemyOrigin = m_lookAt; + float distance = (m_lookAt - EyePosition ()).GetLength2D (); // how far away is the enemy scum? - if (m_currentWeapon == WEAPON_KNIFE) - m_destOrigin = m_enemy->v.origin; - - enemyOrigin = (enemyOrigin - EyePosition ()).Get2D (); // ignore z component (up & down) - - float distance = enemyOrigin.GetLength (); // how far away is the enemy scum? - - if (m_timeWaypointMove + m_frameInterval + 0.5f < GetWorldTime ()) + if (m_timeWaypointMove < GetWorldTime ()) { int approach; + if (m_currentWeapon == WEAPON_KNIFE) // knife? + approach = 100; if ((m_states & STATE_SUSPECT_ENEMY) && !(m_states & STATE_SEEING_ENEMY)) // if suspecting enemy stand still approach = 49; else if (m_isReloading || m_isVIP) // if reloading or vip back off approach = 29; - else if (m_currentWeapon == WEAPON_KNIFE) // knife? - approach = 100; else { approach = static_cast (pev->health * m_agressionLevel); @@ -1071,17 +1059,6 @@ void Bot::CombatFight (void) approach = 49; } - if (UsesPistol() && !((m_enemy->v.weapons & WEAPON_SECONDARY) || (m_enemy->v.weapons & (1 << WEAPON_SG550))) && !g_bombPlanted) - { - m_fearLevel += 0.5f; - - CheckGrenades(); - CheckThrow (EyePosition(), m_throw); - - if ((m_states & STATE_SEEING_ENEMY) && !m_hasC4) - PushTask (TASK_SEEKCOVER, TASKPRI_SEEKCOVER, -1, Random.Long (10, 20), true); - } - // only take cover when bomb is not planted and enemy can see the bot or the bot is VIP if (approach < 30 && !g_bombPlanted && (IsInViewCone (m_enemy->v.origin) || m_isVIP)) { @@ -1108,7 +1085,7 @@ void Bot::CombatFight (void) } else if (UsesRifle () || UsesSubmachineGun ()) { - if (m_lastFightStyleCheck + 3.0 < GetWorldTime ()) + if (m_lastFightStyleCheck + 3.0f < GetWorldTime ()) { int rand = Random.Long (1, 100); diff --git a/source/interface.cpp b/source/interface.cpp index 3d3cd93..eeafebb 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -1105,31 +1105,14 @@ int ClientConnect (edict_t *ent, const char *name, const char *addr, char reject if (strcmp (addr, "loopback") == 0) g_hostEntity = ent; // save the edict of the listen server client... + bots.AdjustQuota (true, ent); + if (g_isMetamod) RETURN_META_VALUE (MRES_IGNORED, 0); return (*g_functionTable.pfnClientConnect) (ent, name, addr, rejectReason); } -void ClientPutInServer (edict_t *ent) -{ - // this function is called once a just connected client actually enters the game, after - // having downloaded and synchronized its resources with the of the server's. It's the - // perfect place to hook for client connecting, since a client can always try to connect - // passing the ClientConnect() step, and not be allowed by the server later (because of a - // latency timeout or whatever reason). We can here keep track of both bots and players - // counts on occurence, since bots connect the server just like the way normal client do, - // and their third party bot flag is already supposed to be set then. If it's a bot which - // is connecting, we also have to awake its brain(s) by reading them from the disk. - - bots.AdjustQuota (true, ent); - - if (g_isMetamod) - RETURN_META (MRES_IGNORED); - - (*g_functionTable.pfnClientPutInServer) (ent); -} - void ClientDisconnect (edict_t *ent) { // this function is called whenever a client is VOLUNTARILY disconnected from the server, @@ -2783,7 +2766,7 @@ void pfnAlertMessage (ALERT_TYPE alertType, char *format, ...) vsprintf (buffer, format, ap); va_end (ap); - if (strstr (buffer, "_Defuse_") != NULL) + if ((g_mapType & MAP_DE) && g_bombPlanted && strstr (buffer, "_Defuse_") != NULL) { // notify all terrorists that CT is starting bomb defusing for (int i = 0; i < GetMaxClients (); i++) @@ -2840,7 +2823,6 @@ export int GetEntityAPI2 (gamefuncs_t *functionTable, int *) functionTable->pfnTouch = Touch; functionTable->pfnClientConnect = ClientConnect; functionTable->pfnClientDisconnect = ClientDisconnect; - functionTable->pfnClientPutInServer = ClientPutInServer; functionTable->pfnClientUserInfoChanged = ClientUserInfoChanged; functionTable->pfnClientCommand = ClientCommand; functionTable->pfnServerActivate = ServerActivate; diff --git a/source/manager.cpp b/source/manager.cpp index 979db9a..ec756bf 100644 --- a/source/manager.cpp +++ b/source/manager.cpp @@ -311,10 +311,6 @@ void BotManager::AddBot (const String &name, int difficulty, int personality, in // put to queue m_creationTab.Push (bot); - - // keep quota number up to date - if (GetBotsNum () + 1 > yb_quota.GetInt ()) - yb_quota.SetInt (GetBotsNum () + 1); } void BotManager::AddBot (const String &name, const String &difficulty, const String &personality, const String &team, const String &member) @@ -331,12 +327,6 @@ void BotManager::AddBot (const String &name, const String &difficulty, const Str bot.personality = (personality.IsEmpty () || personality == any) ? -1 : personality.ToInt (); m_creationTab.Push (bot); - - int newBotsNum = GetBotsNum () + 1; - - // keep quota number up to date - if (newBotsNum < GetMaxClients () && newBotsNum > yb_quota.GetInt ()) - yb_quota.SetInt (newBotsNum); } void BotManager::AdjustQuota (bool isPlayerConnection, edict_t *ent) @@ -391,14 +381,6 @@ void BotManager::MaintainBotQuota (void) if (yb_join_after_player.GetInt () > 0 && !numHumans) desiredCount = 0; - if (m_quotaOption != QUOTA_NONE && numBots > 1 && desiredCount > 1) - { - if (m_quotaOption == QUOTA_INCREMENT) - desiredCount++; - else - desiredCount--; - } - // quota mode char mode = yb_quota_mode.GetString ()[0]; @@ -412,57 +394,21 @@ void BotManager::MaintainBotQuota (void) else desiredCount = min (desiredCount, GetMaxClients () - numHumans); - m_quotaOption = QUOTA_NONE; + if (m_quotaOption != QUOTA_NONE && numBots > 1 && desiredCount > 1) + { + if (m_quotaOption == QUOTA_INCREMENT) + desiredCount++; + else + desiredCount--; + + m_quotaOption = QUOTA_NONE; + } if (desiredCount > numBots) AddRandom (); else if (desiredCount < numBots) RemoveRandom (); -#if 0 - int botNumber = GetBotsNum (); - int humanNumber = GetHumansNum (); - - if (botNumber > yb_quota.GetInt ()) - RemoveRandom (); - - if (humanNumber > 0 && yb_quota_match.GetInt () > 0) - { - int num = yb_quota_match.GetInt () * humanNumber; - - if (num >= GetMaxClients () - humanNumber) - num = GetMaxClients () - humanNumber; - - if (yb_quota_match_max.GetInt () > 0 && num > yb_quota_match_max.GetInt ()) - num = yb_quota_match_max.GetInt (); - - yb_quota.SetInt (num); - yb_autovacate.SetInt (0); - } - - if (yb_autovacate.GetBool ()) - { - if (botNumber < yb_quota.GetInt () && humanNumber < GetMaxClients () - 1) - AddRandom (); - - if (humanNumber >= GetMaxClients ()) - RemoveRandom (); - } - else - { - if (botNumber < yb_quota.GetInt () && humanNumber < GetMaxClients ()) - AddRandom (); - } - - int botQuota = yb_autovacate.GetBool () ? GetMaxClients () - humanNumber : GetMaxClients (); - - // check valid range of quota - if (yb_quota.GetInt () > botQuota) - yb_quota.SetInt (botQuota); - - else if (yb_quota.GetInt () < 0) - yb_quota.SetInt (0); -#endif m_maintainTime = GetWorldTime () + 0.15f; } } @@ -922,6 +868,12 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member, c m_wantedTeam = team; m_wantedClass = member; + int newBotsNum = bots.GetBotsNum () + 1; + + // keep quota number up to date + if (newBotsNum < GetMaxClients () && newBotsNum > yb_quota.GetInt ()) + yb_quota.SetInt (newBotsNum); + NewRound (); } @@ -1220,9 +1172,11 @@ void Bot::Kick (void) ServerCommand ("kick \"%s\"", STRING (pev->netname)); CenterPrint ("Bot '%s' kicked", STRING (pev->netname)); - // balances quota - if (bots.GetBotsNum () - 1 < yb_quota.GetInt ()) - yb_quota.SetInt (bots.GetBotsNum () - 1); + int newBotsNum = bots.GetBotsNum () - 1; + + // keep quota number up to date + if (newBotsNum < GetMaxClients () && newBotsNum < yb_quota.GetInt ()) + yb_quota.SetInt (newBotsNum); } void Bot::StartGame (void)