core/ChatTriggers.cpp
author SystematicMania <systematicmania@gmail.com>
Thu Feb 27 23:06:02 2014 -0500 (2014-02-27)
changeset 4260 b2f7d97b1ea7
parent 4256 9f0db041581a
child 4262 c2836eb6c34a
permissions -rw-r--r--
Strip quotes from chat forwards (bug 5986, r=psychonic).
dvander@1231
     1
/**
dvander@1231
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@1231
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@1231
    28
 *
dvander@1231
    29
 * Version: $Id$
dvander@1231
    30
 */
dvander@1231
    31
dvander@1406
    32
#include <ITextParsers.h>
dvander@893
    33
#include "ChatTriggers.h"
dvander@893
    34
#include "sm_stringutil.h"
dvander@893
    35
#include "ConCmdManager.h"
dvander@1794
    36
#include "PlayerManager.h"
dvander@1925
    37
#include "HalfLife2.h"
dvander@3004
    38
#include "logic_bridge.h"
skamonkey@4140
    39
#include "sourcemod.h"
dvander@893
    40
skamonkey@3899
    41
#if SOURCE_ENGINE == SE_DOTA
skamonkey@3942
    42
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
skamonkey@3899
    43
#elif SOURCE_ENGINE >= SE_ORANGEBOX
skamonkey@3899
    44
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
skamonkey@3899
    45
#elif SOURCE_ENGINE == SE_DARKMESSIAH
skamonkey@3899
    46
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
faluco@1541
    47
#else
skamonkey@3899
    48
# if SH_IMPL_VERSION >= 4
skamonkey@3899
    49
 extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
skamonkey@3899
    50
# else
skamonkey@3899
    51
 extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
skamonkey@3899
    52
# endif
skamonkey@3899
    53
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
skamonkey@3899
    54
#endif
dvander@893
    55
dvander@893
    56
ChatTriggers g_ChatTriggers;
dvander@1794
    57
bool g_bSupressSilentFails = false;
dvander@893
    58
dvander@893
    59
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false), 
systematicmania@4260
    60
	m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL)
dvander@893
    61
{
dvander@893
    62
	m_PubTrigger = sm_strdup("!");
dvander@893
    63
	m_PrivTrigger = sm_strdup("/");
dvander@893
    64
	m_PubTriggerSize = 1;
dvander@893
    65
	m_PrivTriggerSize = 1;
dvander@1469
    66
	m_bIsChatTrigger = false;
systematicmania@4256
    67
	m_bPluginIgnored = true;
kyle@3974
    68
#if SOURCE_ENGINE == SE_EPISODEONE
kyle@3974
    69
	m_bIsINS = false;
kyle@3974
    70
#endif
dvander@893
    71
}
dvander@893
    72
dvander@897
    73
ChatTriggers::~ChatTriggers()
dvander@897
    74
{
dvander@897
    75
	delete [] m_PubTrigger;
dvander@897
    76
	m_PubTrigger = NULL;
dvander@897
    77
	delete [] m_PrivTrigger;
dvander@897
    78
	m_PrivTrigger = NULL;
systematicmania@4260
    79
	delete [] m_ArgSBackup;
systematicmania@4260
    80
	m_ArgSBackup = NULL;
dvander@897
    81
}
dvander@896
    82
dvander@896
    83
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key, 
dvander@896
    84
													const char *value, 
dvander@896
    85
													ConfigSource source,
dvander@896
    86
													char *error, 
dvander@896
    87
													size_t maxlength)
dvander@896
    88
{
dvander@896
    89
	if (strcmp(key, "PublicChatTrigger") == 0)
dvander@896
    90
	{
dvander@896
    91
		delete [] m_PubTrigger;
dvander@896
    92
		m_PubTrigger = sm_strdup(value);
dvander@896
    93
		m_PubTriggerSize = strlen(m_PubTrigger);
dvander@896
    94
		return ConfigResult_Accept;
dvander@1794
    95
	}
dvander@1794
    96
	else if (strcmp(key, "SilentChatTrigger") == 0)
dvander@1794
    97
	{
dvander@896
    98
		delete [] m_PrivTrigger;
dvander@896
    99
		m_PrivTrigger = sm_strdup(value);
dvander@896
   100
		m_PrivTriggerSize = strlen(m_PrivTrigger);
dvander@896
   101
		return ConfigResult_Accept;
dvander@896
   102
	}
dvander@1794
   103
	else if (strcmp(key, "SilentFailSuppress") == 0)
dvander@1794
   104
	{
dvander@1794
   105
		g_bSupressSilentFails = strcmp(value, "yes") == 0;
dvander@1794
   106
		return ConfigResult_Accept;
dvander@1794
   107
	}
dvander@896
   108
dvander@896
   109
	return ConfigResult_Ignore;
dvander@896
   110
}
dvander@896
   111
