Files
sm-plugins/Radio/scripting/radio/grenade.sp
T
2026-10-22 16:17:56 +01:00

133 lines
4.3 KiB
SourcePawn

//----------------------------------------------------------------------------------------------------
// 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);
}