diff --git a/core/ChatTriggers.cpp b/core/ChatTriggers.cpp index 4f1db6d89..c95dc730c 100644 --- a/core/ChatTriggers.cpp +++ b/core/ChatTriggers.cpp @@ -66,6 +66,10 @@ ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false), m_PubTriggerSize = 1; m_PrivTriggerSize = 1; m_bIsChatTrigger = false; + m_bPluginIgnored = false; +#if SOURCE_ENGINE == SE_EPISODEONE + m_bIsINS = false; +#endif } ChatTriggers::~ChatTriggers() @@ -109,6 +113,8 @@ void ChatTriggers::OnSourceModAllInitialized() { m_pShouldFloodBlock = g_Forwards.CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell); m_pDidFloodBlock = g_Forwards.CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell); + m_pOnClientSayCmd = g_Forwards.CreateForward("OnClientSayCommand", ET_Event, 3, NULL, Param_Cell, Param_String, Param_String); + m_pOnClientSayCmd_Post = g_Forwards.CreateForward("OnClientSayCommand_Post", ET_Ignore, 3, NULL, Param_Cell, Param_String, Param_String); } void ChatTriggers::OnSourceModAllInitialized_Post() @@ -131,23 +137,62 @@ void ChatTriggers::OnSourceModGameInitialized() SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false); SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true); } + +#if SOURCE_ENGINE == SE_EPISODEONE + m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0); + + if (m_bIsINS) + { + m_pSay2Cmd = FindCommand("say2"); + if (m_pSay2Cmd) + { + SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false); + SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true); + } + } +#elif SOURCE_ENGINE == SE_NUCLEARDAWN + m_pSaySquadCmd = FindCommand("say_squad"); + + if (m_pSaySquadCmd) + { + SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false); + SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true); + } +#endif } void ChatTriggers::OnSourceModShutdown() { - if (m_pSayTeamCmd) - { - SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true); - SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false); - } if (m_pSayCmd) { SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true); SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false); } + if (m_pSayTeamCmd) + { + SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true); + SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false); + } + +#if SOURCE_ENGINE == SE_EPISODEONE + if (m_bIsINS && m_pSay2Cmd) + { + SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false); + SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true); + } +#elif SOURCE_ENGINE == SE_NUCLEARDAWN + if (m_pSaySquadCmd) + { + SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false); + SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true); + } +#endif + g_Forwards.ReleaseForward(m_pShouldFloodBlock); g_Forwards.ReleaseForward(m_pDidFloodBlock); + g_Forwards.ReleaseForward(m_pOnClientSayCmd); + g_Forwards.ReleaseForward(m_pOnClientSayCmd_Post); } #if SOURCE_ENGINE >= SE_ORANGEBOX @@ -158,21 +203,21 @@ void ChatTriggers::OnSayCommand_Pre() { CCommand command; #endif - int client; - CPlayer *pPlayer; - - client = g_ConCmds.GetCommandClient(); + int client = g_ConCmds.GetCommandClient(); m_bIsChatTrigger = false; m_bWasFloodedMessage = false; + m_bPluginIgnored = false; /* The server console cannot do this */ - if (client == 0 || (pPlayer = g_Players.GetPlayerByIndex(client)) == NULL) + if (client == 0) { RETURN_META(MRES_IGNORED); } + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + /* We guarantee the client is connected */ - if (!pPlayer->IsConnected()) + if (!pPlayer || !pPlayer->IsConnected()) { RETURN_META(MRES_IGNORED); } @@ -211,6 +256,14 @@ void ChatTriggers::OnSayCommand_Pre() is_quoted = true; } + const char * pCommandName = command.Arg(0); +#if SOURCE_ENGINE == SE_EPISODEONE + if (m_bIsINS && strcmp(pCommandName, "say2") == 0 && strlen(args) >= 4) + { + args += 4; + } +#endif + bool is_trigger = false; bool is_silent = false; @@ -227,38 +280,37 @@ void ChatTriggers::OnSayCommand_Pre() args = &args[m_PrivTriggerSize]; } - if (!is_trigger) - { - RETURN_META(MRES_IGNORED); - } - /** * Test if this is actually a command! */ - if (!PreProcessTrigger(PEntityOfEntIndex(client), args, is_quoted)) + if (is_trigger && PreProcessTrigger(PEntityOfEntIndex(client), args, is_quoted)) { - CPlayer *pPlayer; - if (is_silent - && g_bSupressSilentFails - && client != 0 - && (pPlayer = g_Players.GetPlayerByIndex(client)) != NULL - && pPlayer->GetAdminId() != INVALID_ADMIN_ID) - { - RETURN_META(MRES_SUPERCEDE); - } - RETURN_META(MRES_IGNORED); + m_bIsChatTrigger = true; + + /** + * We'll execute it in post. + */ + m_bWillProcessInPost = true; + m_bTriggerWasSilent = is_silent; } - m_bIsChatTrigger = true; + if (m_pOnClientSayCmd->GetFunctionCount() != 0) + { + cell_t res = Pl_Continue; + m_pOnClientSayCmd->PushCell(client); + m_pOnClientSayCmd->PushString(pCommandName); + m_pOnClientSayCmd->PushString(command.ArgS()); + m_pOnClientSayCmd->Execute(&res); - /** - * We'll execute it in post. - */ - m_bWillProcessInPost = true; - m_bTriggerWasSilent = is_silent; + if (res >= Pl_Handled) + { + m_bPluginIgnored = (res >= Pl_Stop); + RETURN_META(MRES_SUPERCEDE); + } + } - /* If we're silent, block */ - if (is_silent) + if (m_bWillProcessInPost || \ + (is_silent && g_bSupressSilentFails && pPlayer->GetAdminId() != INVALID_ADMIN_ID)) { RETURN_META(MRES_SUPERCEDE); } @@ -269,23 +321,39 @@ void ChatTriggers::OnSayCommand_Pre() #if SOURCE_ENGINE >= SE_ORANGEBOX void ChatTriggers::OnSayCommand_Post(const CCommand &command) +{ #else void ChatTriggers::OnSayCommand_Post() -#endif { - m_bIsChatTrigger = false; - m_bWasFloodedMessage = false; + CCommand command; +#endif + int client = g_ConCmds.GetCommandClient(); + if (m_bWillProcessInPost) { /* Reset this for re-entrancy */ m_bWillProcessInPost = false; /* Execute the cached command */ - int client = g_ConCmds.GetCommandClient(); unsigned int old = SetReplyTo(SM_REPLY_CHAT); serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute); SetReplyTo(old); } + + if (m_bPluginIgnored) + { + m_bPluginIgnored = false; + } + else if (!m_bWasFloodedMessage && m_pOnClientSayCmd_Post->GetFunctionCount() != 0) + { + m_pOnClientSayCmd_Post->PushCell(client); + m_pOnClientSayCmd_Post->PushString(command.Arg(0)); + m_pOnClientSayCmd_Post->PushString(command.ArgS()); + m_pOnClientSayCmd_Post->Execute(NULL); + } + + m_bIsChatTrigger = false; + m_bWasFloodedMessage = false; } bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted) diff --git a/core/ChatTriggers.h b/core/ChatTriggers.h index 38295c5c6..8b5bc21e0 100644 --- a/core/ChatTriggers.h +++ b/core/ChatTriggers.h @@ -72,6 +72,11 @@ private: private: ConCommand *m_pSayCmd; ConCommand *m_pSayTeamCmd; +#if SOURCE_ENGINE == SE_EPISODEONE + ConCommand *m_pSay2Cmd; +#elif SOURCE_ENGINE == SE_NUCLEARDAWN + ConCommand *m_pSaySquadCmd; +#endif char *m_PubTrigger; size_t m_PubTriggerSize; char *m_PrivTrigger; @@ -80,10 +85,16 @@ private: bool m_bTriggerWasSilent; bool m_bIsChatTrigger; bool m_bWasFloodedMessage; + bool m_bPluginIgnored; unsigned int m_ReplyTo; char m_ToExecute[300]; IForward *m_pShouldFloodBlock; IForward *m_pDidFloodBlock; + IForward *m_pOnClientSayCmd; + IForward *m_pOnClientSayCmd_Post; +#if SOURCE_ENGINE == SE_EPISODEONE + bool m_bIsINS; +#endif }; extern ChatTriggers g_ChatTriggers; diff --git a/plugins/basecomm.sp b/plugins/basecomm.sp index 5e43d7c83..aee6e7e30 100644 --- a/plugins/basecomm.sp +++ b/plugins/basecomm.sp @@ -81,9 +81,6 @@ public OnPluginStart() g_Cvar_Deadtalk = CreateConVar("sm_deadtalk", "0", "Controls how dead communicate. 0 - Off. 1 - Dead players ignore teams. 2 - Dead players talk to living teammates.", 0, true, 0.0, true, 2.0); g_Cvar_Alltalk = FindConVar("sv_alltalk"); - AddCommandListener(Command_Say, "say"); - AddCommandListener(Command_Say, "say_team"); - RegAdminCmd("sm_mute", Command_Mute, ADMFLAG_CHAT, "sm_mute - Removes a player's ability to use voice."); RegAdminCmd("sm_gag", Command_Gag, ADMFLAG_CHAT, "sm_gag - Removes a player's ability to use chat."); RegAdminCmd("sm_silence", Command_Silence, ADMFLAG_CHAT, "sm_silence - Removes a player's ability to use voice or chat."); @@ -154,13 +151,13 @@ public bool:OnClientConnect(client, String:rejectmsg[], maxlen) return true; } -public Action:Command_Say(client, const String:command[], args) +public Action:OnClientSayCommand(client, const String:command[], const String:sArgs[]) { if (client) { if (g_Gagged[client]) { - return Plugin_Handled; + return Plugin_Stop; } } diff --git a/plugins/basetriggers.sp b/plugins/basetriggers.sp index b8c923605..5800023d4 100644 --- a/plugins/basetriggers.sp +++ b/plugins/basetriggers.sp @@ -75,10 +75,6 @@ public OnPluginStart() g_Cvar_TimeleftInterval = CreateConVar("sm_timeleft_interval", "0.0", "Display timeleft every x seconds. Default 0.", 0, true, 0.0, true, 1800.0); g_Cvar_FriendlyFire = FindConVar("mp_friendlyfire"); - AddCommandListener(Command_Say, "say"); - AddCommandListener(Command_Say, "say2"); - AddCommandListener(Command_Say, "say_team"); - RegConsoleCmd("timeleft", Command_Timeleft); RegConsoleCmd("nextmap", Command_Nextmap); RegConsoleCmd("motd", Command_Motd); @@ -236,22 +232,22 @@ public Action:Command_Motd(client, args) return Plugin_Handled; } -public Action:Command_Say(client, const String:command[], argc) +public OnClientSayCommand_Post(client, const String:command[], const String:sArgs[]) { decl String:text[192]; new startidx = 0; - if (GetCmdArgString(text, sizeof(text)) < 1) + + if (strcopy(text, sizeof(text), sArgs) < 1) { - return Plugin_Continue; + return; } - if (text[strlen(text)-1] == '"') + if (text[0] == '"') { - text[strlen(text)-1] = '\0'; startidx = 1; } - if (strcmp(command, "say2", false) == 0) + if ((strcmp(command, "say2", false) == 0) && strlen(sArgs) >= 4) startidx += 4; if (strcmp(text[startidx], "timeleft", false) == 0) @@ -342,8 +338,6 @@ public Action:Command_Say(client, const String:command[], argc) { ShowMOTDPanel(client, "Message Of The Day", "motd", MOTDPANEL_TYPE_INDEX); } - - return Plugin_Continue; } ShowTimeLeft(client, who) diff --git a/plugins/include/console.inc b/plugins/include/console.inc index a0af53dd5..eeb178d20 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -938,3 +938,24 @@ native bool:AddCommandListener(CommandListener:callback, const String:command[]= */ native RemoveCommandListener(CommandListener:callback, const String:command[]=""); +/** + * Global listener for the chat commands. + * + * @param client Client index. + * @param command Command name. + * @param sArgs Chat argument string. + * + * @return An Action value. Returning Plugin_Handled bypasses the game function call. + Returning Plugin_Stop bypasses the post hook as well as the game function. + */ +forward Action:OnClientSayCommand(client, const String:command[], const String:sArgs[]); + +/** + * Global post listener for the chat commands. + * + * @param client Client index. + * @param command Command name. + * @param sArgs Chat argument string. + * + */ +forward OnClientSayCommand_Post(client, const String:command[], const String:sArgs[]);