dvander@1925
   112
void ChatTriggers::OnSourceModAllInitialized()
dvander@1925
   113
{
skamonkey@4139
   114
	m_pShouldFloodBlock = forwardsys->CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
skamonkey@4139
   115
	m_pDidFloodBlock = forwardsys->CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
skamonkey@4139
   116
	m_pOnClientSayCmd = forwardsys->CreateForward("OnClientSayCommand", ET_Event, 3, NULL, Param_Cell, Param_String, Param_String);
skamonkey@4139
   117
	m_pOnClientSayCmd_Post = forwardsys->CreateForward("OnClientSayCommand_Post", ET_Ignore, 3, NULL, Param_Cell, Param_String, Param_String);
dvander@1925
   118
}
dvander@1925
   119
dvander@1925
   120
void ChatTriggers::OnSourceModAllInitialized_Post()
dvander@1925
   121
{
dvander@3004
   122
	logicore.AddCorePhraseFile("antiflood.phrases");
dvander@1925
   123
}
dvander@1925
   124
dvander@893
   125
void ChatTriggers::OnSourceModGameInitialized()
dvander@893
   126
{
ds@2400
   127
	m_pSayCmd = FindCommand("say");
ds@2400
   128
	m_pSayTeamCmd = FindCommand("say_team");
dvander@893
   129
dvander@893
   130
	if (m_pSayCmd)
dvander@893
   131
	{
kyle@3819
   132
		SH_ADD_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
kyle@3819
   133
		SH_ADD_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
dvander@893
   134
	}
dvander@897
   135
	if (m_pSayTeamCmd)
dvander@897
   136
	{
kyle@3819
   137
		SH_ADD_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
kyle@3819
   138
		SH_ADD_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
dvander@897
   139
	}
kyle@3974
   140
kyle@3974
   141
#if SOURCE_ENGINE == SE_EPISODEONE
skamonkey@3975
   142
	m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0);
kyle@3974
   143
kyle@3974
   144
	if (m_bIsINS)
kyle@3974
   145
	{
kyle@3974
   146
		m_pSay2Cmd = FindCommand("say2");
kyle@3974
   147
		if (m_pSay2Cmd)
kyle@3974
   148
		{
kyle@3974
   149
			SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
kyle@3974
   150
			SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
kyle@3974
   151
		}
kyle@3974
   152
	}
kyle@3974
   153
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
kyle@3974
   154
	m_pSaySquadCmd = FindCommand("say_squad");
kyle@3974
   155
kyle@3974
   156
	if (m_pSaySquadCmd)
kyle@3974
   157
	{
kyle@3974
   158
		SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
kyle@3974
   159
		SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
kyle@3974
   160
	}
kyle@3974
   161
#endif
dvander@893
   162
}
dvander@893
   163
dvander@893
   164
void ChatTriggers::OnSourceModShutdown()
dvander@893
   165
{
dvander@893
   166
	if (m_pSayCmd)
dvander@893
   167
	{
kyle@3819
   168
		SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
kyle@3819
   169
		SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
dvander@893
   170
	}
dvander@1925
   171
kyle@3974
   172
	if (m_pSayTeamCmd)
kyle@3974
   173
	{
kyle@3974
   174
		SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
kyle@3974
   175
		SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
kyle@3974
   176
	}
kyle@3974
   177
kyle@3974
   178
#if SOURCE_ENGINE == SE_EPISODEONE
kyle@3974
   179
	if (m_bIsINS && m_pSay2Cmd)
kyle@3974
   180
	{
kyle@3974
   181
		SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
kyle@3974
   182
		SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
kyle@3974
   183
	}
kyle@3974
   184
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
kyle@3974
   185
	if (m_pSaySquadCmd)
kyle@3974
   186
	{
kyle@3974
   187
		SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
kyle@3974
   188
		SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
kyle@3974
   189
	}
kyle@3974
   190
#endif
kyle@3974
   191
skamonkey@4139
   192
	forwardsys->ReleaseForward(m_pShouldFloodBlock);
skamonkey@4139
   193
	forwardsys->ReleaseForward(m_pDidFloodBlock);
skamonkey@4139
   194
	forwardsys->ReleaseForward(m_pOnClientSayCmd);
skamonkey@4139
   195
	forwardsys->ReleaseForward(m_pOnClientSayCmd_Post);
dvander@893
   196
}
dvander@893
   197
