diff --git a/include/core.h b/include/core.h index 691c412..41ef130 100644 --- a/include/core.h +++ b/include/core.h @@ -152,7 +152,8 @@ enum ClientFlags { CF_USED = (1 << 0), CF_ALIVE = (1 << 1), - CF_ADMIN = (1 << 2) + CF_ADMIN = (1 << 2), + CF_ICON = (1 << 3) }; // bot create status @@ -608,7 +609,8 @@ struct BotName struct ChatterItem { String name; - float repeatTime; + float repeat; + float duration; }; struct WeaponSelect @@ -642,7 +644,7 @@ struct Client MenuId menu; // id to opened bot menu edict_t *ent; // pointer to actual edict Vector origin; // position in the world - Vector soundPosition; // position sound was played + Vector soundPos; // position sound was played int team; // bot team int team2; // real bot team in free for all mode (csdm) @@ -651,6 +653,9 @@ struct Client float hearingDistance; // distance this sound is heared float timeSoundLasting; // time sound is played/heared + int iconFlags[MAX_ENGINE_PLAYERS]; // flag holding chatter icons + float iconTimestamp[MAX_ENGINE_PLAYERS]; // timers for chatter icons + Client (void) : menu (BOT_MENU_IVALID) { } }; diff --git a/include/engine/extdll.h b/include/engine/extdll.h index 1d83402..08e9a09 100644 --- a/include/engine/extdll.h +++ b/include/engine/extdll.h @@ -20,6 +20,7 @@ /* disable deprecation warnings concerning unsafe CRT functions */ #if !defined _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE + #define _WINSOCK_DEPRECATED_NO_WARNINGS #endif #endif diff --git a/source/basecode.cpp b/source/basecode.cpp index 3b20d0f..5c6bd08 100644 --- a/source/basecode.cpp +++ b/source/basecode.cpp @@ -967,20 +967,36 @@ void Bot::EnableChatterIcon (bool show) { // this function depending on show boolen, shows/remove chatter, icon, on the head of bot. - if ((g_gameFlags & GAME_LEGACY) || yb_communication_type.GetInt () != 2) + if (!(g_gameFlags & GAME_SUPPORT_BOT_VOICE) || yb_communication_type.GetInt () != 2) return; + auto SendBotVoiceMsg = [] (bool show, edict_t *ent, int ownId) + { + MESSAGE_BEGIN (MSG_ONE, engine.FindMessageId (NETMSG_BOTVOICE), nullptr, ent); // begin message + WRITE_BYTE (show); // switch on/off + WRITE_BYTE (ownId); + MESSAGE_END (); + + }; + + int ownId = GetIndex (); + for (int i = 0; i < engine.MaxClients (); i++) { - const Client &client = g_clients[i]; + Client &client = g_clients[i]; if (!(client.flags & CF_USED) || (client.ent->v.flags & FL_FAKECLIENT) || client.team != m_team) continue; - MESSAGE_BEGIN (MSG_ONE, engine.FindMessageId (NETMSG_BOTVOICE), nullptr, g_clients[i].ent); // begin message - WRITE_BYTE (show); // switch on/off - WRITE_BYTE (GetIndex ()); - MESSAGE_END (); + if (!show && (client.iconFlags[ownId] & CF_ICON) && client.iconTimestamp[ownId] < engine.Time ()) + { + SendBotVoiceMsg (false, client.ent, ownId); + + client.iconTimestamp[ownId] = 0.0f; + client.iconFlags[ownId] &= ~CF_ICON; + } + else if (show && !(client.iconFlags[ownId] & CF_ICON)) + SendBotVoiceMsg (true, client.ent, ownId); } } @@ -988,13 +1004,13 @@ void Bot::InstantChatterMessage (int type) { // this function sends instant chatter messages. - if ((g_gameFlags & GAME_LEGACY) || yb_communication_type.GetInt () != 2 || g_chatterFactory[type].IsEmpty ()) + if (!(g_gameFlags & GAME_SUPPORT_BOT_VOICE) || yb_communication_type.GetInt () != 2 || g_chatterFactory[type].IsEmpty ()) return; if (m_notKilled) EnableChatterIcon (true); - // delay only reportteam + // delay only report team if (type == Radio_ReportTeam) { if (m_timeRepotingInDelay < engine.Time ()) @@ -1002,13 +1018,14 @@ void Bot::InstantChatterMessage (int type) m_timeRepotingInDelay = engine.Time () + Random.Float (30.0f, 60.0f); } + auto playbackSound = g_chatterFactory[type].GetRandomElement (); - const String &defaultSound = g_chatterFactory[type].GetRandomElement ().name; + const String &defaultSound = playbackSound.name; const String &painSound = g_chatterFactory[Chatter_DiePain].GetRandomElement ().name; for (int i = 0; i < engine.MaxClients (); i++) { - const Client &client = g_clients[i]; + Client &client = g_clients[i]; if (!(client.flags & CF_USED) || (client.ent->v.flags & FL_FAKECLIENT) || client.team != m_team) continue; @@ -1023,6 +1040,9 @@ void Bot::InstantChatterMessage (int type) WRITE_SHORT (m_voicePitch); MESSAGE_END (); + + client.iconTimestamp[GetIndex ()] = engine.Time () + playbackSound.duration; + client.iconFlags[GetIndex ()] |= CF_ICON; } } @@ -1033,7 +1053,7 @@ void Bot::RadioMessage (int message) if (yb_communication_type.GetInt () == 0 || m_numFriendsLeft == 0) return; - if ((g_gameFlags & GAME_LEGACY) || g_chatterFactory[message].IsEmpty () || yb_communication_type.GetInt () != 2) + if (!(g_gameFlags & GAME_SUPPORT_BOT_VOICE) || g_chatterFactory[message].IsEmpty () || yb_communication_type.GetInt () != 2) m_forceRadio = true; // use radio instead voice else m_forceRadio = false; @@ -1046,7 +1066,7 @@ void Bot::ChatterMessage (int message) { // this function inserts the voice message into the message queue (mostly same as above) - if ((g_gameFlags & GAME_LEGACY) || yb_communication_type.GetInt () != 2 || g_chatterFactory[message].IsEmpty () || m_numFriendsLeft == 0) + if (!(g_gameFlags & GAME_SUPPORT_BOT_VOICE) || yb_communication_type.GetInt () != 2 || g_chatterFactory[message].IsEmpty () || m_numFriendsLeft == 0) return; bool shouldExecute = false; @@ -1054,7 +1074,7 @@ void Bot::ChatterMessage (int message) if (m_chatterTimes[message] < engine.Time () || m_chatterTimes[message] == 99999.0f) { if (m_chatterTimes[message] != 99999.0f) - m_chatterTimes[message] = engine.Time () + g_chatterFactory[message][0].repeatTime; + m_chatterTimes[message] = engine.Time () + g_chatterFactory[message][0].repeat; shouldExecute = true; } @@ -1247,7 +1267,7 @@ void Bot::CheckMessageQueue (void) } } - if ((m_radioSelect != Radio_ReportingIn && m_forceRadio) || yb_communication_type.GetInt () != 2 || g_chatterFactory[m_radioSelect].IsEmpty () || (g_gameFlags & GAME_LEGACY)) + if ((m_radioSelect != Radio_ReportingIn && m_forceRadio) || yb_communication_type.GetInt () != 2 || g_chatterFactory[m_radioSelect].IsEmpty () || !(g_gameFlags & GAME_SUPPORT_BOT_VOICE)) { if (m_radioSelect < Radio_GoGoGo) engine.IssueBotCommand (GetEntity (), "radio1"); @@ -2920,10 +2940,6 @@ void Bot::ThinkFrame (void) CheckMessageQueue (); // check for pending messages - // remove voice icon - if (!(g_gameFlags & GAME_LEGACY) && g_lastRadioTime[g_clients[GetIndex () - 1].team2] + Random.Float (0.8f, 2.1f) < engine.Time ()) - EnableChatterIcon (false); // hide icon - if (botMovement) BotAI (); // execute main code @@ -2980,6 +2996,9 @@ void Bot::PeriodicThink (void) } } + if (g_gameFlags & GAME_SUPPORT_BOT_VOICE) + EnableChatterIcon (false); // end voice feedback + // clear enemy far away if (!m_lastEnemyOrigin.IsZero () && !engine.IsNullEntity (m_lastEnemy) && (pev->origin - m_lastEnemyOrigin).GetLength () >= 1600.0f) { @@ -5871,7 +5890,7 @@ void Bot::ReactOnSound (void) if (!(client.flags & CF_USED) || !(client.flags & CF_ALIVE) || client.ent == GetEntity () || client.team == m_team || client.timeSoundLasting < engine.Time ()) continue; - float distance = (client.soundPosition - pev->origin).GetLength (); + float distance = (client.soundPos - pev->origin).GetLength (); if (distance > client.hearingDistance) continue; diff --git a/source/engine.cpp b/source/engine.cpp index de07455..b0bf264 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -207,7 +207,7 @@ float Engine::GetWaveLength (const char *fileName) return 0.0f; // check if we have engine function for this - if (g_engfuncs.pfnGetApproxWavePlayLen != nullptr) + if (!(g_gameFlags & GAME_XASH_ENGINE) && g_engfuncs.pfnGetApproxWavePlayLen != nullptr) { fp.Close (); return g_engfuncs.pfnGetApproxWavePlayLen (filePath) / 1000.0f; @@ -545,7 +545,7 @@ char *Engine::TraslateMessage (const char *input) if (IsDedicatedServer ()) return const_cast (&input[0]); - static char string[MAX_PRINT_BUFFER]; + static char string[MAX_PRINT_BUFFER] = { 0, }; const char *ptr = input + strlen (input) - 1; while (ptr > input && *ptr == '\n') diff --git a/source/interface.cpp b/source/interface.cpp index 23a9434..30eddaf 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -468,11 +468,14 @@ void ParseVoiceEvent (const String &base, int type, float timeToRepeat) { temp[i].Trim ().TrimQuotes (); - if (engine.GetWaveLength (temp[i]) <= 0.0f) + float duration = engine.GetWaveLength (temp[i]); + + if (duration <= 0.0f) continue; chatterItem.name = temp[i]; - chatterItem.repeatTime = timeToRepeat; + chatterItem.repeat = timeToRepeat; + chatterItem.duration = duration; g_chatterFactory[type].Push (chatterItem); } @@ -727,7 +730,7 @@ void InitConfig (void) } // CHATTER SYSTEM INITIALIZATION - if (OpenConfig ("chatter.cfg", "Couldn't open chatter system configuration", &fp) && !(g_gameFlags & GAME_LEGACY) && yb_communication_type.GetInt () == 2) + if ((g_gameFlags & GAME_SUPPORT_BOT_VOICE) && yb_communication_type.GetInt () == 2 && OpenConfig ("chatter.cfg", "Couldn't open chatter system configuration", &fp)) { Array array; @@ -744,7 +747,7 @@ void InitConfig (void) array = String (&line[6]).Split ('='); if (array.GetElementNumber () != 2) - AddLogEntry (true, LL_FATAL, "Error in chatter config file syntax... Please correct all Errors."); + AddLogEntry (true, LL_ERROR, "Error in chatter config file syntax... Please correct all Errors."); FOR_EACH_AE (array, i) array[i].Trim ().Trim (); // double trim @@ -1069,7 +1072,7 @@ void UpdateClientData (const struct edict_s *ent, int sendweapons, struct client { extern ConVar yb_latency_display; - if (!(g_gameFlags & GAME_LEGACY) && yb_latency_display.GetInt () == 2) + if ((g_gameFlags & GAME_SUPPORT_SVC_PINGS) && yb_latency_display.GetInt () == 2) bots.SendPingDataOffsets (const_cast (ent)); if (g_gameFlags & GAME_METAMOD) @@ -2414,7 +2417,7 @@ void pfnMessageBegin (int msgDest, int msgType, const float *origin, edict_t *ed engine.AssignMessageId (NETMSG_SENDAUDIO, GET_USER_MSG_ID (PLID, "SendAudio", nullptr)); engine.AssignMessageId (NETMSG_SAYTEXT, GET_USER_MSG_ID (PLID, "SayText", nullptr)); - if (!(g_gameFlags & GAME_LEGACY)) + if (g_gameFlags & GAME_SUPPORT_BOT_VOICE) engine.AssignMessageId (NETMSG_BOTVOICE, GET_USER_MSG_ID (PLID, "BotVoice", nullptr)); } engine.ResetMessageCapture (); @@ -3025,12 +3028,17 @@ Library *LoadCSBinary (void) AddLogEntry (true, LL_FATAL | LL_IGNORE, "Unable to load gamedll \"%s\". Exiting... (gamedir: %s)", libs[i], modname); return nullptr; } + // detect if we're running modern game + Entity_FN entity = game->GetFuncAddr ("weapon_famas"); // detect xash engine if (g_engfuncs.pfnCVarGetPointer ("build") != nullptr) { g_gameFlags |= (GAME_LEGACY | GAME_XASH_ENGINE); + if (entity != nullptr) + g_gameFlags |= GAME_SUPPORT_BOT_VOICE; + if (g_gameFlags & GAME_METAMOD) { delete game; @@ -3039,11 +3047,8 @@ Library *LoadCSBinary (void) return game; } - // detect if we're running modern game - Entity_FN entity = game->GetFuncAddr ("weapon_famas"); - if (entity != nullptr) - g_gameFlags |= GAME_CSTRIKE16; + g_gameFlags |= (GAME_CSTRIKE16 | GAME_SUPPORT_BOT_VOICE | GAME_SUPPORT_SVC_PINGS); else g_gameFlags |= GAME_LEGACY; @@ -3088,7 +3093,7 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t } #ifdef PLATFORM_ANDROID - g_gameFlags |= (GAME_LEGACY | GAME_XASH_ENGINE | GAME_MOBILITY); + g_gameFlags |= (GAME_LEGACY | GAME_XASH_ENGINE | GAME_MOBILITY | GAME_SUPPORT_BOT_VOICE); if (g_gameFlags & GAME_METAMOD) return; // we should stop the attempt for loading the real gamedll, since metamod handle this for us @@ -3136,6 +3141,13 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t gameVersionStr.Replace ("Legacy", "1.6 Limited"); } + + if (g_gameFlags & GAME_SUPPORT_BOT_VOICE) + gameVersionStr.Append (" (BV)"); + + if (g_gameFlags & GAME_SUPPORT_SVC_PINGS) + gameVersionStr.Append (" (SVC)"); + engine.Printf ("YaPB Bot has detect game version as Counter-Strike: %s", gameVersionStr.GetBuffer ()); if (g_gameFlags & GAME_METAMOD) diff --git a/source/manager.cpp b/source/manager.cpp index ef816fb..0228bb9 100644 --- a/source/manager.cpp +++ b/source/manager.cpp @@ -1330,7 +1330,7 @@ void Bot::StartGame (void) void BotManager::CalculatePingOffsets (void) { - if ((g_gameFlags & GAME_LEGACY) || yb_latency_display.GetInt () != 2) + if (!(g_gameFlags & GAME_SUPPORT_SVC_PINGS) || yb_latency_display.GetInt () != 2) return; int averagePing = 0; @@ -1391,7 +1391,7 @@ void BotManager::CalculatePingOffsets (void) void BotManager::SendPingDataOffsets (edict_t *to) { - if ((g_gameFlags & GAME_LEGACY) || yb_latency_display.GetInt () != 2 || engine.IsNullEntity (to) || (to->v.flags & FL_FAKECLIENT)) + if (!(g_gameFlags & GAME_SUPPORT_SVC_PINGS) || yb_latency_display.GetInt () != 2 || engine.IsNullEntity (to) || (to->v.flags & FL_FAKECLIENT)) return; if (!(to->v.flags & FL_CLIENT) && !(((to->v.button & IN_SCORE) || !(to->v.oldbuttons & IN_SCORE)))) diff --git a/source/support.cpp b/source/support.cpp index 0d2402b..9939e21 100644 --- a/source/support.cpp +++ b/source/support.cpp @@ -115,8 +115,11 @@ void DisplayMenuToClient (edict_t *ent, MenuId menu) parsed->text.Assign (engine.TraslateMessage (parsed->text.GetBuffer ())); // make menu looks best - for (int j = 0; j < 10; j++) - parsed->text.Replace (FormatBuffer ("%d.", j), FormatBuffer ("\\r%d.\\w", j)); + if (!(g_gameFlags & GAME_LEGACY)) + { + for (int j = 0; j < 10; j++) + parsed->text.Replace (FormatBuffer ("%d.", j), FormatBuffer ("\\r%d.\\w", j)); + } } s_menusParsed = true; } @@ -149,6 +152,13 @@ void DisplayMenuToClient (edict_t *ent, MenuId menu) break; } } + + // worst case + if (!menuPtr) + { + client.menu = BOT_MENU_IVALID; + return; + } const char *displayText = ((g_gameFlags & (GAME_XASH_ENGINE | GAME_MOBILITY)) && !yb_display_menu_text.GetBool ()) ? " " : menuPtr->text.GetBuffer (); while (strlen (displayText) >= 64) @@ -755,49 +765,49 @@ void SoundAttachToClients (edict_t *ent, const char *sample, float volume) // hit/fall sound? client.hearingDistance = 768.0f * volume; client.timeSoundLasting = engine.Time () + 0.5f; - client.soundPosition = origin; + client.soundPos = origin; } else if (strncmp ("items/gunpickup", sample, 15) == 0) { // weapon pickup? client.hearingDistance = 768.0f * volume; client.timeSoundLasting = engine.Time () + 0.5f; - client.soundPosition = origin; + client.soundPos = origin; } else if (strncmp ("weapons/zoom", sample, 12) == 0) { // sniper zooming? client.hearingDistance = 512.0f * volume; client.timeSoundLasting = engine.Time () + 0.1f; - client.soundPosition = origin; + client.soundPos = origin; } else if (strncmp ("items/9mmclip", sample, 13) == 0) { // ammo pickup? client.hearingDistance = 512.0f * volume; client.timeSoundLasting = engine.Time () + 0.1f; - client.soundPosition = origin; + client.soundPos = origin; } else if (strncmp ("hostage/hos", sample, 11) == 0) { // CT used hostage? client.hearingDistance = 1024.0f * volume; client.timeSoundLasting = engine.Time () + 5.0f; - client.soundPosition = origin; + client.soundPos = origin; } else if (strncmp ("debris/bustmetal", sample, 16) == 0 || strncmp ("debris/bustglass", sample, 16) == 0) { // broke something? client.hearingDistance = 1024.0f * volume; client.timeSoundLasting = engine.Time () + 2.0f; - client.soundPosition = origin; + client.soundPos = origin; } else if (strncmp ("doors/doormove", sample, 14) == 0) { // someone opened a door client.hearingDistance = 1024.0f * volume; client.timeSoundLasting = engine.Time () + 3.0f; - client.soundPosition = origin; + client.soundPos = origin; } } @@ -860,7 +870,7 @@ void SoundSimulateUpdate (int playerIndex) // override it with new client.hearingDistance = hearDistance; client.timeSoundLasting = timeSound; - client.soundPosition = client.ent->v.origin; + client.soundPos = client.ent->v.origin; } } else @@ -868,7 +878,7 @@ void SoundSimulateUpdate (int playerIndex) // just remember it client.hearingDistance = hearDistance; client.timeSoundLasting = timeSound; - client.soundPosition = client.ent->v.origin; + client.soundPos = client.ent->v.origin; } }