//---------------------------------------------------------------------------------------------------- // Grenade announce: throwing a grenade makes the game itself emit "Fire in the hole!" via the // RadioText usermessage (it is not a client command), so intercept it and re-send the line // styled a frame later. The game's SendAudio (Radio.FireInTheHole) is likewise intercepted and // re-emitted through EmitSoundToClient so each listener's radio volume preference applies. //---------------------------------------------------------------------------------------------------- #define FIRE_IN_THE_HOLE_TOKEN "#Cstrike_TitlesTXT_Fire_in_the_hole" void Grenade_Init() { UserMsg RadioText = GetUserMessageId("RadioText"); if (RadioText == INVALID_MESSAGE_ID) SetFailState("RadioText usermessage unavailable."); HookUserMessage(RadioText, Hook_RadioText, true); HookUserMessage(GetUserMessageId("SendAudio"), Hook_SendAudio, true); } public Action Hook_SendAudio(UserMsg msg_id, Handle bf, const int[] players, int playersNum, bool reliable, bool init) { if (!g_cvEnabled.BoolValue) return Plugin_Continue; char sound[32]; BfReadString(bf, sound, sizeof(sound), false); // Grenade announces are the only radio SendAudio the engine still emits (the command // listeners block the rest); round events (bomb/win jingles) pass through untouched. if (!StrEqual(sound, "Radio.FireInTheHole")) return Plugin_Continue; // Sounds cannot be emitted from inside a usermessage hook either, so re-emit next frame. DataPack pack = new DataPack(); pack.WriteCell(playersNum); for (int i = 0; i < playersNum; i++) { int target = players[i]; pack.WriteCell((target >= 1 && target <= MaxClients && IsClientInGame(target)) ? GetClientUserId(target) : 0); } RequestFrame(OnFireInTheHoleResend, pack); return Plugin_Handled; } public void OnFireInTheHoleResend(DataPack pack) { pack.Reset(); int num = pack.ReadCell(); int[] players = new int[MaxClients]; int playersNum = 0; for (int i = 0; i < num; i++) { int target = GetClientOfUserId(pack.ReadCell()); if (target && !IsFakeClient(target)) players[playersNum++] = target; } delete pack; Radio_EmitToPlayers(players, playersNum, SOUND_FIREINTHEHOLE); } public Action Hook_RadioText(UserMsg msg_id, Handle bf, const int[] players, int playersNum, bool reliable, bool init) { if (!g_cvEnabled.BoolValue) return Plugin_Continue; BfReadByte(bf); // msg_dest int client = BfReadByte(bf); if (client < 1 || client > MaxClients || !IsClientInGame(client)) return Plugin_Continue; // Layout: msg_name, then up to four params. "#Game_radio" carries the phrase token in // param2, "#Game_radio_location" in param3 (param2 is the nav place name). char msgName[64], param[64], token[64]; BfReadString(bf, msgName, sizeof(msgName), false); // msg_name BfReadString(bf, param, sizeof(param), false); // param1 = player name BfReadString(bf, token, sizeof(token), false); // param2 BfReadString(bf, param, sizeof(param), false); // param3 if (StrEqual(msgName, "#Game_radio_location")) strcopy(token, sizeof(token), param); else if (!StrEqual(msgName, "#Game_radio")) return Plugin_Continue; if (!StrEqual(token, FIRE_IN_THE_HOLE_TOKEN)) return Plugin_Continue; if (Bans_IsBanned(client)) return Plugin_Handled; // Usermessages cannot be sent from inside a usermessage hook, so stash the data and // recipients (as userids) and re-send next frame. DataPack pack = new DataPack(); pack.WriteCell(GetClientUserId(client)); pack.WriteCell(playersNum); for (int i = 0; i < playersNum; i++) { int target = players[i]; pack.WriteCell((target >= 1 && target <= MaxClients && IsClientInGame(target)) ? GetClientUserId(target) : 0); } RequestFrame(OnGrenadeResend, pack); return Plugin_Handled; } public void OnGrenadeResend(DataPack pack) { pack.Reset(); int client = GetClientOfUserId(pack.ReadCell()); int num = pack.ReadCell(); int[] players = new int[MaxClients]; int playersNum = 0; for (int i = 0; i < num; i++) { int target = GetClientOfUserId(pack.ReadCell()); if (target && !IsFakeClient(target)) players[playersNum++] = target; } delete pack; if (!client || !IsClientInGame(client) || !playersNum) return; char text[256]; Format_RadioLine(client, Radio_IsLeader(client), "Fire in the hole!", text, sizeof(text)); Radio_SendChat(client, players, playersNum, text); }