skamonkey@3899
   198
#if SOURCE_ENGINE == SE_DOTA
skamonkey@3942
   199
void ChatTriggers::OnSayCommand_Pre(const CCommandContext &context, const CCommand &command)
skamonkey@3899
   200
{
skamonkey@3899
   201
#elif SOURCE_ENGINE >= SE_ORANGEBOX
faluco@1541
   202
void ChatTriggers::OnSayCommand_Pre(const CCommand &command)
faluco@1541
   203
{
faluco@1541
   204
#else
dvander@893
   205
void ChatTriggers::OnSayCommand_Pre()
dvander@893
   206
{
faluco@1541
   207
	CCommand command;
faluco@1541
   208
#endif
kyle@3974
   209
	int client = g_ConCmds.GetCommandClient();
dvander@1469
   210
	m_bIsChatTrigger = false;
dvander@1925
   211
	m_bWasFloodedMessage = false;
systematicmania@4256
   212
	m_bPluginIgnored = true;
dvander@893
   213
januk@4042
   214
	const char *args = command.ArgS();
systematicmania@4256
   215
januk@4042
   216
	if (!args)
januk@4042
   217
	{
januk@4042
   218
		RETURN_META(MRES_IGNORED);
januk@4042
   219
	}
januk@4042
   220
januk@4042
   221
	/* Save these off for post hook as the command data returned from the engine in older engine versions 
januk@4042
   222
	 * can be NULL, despite the data still being there and valid. */
januk@4042
   223
	m_Arg0Backup = command.Arg(0);
systematicmania@4260
   224
systematicmania@4260
   225
	/* Handle quoted string sets */
systematicmania@4260
   226
	bool is_quoted = false;
systematicmania@4260
   227
	size_t len = strlen(args);
systematicmania@4260
   228
systematicmania@4260
   229
	/* The engine does not display empty say commands.
systematicmania@4260
   230
	 * So to prevent forwarding it, let's block it. */
systematicmania@4260
   231
	if (len == 0)
systematicmania@4260
   232
	{
systematicmania@4260
   233
		RETURN_META(MRES_SUPERCEDE);
systematicmania@4260
   234
	}
systematicmania@4260
   235
systematicmania@4260
   236
	/* The first pair of quotes are stripped from client say commands, but not console ones.
systematicmania@4260
   237
	 * We do not want the forwards to differ from what is displayed.
systematicmania@4260
   238
	 * So only strip the first pair of quotes from client say commands. */
systematicmania@4260
   239
	if (client != 0 && args[0] == '"' && args[len-1] == '"')
systematicmania@4260
   240
	{
systematicmania@4260
   241
		/* The server normally won't display empty say commands, but in this case it does.
systematicmania@4260
   242
		 * I don't think it's desired so let's block it. */
systematicmania@4260
   243
		if (len <= 2)
systematicmania@4260
   244
		{
systematicmania@4260
   245
			RETURN_META(MRES_SUPERCEDE);
systematicmania@4260
   246
		}
systematicmania@4260
   247
systematicmania@4260
   248
		args++;
systematicmania@4260
   249
		len--;
systematicmania@4260
   250
		is_quoted = true;
systematicmania@4260
   251
	}
systematicmania@4260
   252
	
systematicmania@4260
   253
	/* Some? engines strip the last quote when printing the string to chat.
systematicmania@4260
   254
	 * This results in having a double-quoted message passed to the OnClientSayCommand ("message") forward,
systematicmania@4260
   255
	 * but losing the last quote in the OnClientSayCommand_Post ("message) forward.
systematicmania@4260
   256
	 * To compensate this, we copy the args into our own buffer where the engine won't mess with
systematicmania@4260
   257
	 * and strip the quotes. */
systematicmania@4260
   258
	delete [] m_ArgSBackup;
systematicmania@4260
   259
	m_ArgSBackup = new char[CCommand::MaxCommandLength()+1];
systematicmania@4260
   260
	memcpy(m_ArgSBackup, args, len+1);
systematicmania@4260
   261
systematicmania@4260
   262
	/* Strip the quotes from the argument */
systematicmania@4260
   263
	if (is_quoted)
systematicmania@4260
   264
	{
systematicmania@4260
   265
		if (m_ArgSBackup[len-1] == '"')
systematicmania@4260
   266
		{
systematicmania@4260
   267
			m_ArgSBackup[--len] = '\0';
systematicmania@4260
   268
		}
systematicmania@4260
   269
	}
januk@4042
   270
dvander@893
   271
	/* The server console cannot do this */
kyle@3974
   272
	if (client == 0)
dvander@1934
   273
	{
systematicmania@4256
   274
		if (CallOnClientSayCommand(client) >= Pl_Handled)
januk@4042
   275
		{
januk@4042
   276
			RETURN_META(MRES_SUPERCEDE);
januk@4042
   277
		}
systematicmania@4256
   278
dvander@1934
   279
		RETURN_META(MRES_IGNORED);
dvander@1934
   280
	}
dvander@1934
   281
kyle@3974
   282
	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
kyle@3974
   283
dvander@1934
   284
	/* We guarantee the client is connected */
kyle@3974
   285
	if (!pPlayer || !pPlayer->IsConnected())
dvander@893
   286
	{
dvander@893
   287
		RETURN_META(MRES_IGNORED);
dvander@893
   288
	}
dvander@893
   289
dvander@1925
   290
	/* Check if we need to block this message from being sent */
dvander@1925
   291
	if (ClientIsFlooding(client))
dvander@1925
   292
	{
dvander@1925
   293
		char buffer[128];
dvander@1925
   294
dvander@3004
   295
		if (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "Flooding the server", &client))
dvander@1925
   296
			UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
dvander@1925
   297
dvander@1925
   298
		/* :TODO: we should probably kick people who spam too much. */
dvander@1925
   299
dvander@1925
   300
		char fullbuffer[192];
dvander@1925
   301
		UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s", buffer);
dvander@1925
   302
		g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
dvander@1925
   303
dvander@1925
   304
		m_bWasFloodedMessage = true;
dvander@1925
   305
dvander@1925
   306
		RETURN_META(MRES_SUPERCEDE);
dvander@1925
   307
	}
dvander@1925
   308
kyle@3974
   309
#if SOURCE_ENGINE == SE_EPISODEONE
skamonkey@4015
   310
	if (m_bIsINS && strcmp(m_Arg0Backup, "say2") == 0 && strlen(args) >= 4)
kyle@3974
   311
	{
kyle@3974
   312
		args += 4;
kyle@3974
   313
	}
kyle@3974
   314
#endif
kyle@3974
   315
dvander@893
   316
	bool is_trigger = false;
dvander@893
   317
	bool is_silent = false;
dvander@893
   318
dvander@893
   319
	/* Check for either trigger */
dvander@893
   320
	if (m_PubTriggerSize && strncmp(args, m_PubTrigger, m_PubTriggerSize) == 0)
dvander@893
   321
	{
dvander@893
   322
		is_trigger = true;
dvander@1103
   323
		args = &args[m_PubTriggerSize];
dvander@1925
   324
	} 
dvander@2607
   325
	else if (m_PrivTriggerSize && strncmp(args, m_PrivTrigger, m_PrivTriggerSize) == 0) 
dvander@1925
   326
	{
dvander@893
   327
		is_trigger = true;
dvander@893
   328
		is_silent = true;
dvander@1103
   329
		args = &args[m_PrivTriggerSize];
dvander@893
   330
	}
dvander@893
   331
dvander@1103
   332
	/**
dvander@1103
   333
	 * Test if this is actually a command!
dvander@1103
   334
	 */
systematicmania@4260
   335
	if (is_trigger && PreProcessTrigger(PEntityOfEntIndex(client), args))
dvander@893
   336
	{
kyle@3974
   337
		m_bIsChatTrigger = true;
kyle@3974
   338
kyle@3974
   339
		/**
kyle@3974
   340
		 * We'll execute it in post.
kyle@3974
   341
		 */
kyle@3974
   342
		m_bWillProcessInPost = true;
kyle@3974
   343
	}
kyle@3974
   344
systematicmania@4256
   345
	if (is_silent && (m_bIsChatTrigger || (g_bSupressSilentFails && pPlayer->GetAdminId() != INVALID_ADMIN_ID)))
skamonkey@4044
   346
	{
skamonkey@4044
   347
		RETURN_META(MRES_SUPERCEDE);
dvander@893
   348
	}
dvander@893
   349
systematicmania@4256
   350
	if (CallOnClientSayCommand(client) >= Pl_Handled)
dvander@893
   351
	{
dvander@893
   352
		RETURN_META(MRES_SUPERCEDE);
dvander@893
   353
	}
dvander@893
   354
dvander@1103
   355
	/* Otherwise, let the command continue */
dvander@893
   356
	RETURN_META(MRES_IGNORED);
dvander@893
   357
}
dvander@893
   358
skamonkey@3899
   359
#if SOURCE_ENGINE == SE_DOTA
skamonkey@3942
   360
void ChatTriggers::OnSayCommand_Post(const CCommandContext &context, const CCommand &command)
skamonkey@3899
   361
#elif SOURCE_ENGINE >= SE_ORANGEBOX
faluco@1541
   362
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
faluco@1541
   363
#else
dvander@893
   364
void ChatTriggers::OnSayCommand_Post()
skamonkey@4015
   365
#endif
skamonkey@3975
   366
{
kyle@3974
   367
	int client = g_ConCmds.GetCommandClient();
kyle@3974
   368
skamonkey@4041
   369
	if (m_bWillProcessInPost)
dvander@893
   370
	{
skamonkey@4041
   371
		/* Reset this for re-entrancy */
skamonkey@4041
   372
		m_bWillProcessInPost = false;
systematicmania@4256
   373
dvander@1103
   374
		/* Execute the cached command */
dvander@1103
   375
		unsigned int old = SetReplyTo(SM_REPLY_CHAT);
skamonkey@3854
   376
#if SOURCE_ENGINE == SE_DOTA
skamonkey@3913
   377
		engine->ClientCommand(client, "%s", m_ToExecute);
skamonkey@3854
   378
#else
ds@2400
   379
		serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute);
skamonkey@3854
   380
#endif
dvander@1103
   381
		SetReplyTo(old);
dvander@893
   382
	}
kyle@3974
   383
systematicmania@4256
   384
	if (!m_bPluginIgnored && m_pOnClientSayCmd_Post->GetFunctionCount() != 0)
kyle@3974
   385
	{
kyle@3974
   386
		m_pOnClientSayCmd_Post->PushCell(client);
skamonkey@4015
   387
		m_pOnClientSayCmd_Post->PushString(m_Arg0Backup);
skamonkey@4015
   388
		m_pOnClientSayCmd_Post->PushString(m_ArgSBackup);
kyle@3974
   389
		m_pOnClientSayCmd_Post->Execute(NULL);
kyle@3974
   390
	}
kyle@3974
   391
kyle@3974
   392
	m_bIsChatTrigger = false;
kyle@3974
   393
	m_bWasFloodedMessage = false;
dvander@893
   394
}
dvander@893
   395
