lots of changes

This commit is contained in:
2026-10-22 16:17:56 +01:00
parent e4a75367aa
commit ac3ffd5be2
53 changed files with 7716 additions and 193 deletions
+234
View File
@@ -0,0 +1,234 @@
//----------------------------------------------------------------------------------------------------
// Radio commands: takes over the stock CS:S radio commands (the listener blocks the game's
// handling) and re-emits the voice line plus a custom-chatcolors styled chat line to the team.
//----------------------------------------------------------------------------------------------------
static const char g_sRadioCommands[][] = {
"coverme", "takepoint", "holdpos", "regroup", "followme", "takingfire", "go",
"fallback", "sticktog", "getinpos", "stormfront", "report", "roger", "enemyspot",
"needbackup", "sectorclear", "inposition", "reportingin", "getout", "negative", "enemydown",
"thanks", "cheer"
};
// Everything from this index on is a custom addition, not a stock radio command
// (gated behind sm_radio_custom).
#define RADIO_FIRST_CUSTOM (sizeof(g_sRadioCommands) - 2)
static const char g_sRadioSounds[][] = {
"radio/ct_coverme.wav", "radio/takepoint.wav", "radio/position.wav", "radio/regroup.wav",
"radio/followme.wav", "radio/fireassis.wav", "radio/com_go.wav", "radio/fallback.wav",
"radio/sticktog.wav", "radio/com_getinpos.wav", "radio/stormfront.wav", "radio/com_reportin.wav",
"radio/roger.wav", "radio/ct_enemys.wav", "radio/ct_backup.wav", "radio/clear.wav",
"radio/ct_inpos.wav", "radio/ct_reportingin.wav", "radio/blow.wav", "radio/negative.wav",
"radio/enemydown.wav",
"", "" // thanks/cheer have no stock radio sound; a random bot-chatter wav is picked below
};
#define SOUND_AFFIRMATIVE "radio/ct_affirm.wav"
#define SOUND_FIREINTHEHOLE "radio/ct_fireinhole.wav"
static const char g_sThanksSounds[][] = {
"bot/nice.wav", "bot/nice2.wav", "bot/good_one.wav", "bot/good_one2.wav",
"bot/very_nice.wav", "bot/well_done.wav"
};
static const char g_sCheerSounds[][] = {
"bot/whoo.wav", "bot/whoo2.wav", "bot/yesss.wav", "bot/yesss2.wav",
"bot/yea_baby.wav", "bot/oh_yea.wav", "bot/oh_yea2.wav"
};
// The bot chatter wavs are mastered 6-10 dB hotter than the radio wavs (radio averages
// -16.6 LUFS), so each one carries a gain that brings it down to the radio loudness.
static const float g_flThanksScales[] = {
0.61, 0.44, 0.45, 0.63,
0.43, 0.42
};
static const float g_flCheerScales[] = {
0.33, 0.27, 0.25, 0.32,
0.31, 0.32, 0.39
};
static const char g_sRadioPhrases[][] = {
"Cover Me!", "You take the point.", "Hold This position.", "Regroup Team.",
"Follow Me.", "Taking fire...need assistance!", "Go go go!", "Team, fall back!",
"Stick together, team.", "Get in position and wait for my go.", "Storm the Front!",
"Report in, team.", "Roger that.", "Enemy spotted.", "Need backup.", "Sector clear.",
"I'm in position.", "Reporting in.", "Get out of there, it's gonna blow!",
"Negative.", "Enemy down.",
"Thanks!", "Cheered!!!"
};
static const char g_sCheerColors[][] = {
"FF0000", "FF4500", "FF8C00", "FFD700", "ADFF2F",
"00FF00", "00BFFF", "1E90FF", "0000CD", "9400D3"
};
static const char g_sCheerText[] = "Cheered!!!";
static int g_iCheerOffset;
static void Commands_BuildCheerPhrase(char[] phrase, int maxlen)
{
phrase[0] = '\0';
for (int i = 0; i < sizeof(g_sCheerText) - 1; i++)
{
Format(phrase, maxlen, "%s\x07%s%c", phrase,
g_sCheerColors[(i + g_iCheerOffset) % sizeof(g_sCheerColors)], g_sCheerText[i]);
}
g_iCheerOffset = (g_iCheerOffset + 1) % sizeof(g_sCheerColors);
}
static StringMap g_RadioIndex;
void Commands_PrecacheSounds()
{
for (int i = 0; i < sizeof(g_sRadioSounds); i++)
{
if (g_sRadioSounds[i][0])
PrecacheSound(g_sRadioSounds[i]);
}
PrecacheSound(SOUND_AFFIRMATIVE);
PrecacheSound(SOUND_FIREINTHEHOLE); // grenade.sp
for (int i = 0; i < sizeof(g_sThanksSounds); i++)
PrecacheSound(g_sThanksSounds[i]);
for (int i = 0; i < sizeof(g_sCheerSounds); i++)
PrecacheSound(g_sCheerSounds[i]);
}
void Radio_EmitToPlayers(const int[] players, int playersNum, const char[] sound, float scale = 1.0)
{
for (int i = 0; i < playersNum; i++)
{
float volume = Settings_GetVolume(players[i]);
if (volume <= 0.0)
continue;
EmitSoundToClient(players[i], sound, SOUND_FROM_PLAYER, SNDCHAN_VOICE,
SNDLEVEL_NORMAL, SND_NOFLAGS, volume * scale);
}
}
void Commands_Init()
{
g_RadioIndex = new StringMap();
for (int i = 0; i < sizeof(g_sRadioCommands); i++)
{
g_RadioIndex.SetValue(g_sRadioCommands[i], i);
AddCommandListener(Command_Radio, g_sRadioCommands[i]);
}
}
public Action Command_Radio(int client, const char[] command, int argc)
{
if (!g_cvEnabled.BoolValue)
return Plugin_Continue;
if (client < 1 || client > MaxClients || !IsClientInGame(client))
return Plugin_Continue;
// Console commands are case-insensitive, StringMap keys are not.
char cmd[16];
strcopy(cmd, sizeof(cmd), command);
for (int i = 0; cmd[i]; i++)
cmd[i] = CharToLower(cmd[i]);
int index;
if (!g_RadioIndex.GetValue(cmd, index))
return Plugin_Continue;
// With the custom commands disabled they fall through as unknown commands.
if (index >= RADIO_FIRST_CUSTOM && !g_cvCustom.BoolValue)
return Plugin_Continue;
if (Bans_IsBanned(client))
return Plugin_Handled;
int team = GetClientTeam(client);
if (team != CS_TEAM_T && team != CS_TEAM_CT)
return Plugin_Handled;
if (!IsPlayerAlive(client) && !g_cvDead.BoolValue)
return Plugin_Handled;
bool bLeader = Radio_IsLeader(client);
float flNow = GetGameTime();
bool bPlaySound = g_cvSound.BoolValue;
if (!bLeader)
{
if (flNow < g_flNextRadio[client])
return Plugin_Handled;
int limit = g_cvRoundLimit.IntValue;
if (limit > 0 && g_iRadioCount[client] >= limit)
return Plugin_Handled;
g_flNextRadio[client] = flNow + g_cvCooldown.FloatValue;
}
else if (flNow < g_flNextRadio[client])
{
// Leaders may spam the chat line, but the voice line still honours the cooldown.
bPlaySound = false;
}
else
{
g_flNextRadio[client] = flNow + g_cvCooldown.FloatValue;
}
g_iRadioCount[client]++;
bool bCustom = (index >= RADIO_FIRST_CUSTOM);
int[] players = new int[MaxClients];
int playersNum = 0;
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i) || IsFakeClient(i) || GetClientTeam(i) != team)
continue;
// Players may opt out of the custom commands in !settings.
if (bCustom && !Settings_GetCustom(i))
continue;
players[playersNum++] = i;
}
if (!playersNum)
return Plugin_Handled;
// phrase must hold the coloured cheer line (10 glyphs each prefixed by a 7-byte \x07RRGGBB code)
char sound[32], phrase[128];
float soundScale = 1.0;
strcopy(sound, sizeof(sound), g_sRadioSounds[index]);
strcopy(phrase, sizeof(phrase), g_sRadioPhrases[index]);
// Stock "roger" picks one of two acknowledgements at random.
if (StrEqual(cmd, "roger") && GetRandomInt(0, 1))
{
strcopy(sound, sizeof(sound), SOUND_AFFIRMATIVE);
strcopy(phrase, sizeof(phrase), "Affirmative.");
}
else if (StrEqual(cmd, "thanks"))
{
int pick = GetRandomInt(0, sizeof(g_sThanksSounds) - 1);
strcopy(sound, sizeof(sound), g_sThanksSounds[pick]);
soundScale = g_flThanksScales[pick];
}
else if (StrEqual(cmd, "cheer"))
{
int pick = GetRandomInt(0, sizeof(g_sCheerSounds) - 1);
strcopy(sound, sizeof(sound), g_sCheerSounds[pick]);
soundScale = g_flCheerScales[pick];
Commands_BuildCheerPhrase(phrase, sizeof(phrase));
}
if (bPlaySound && sound[0])
Radio_EmitToPlayers(players, playersNum, sound, soundScale);
char text[256];
Format_RadioLine(client, bLeader, phrase, text, sizeof(text));
Radio_SendChat(client, players, playersNum, text);
return Plugin_Handled;
}