1 #include "ChatTriggers.h"
2 #include "sm_stringutil.h"
3 #include "TextParsers.h"
4 #include "ConCmdManager.h"
6 /* :HACKHACK: We can't SH_DECL here because ConCmdManager.cpp does */
7 extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
8 extern int __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
10 ChatTriggers g_ChatTriggers;
12 ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
13 m_ReplyTo(SM_REPLY_CONSOLE)
15 m_PubTrigger = sm_strdup("!");
16 m_PrivTrigger = sm_strdup("/");
18 m_PrivTriggerSize = 1;
21 void ChatTriggers::OnSourceModGameInitialized()
23 ConCommandBase *pCmd = icvar->GetCommands();
27 if (pCmd->IsCommand())
29 name = pCmd->GetName();
30 if (strcmp(name, "say") == 0)
32 m_pSayCmd = (ConCommand *)pCmd;
36 pCmd = const_cast<ConCommandBase *>(pCmd->GetNext());
41 SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
42 SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
46 void ChatTriggers::OnSourceModShutdown()
50 SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
51 SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
55 void ChatTriggers::OnSayCommand_Pre()
57 int client = g_ConCmds.GetCommandClient();
59 /* The server console cannot do this */
62 RETURN_META(MRES_IGNORED);
65 const char *args = engine->Cmd_Args();
67 /* Handle quoted string sets */
68 bool is_quoted = false;
75 bool is_trigger = false;
76 bool is_silent = false;
78 /* Check for either trigger */
79 if (m_PubTriggerSize && strncmp(args, m_PubTrigger, m_PubTriggerSize) == 0)
82 } else if (m_PrivTriggerSize && strncmp(args, m_PrivTrigger, m_PrivTriggerSize) == 0) {
89 RETURN_META(MRES_IGNORED);
92 /* If we're a public command, process later */
95 /* We have to process this in _post_ instead. Darn. */
96 m_bWillProcessInPost = true;
97 RETURN_META(MRES_IGNORED);
100 /* Otherwise, process now */
101 if (ProcessTrigger(engine->PEntityOfEntIndex(client), &args[m_PrivTriggerSize], is_quoted))
103 /* If we succeed, block the original say! */
104 RETURN_META(MRES_SUPERCEDE);
107 RETURN_META(MRES_IGNORED);
110 void ChatTriggers::OnSayCommand_Post()
112 if (m_bWillProcessInPost)
114 /* Reset this for re-entrancy */
115 m_bWillProcessInPost = false;
117 /* Get our arguments */
118 const char *args = engine->Cmd_Args();
120 /* Handle quotations */
121 bool is_quoted = false;
128 int client = g_ConCmds.GetCommandClient();
130 ProcessTrigger(engine->PEntityOfEntIndex(client), &args[m_PubTriggerSize], is_quoted);
134 bool ChatTriggers::ProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted)
136 /* Eat up whitespace */
137 while (*args != '\0' && IsWhitespace(args))
142 /* Check if we're still valid */
148 /* Extract a command. This is kind of sloppy. */
151 const char *inptr = args;
152 while (*inptr != '\0'
153 && !IsWhitespace(inptr)
154 && cmd_len < sizeof(cmd_buf) - 1)
156 cmd_buf[cmd_len++] = *inptr++;
158 cmd_buf[cmd_len] = '\0';
160 /* See if we have this registered */
161 bool prepended = false;
162 if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
164 /* Check if we had an "sm_" prefix */
165 if (strncmp(cmd_buf, "sm_", 3) == 0)
170 /* Now, prepend. Don't worry about the buffers. This will
171 * work because the sizes are limited from earlier.
174 strcpy(new_buf, "sm_");
175 strncopy(&new_buf[3], cmd_buf, sizeof(new_buf)-3);
178 if (!g_ConCmds.LookForSourceModCommand(new_buf))
186 /* See if we need to do extra string manipulation */
187 if (is_quoted || prepended)
189 static char buffer[300];
192 /* Check if we need to prepend sm_ */
195 len = UTIL_Format(buffer, sizeof(buffer), "sm_%s", args);
197 len = strncopy(buffer, args, sizeof(buffer));
200 /* Check if we need to strip a quote */
203 if (buffer[len-1] == '"')
205 buffer[--len] = '\0';
212 /* Finally, execute! */
213 unsigned int old = SetReplyTo(SM_REPLY_CHAT);
214 serverpluginhelpers->ClientCommand(pEdict, args);
220 unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
222 unsigned int old = m_ReplyTo;
229 unsigned int ChatTriggers::GetReplyTo()