systematicmania@4260
   396
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
dvander@893
   397
{
dvander@893
   398
	/* Extract a command.  This is kind of sloppy. */
dvander@893
   399
	char cmd_buf[64];
dvander@893
   400
	size_t cmd_len = 0;
dvander@893
   401
	const char *inptr = args;
dvander@893
   402
	while (*inptr != '\0' 
dvander@1406
   403
			&& !textparsers->IsWhitespace(inptr) 
dvander@935
   404
			&& *inptr != '"'
dvander@893
   405
			&& cmd_len < sizeof(cmd_buf) - 1)
dvander@893
   406
	{
dvander@893
   407
		cmd_buf[cmd_len++] = *inptr++;
dvander@893
   408
	}
dvander@893
   409
	cmd_buf[cmd_len] = '\0';
dvander@893
   410
dvander@1377
   411
	if (cmd_len == 0)
dvander@1377
   412
	{
dvander@1377
   413
		return false;
dvander@1377
   414
	}
dvander@1377
   415
dvander@893
   416
	/* See if we have this registered */
dvander@893
   417
	bool prepended = false;
dvander@893
   418
	if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
dvander@893
   419
	{
dvander@893
   420
		/* Check if we had an "sm_" prefix */
dvander@893
   421
		if (strncmp(cmd_buf, "sm_", 3) == 0)
dvander@893
   422
		{
dvander@893
   423
			return false;
dvander@893
   424
		}
dvander@893
   425
dvander@893
   426
		/* Now, prepend.  Don't worry about the buffers.  This will 
dvander@893
   427
		 * work because the sizes are limited from earlier.
dvander@893
   428
		 */
dvander@893
   429
		char new_buf[80];
dvander@893
   430
		strcpy(new_buf, "sm_");
dvander@893
   431
		strncopy(&new_buf[3], cmd_buf, sizeof(new_buf)-3);
dvander@893
   432
dvander@893
   433
		/* Recheck */
dvander@893
   434
		if (!g_ConCmds.LookForSourceModCommand(new_buf))
dvander@893
   435
		{
dvander@893
   436
			return false;
dvander@893
   437
		}
systematicmania@4256
   438
dvander@893
   439
		prepended = true;
dvander@893
   440
	}
dvander@893
   441
dvander@893
   442
	/* See if we need to do extra string manipulation */
systematicmania@4260
   443
	if (prepended)
dvander@893
   444
	{
dvander@893
   445
		size_t len;
dvander@893
   446
dvander@893
   447
		/* Check if we need to prepend sm_ */
dvander@893
   448
		if (prepended)
dvander@893
   449
		{
dvander@1103
   450
			len = UTIL_Format(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
dvander@893
   451
		} else {
dvander@1103
   452
			len = strncopy(m_ToExecute, args, sizeof(m_ToExecute));
dvander@893
   453
		}
dvander@1103
   454
	} else {
dvander@1103
   455
		strncopy(m_ToExecute, args, sizeof(m_ToExecute));
dvander@893
   456
	}
dvander@893
   457
dvander@893
   458
	return true;
dvander@893
   459
}
dvander@893
   460
januk@4042
   461
cell_t ChatTriggers::CallOnClientSayCommand(int client)
januk@4042
   462
{
januk@4042
   463
	cell_t res = Pl_Continue;
systematicmania@4256
   464
	if (m_pOnClientSayCmd->GetFunctionCount() != 0)
skamonkey@4044
   465
	{
skamonkey@4044
   466
		m_pOnClientSayCmd->PushCell(client);
skamonkey@4044
   467
		m_pOnClientSayCmd->PushString(m_Arg0Backup);
skamonkey@4044
   468
		m_pOnClientSayCmd->PushString(m_ArgSBackup);
skamonkey@4044
   469
		m_pOnClientSayCmd->Execute(&res);
skamonkey@4044
   470
	}
systematicmania@4256
   471
systematicmania@4256
   472
	m_bPluginIgnored = (res >= Pl_Stop);
systematicmania@4256
   473
januk@4042
   474
	return res;
januk@4042
   475
}
januk@4042
   476
dvander@893
   477
unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
dvander@893
   478
{
dvander@893
   479
	unsigned int old = m_ReplyTo;
dvander@893
   480
dvander@893
   481
	m_ReplyTo = reply;
dvander@893
   482
dvander@893
   483
	return old;
dvander@893
   484
}
dvander@893
   485
dvander@893
   486
unsigned int ChatTriggers::GetReplyTo()
dvander@893
   487
{
dvander@893
   488
	return m_ReplyTo;
dvander@893
   489
}
dvander@1469
   490
dvander@1469
   491
bool ChatTriggers::IsChatTrigger()
dvander@1469
   492
{
dvander@1469
   493
	return m_bIsChatTrigger;
dvander@1469
   494
}
dvander@1925
   495
dvander@1925
   496
bool ChatTriggers::ClientIsFlooding(int client)
dvander@1925
   497
{
dvander@1925
   498
	bool is_flooding = false;
dvander@1925
   499
dvander@1925
   500
	if (m_pShouldFloodBlock->GetFunctionCount() != 0)
dvander@1925
   501
	{
dvander@1925
   502
		cell_t res = 0;
dvander@1925
   503
dvander@1925
   504
		m_pShouldFloodBlock->PushCell(client);
dvander@1925
   505
		m_pShouldFloodBlock->Execute(&res);
dvander@1925
   506
dvander@1925
   507
		if (res != 0)
dvander@1925
   508
		{
dvander@1925
   509
			is_flooding = true;
dvander@1925
   510
		}
dvander@1925
   511
	}
dvander@1925
   512
dvander@1925
   513
	if (m_pDidFloodBlock->GetFunctionCount() != 0)
dvander@1925
   514
	{
dvander@1925
   515
		m_pDidFloodBlock->PushCell(client);
dvander@1925
   516
		m_pDidFloodBlock->PushCell(is_flooding ? 1 : 0);
dvander@1925
   517
		m_pDidFloodBlock->Execute(NULL);
dvander@1925
   518
	}
dvander@1925
   519
dvander@1925
   520
	return is_flooding;
dvander@1925
   521
}
dvander@1925
   522
dvander@1925
   523
bool ChatTriggers::WasFloodedMessage()
dvander@1925
   524
{
dvander@1925
   525
	return m_bWasFloodedMessage;
dvander@1925
   526
}