core/ChatTriggers.cpp
author Peace-Maker <januk@freenet.de>
Wed Apr 23 08:55:09 2014 -0400 (2014-04-23)
changeset 4330 98726cea1607
parent 4262 c2836eb6c34a
permissions -rw-r--r--
Mark CS:S as supporting HudMsg (bug 6108, 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
	size_t len = strlen(args);
systematicmania@4260
   225
systematicmania@4262
   226
#if SOURCE_ENGINE == SE_EPISODEONE
systematicmania@4262
   227
	if (m_bIsINS)
systematicmania@4260
   228
	{
systematicmania@4262
   229
		if (strcmp(m_Arg0Backup, "say2") == 0 && len >= 4)
systematicmania@4262
   230
		{
systematicmania@4262
   231
			args += 4;
systematicmania@4262
   232
			len -= 4;
systematicmania@4262
   233
		}
systematicmania@4262
   234
systematicmania@4262
   235
		if (len == 0)
systematicmania@4262
   236
		{
systematicmania@4262
   237
			RETURN_META(MRES_SUPERCEDE);
systematicmania@4262
   238
		}
systematicmania@4260
   239
	}
systematicmania@4262
   240
#endif
systematicmania@4260
   241
systematicmania@4260
   242
	/* The first pair of quotes are stripped from client say commands, but not console ones.
systematicmania@4260
   243
	 * We do not want the forwards to differ from what is displayed.
systematicmania@4260
   244
	 * So only strip the first pair of quotes from client say commands. */
systematicmania@4262
   245
	bool is_quoted = false;
systematicmania@4262
   246
systematicmania@4262
   247
	if (
systematicmania@4262
   248
#if SOURCE_ENGINE == SE_EPISODEONE
systematicmania@4262
   249
		!m_bIsINS && 
systematicmania@4262
   250
#endif
systematicmania@4262
   251
		client != 0 && args[0] == '"' && args[len-1] == '"')
systematicmania@4260
   252
	{
systematicmania@4260
   253
		/* The server normally won't display empty say commands, but in this case it does.
systematicmania@4260
   254
		 * I don't think it's desired so let's block it. */
systematicmania@4260
   255
		if (len <= 2)
systematicmania@4260
   256
		{
systematicmania@4260
   257
			RETURN_META(MRES_SUPERCEDE);
systematicmania@4260
   258
		}
systematicmania@4260
   259
systematicmania@4260
   260
		args++;
systematicmania@4260
   261
		len--;
systematicmania@4260
   262
		is_quoted = true;
systematicmania@4260
   263
	}
systematicmania@4262
   264
systematicmania@4260
   265
	/* Some? engines strip the last quote when printing the string to chat.
systematicmania@4260
   266
	 * This results in having a double-quoted message passed to the OnClientSayCommand ("message") forward,
systematicmania@4260
   267
	 * but losing the last quote in the OnClientSayCommand_Post ("message) forward.
systematicmania@4260
   268
	 * To compensate this, we copy the args into our own buffer where the engine won't mess with
systematicmania@4260
   269
	 * and strip the quotes. */
systematicmania@4260
   270
	delete [] m_ArgSBackup;
systematicmania@4260
   271
	m_ArgSBackup = new char[CCommand::MaxCommandLength()+1];
systematicmania@4260
   272
	memcpy(m_ArgSBackup, args, len+1);
systematicmania@4260
   273
systematicmania@4260
   274
	/* Strip the quotes from the argument */
systematicmania@4260
   275
	if (is_quoted)
systematicmania@4260
   276
	{
systematicmania@4260
   277
		if (m_ArgSBackup[len-1] == '"')
systematicmania@4260
   278
		{
systematicmania@4260
   279
			m_ArgSBackup[--len] = '\0';
systematicmania@4260
   280
		}
systematicmania@4260
   281
	}
januk@4042
   282
dvander@893
   283
	/* The server console cannot do this */
kyle@3974
   284
	if (client == 0)
dvander@1934
   285
	{
systematicmania@4256
   286
		if (CallOnClientSayCommand(client) >= Pl_Handled)
januk@4042
   287
		{
januk@4042
   288
			RETURN_META(MRES_SUPERCEDE);
januk@4042
   289
		}
systematicmania@4256
   290
dvander@1934
   291
		RETURN_META(MRES_IGNORED);
dvander@1934
   292
	}
dvander@1934
   293
kyle@3974
   294
	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
kyle@3974
   295
dvander@1934
   296
	/* We guarantee the client is connected */
kyle@3974
   297
	if (!pPlayer || !pPlayer->IsConnected())
dvander@893
   298
	{
dvander@893
   299
		RETURN_META(MRES_IGNORED);
dvander@893
   300
	}
dvander@893
   301
dvander@1925
   302
	/* Check if we need to block this message from being sent */
dvander@1925
   303
	if (ClientIsFlooding(client))
dvander@1925
   304
	{
dvander@1925
   305
		char buffer[128];
dvander@1925
   306
dvander@3004
   307
		if (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "Flooding the server", &client))
dvander@1925
   308
			UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
dvander@1925
   309
dvander@1925
   310
		/* :TODO: we should probably kick people who spam too much. */
dvander@1925
   311
dvander@1925
   312
		char fullbuffer[192];
dvander@1925
   313
		UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s", buffer);
dvander@1925
   314
		g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
dvander@1925
   315
dvander@1925
   316
		m_bWasFloodedMessage = true;
dvander@1925
   317
dvander@1925
   318
		RETURN_META(MRES_SUPERCEDE);
dvander@1925
   319
	}
dvander@1925
   320
dvander@893
   321
	bool is_trigger = false;
dvander@893
   322
	bool is_silent = false;
dvander@893
   323
dvander@893
   324
	/* Check for either trigger */
systematicmania@4262
   325
	if (m_PubTriggerSize && strncmp(m_ArgSBackup, m_PubTrigger, m_PubTriggerSize) == 0)
dvander@893
   326
	{
dvander@893
   327
		is_trigger = true;
systematicmania@4262
   328
		args = &m_ArgSBackup[m_PubTriggerSize];
dvander@1925
   329
	} 
systematicmania@4262
   330
	else if (m_PrivTriggerSize && strncmp(m_ArgSBackup, m_PrivTrigger, m_PrivTriggerSize) == 0) 
dvander@1925
   331
	{
dvander@893
   332
		is_trigger = true;
dvander@893
   333
		is_silent = true;
systematicmania@4262
   334
		args = &m_ArgSBackup[m_PrivTriggerSize];
dvander@893
   335
	}
dvander@893
   336
dvander@1103
   337
	/**
dvander@1103
   338
	 * Test if this is actually a command!
dvander@1103
   339
	 */
systematicmania@4260
   340
	if (is_trigger && PreProcessTrigger(PEntityOfEntIndex(client), args))
dvander@893
   341
	{
kyle@3974
   342
		m_bIsChatTrigger = true;
kyle@3974
   343
kyle@3974
   344
		/**
kyle@3974
   345
		 * We'll execute it in post.
kyle@3974
   346
		 */
kyle@3974
   347
		m_bWillProcessInPost = true;
kyle@3974
   348
	}
kyle@3974
   349
systematicmania@4256
   350
	if (is_silent && (m_bIsChatTrigger || (g_bSupressSilentFails && pPlayer->GetAdminId() != INVALID_ADMIN_ID)))
skamonkey@4044
   351
	{
skamonkey@4044
   352
		RETURN_META(MRES_SUPERCEDE);
dvander@893
   353
	}
dvander@893
   354
systematicmania@4256
   355
	if (CallOnClientSayCommand(client) >= Pl_Handled)
dvander@893
   356
	{
dvander@893
   357
		RETURN_META(MRES_SUPERCEDE);
dvander@893
   358
	}
dvander@893
   359
dvander@1103
   360
	/* Otherwise, let the command continue */
dvander@893
   361
	RETURN_META(MRES_IGNORED);
dvander@893
   362
}
dvander@893
   363
skamonkey@3899
   364
#if SOURCE_ENGINE == SE_DOTA
skamonkey@3942
   365
void ChatTriggers::OnSayCommand_Post(const CCommandContext &context, const CCommand &command)
skamonkey@3899
   366
#elif SOURCE_ENGINE >= SE_ORANGEBOX
faluco@1541
   367
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
faluco@1541
   368
#else
dvander@893
   369
void ChatTriggers::OnSayCommand_Post()
skamonkey@4015
   370
#endif
skamonkey@3975
   371
{
kyle@3974
   372
	int client = g_ConCmds.GetCommandClient();
kyle@3974
   373
skamonkey@4041
   374
	if (m_bWillProcessInPost)
dvander@893
   375
	{
skamonkey@4041
   376
		/* Reset this for re-entrancy */
skamonkey@4041
   377
		m_bWillProcessInPost = false;
systematicmania@4256
   378
dvander@1103
   379
		/* Execute the cached command */
dvander@1103
   380
		unsigned int old = SetReplyTo(SM_REPLY_CHAT);
skamonkey@3854
   381
#if SOURCE_ENGINE == SE_DOTA
skamonkey@3913
   382
		engine->ClientCommand(client, "%s", m_ToExecute);
skamonkey@3854
   383
#else
ds@2400
   384
		serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute);
skamonkey@3854
   385
#endif
dvander@1103
   386
		SetReplyTo(old);
dvander@893
   387
	}
kyle@3974
   388
systematicmania@4256
   389
	if (!m_bPluginIgnored && m_pOnClientSayCmd_Post->GetFunctionCount() != 0)
kyle@3974
   390
	{
kyle@3974
   391
		m_pOnClientSayCmd_Post->PushCell(client);
skamonkey@4015
   392
		m_pOnClientSayCmd_Post->PushString(m_Arg0Backup);
skamonkey@4015
   393
		m_pOnClientSayCmd_Post->PushString(m_ArgSBackup);
kyle@3974
   394
		m_pOnClientSayCmd_Post->Execute(NULL);
kyle@3974
   395
	}
kyle@3974
   396
kyle@3974
   397
	m_bIsChatTrigger = false;
kyle@3974
   398
	m_bWasFloodedMessage = false;
dvander@893
   399
}
dvander@893
   400
systematicmania@4260
   401
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
dvander@893
   402
{
dvander@893
   403
	/* Extract a command.  This is kind of sloppy. */
dvander@893
   404
	char cmd_buf[64];
dvander@893
   405
	size_t cmd_len = 0;
dvander@893
   406
	const char *inptr = args;
dvander@893
   407
	while (*inptr != '\0' 
dvander@1406
   408
			&& !textparsers->IsWhitespace(inptr) 
dvander@935
   409
			&& *inptr != '"'
dvander@893
   410
			&& cmd_len < sizeof(cmd_buf) - 1)
dvander@893
   411
	{
dvander@893
   412
		cmd_buf[cmd_len++] = *inptr++;
dvander@893
   413
	}
dvander@893
   414
	cmd_buf[cmd_len] = '\0';
dvander@893
   415
dvander@1377
   416
	if (cmd_len == 0)
dvander@1377
   417
	{
dvander@1377
   418
		return false;
dvander@1377
   419
	}
dvander@1377
   420
dvander@893
   421
	/* See if we have this registered */
dvander@893
   422
	bool prepended = false;
dvander@893
   423
	if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
dvander@893
   424
	{
dvander@893
   425
		/* Check if we had an "sm_" prefix */
dvander@893
   426
		if (strncmp(cmd_buf, "sm_", 3) == 0)
dvander@893
   427
		{
dvander@893
   428
			return false;
dvander@893
   429
		}
dvander@893
   430
dvander@893
   431
		/* Now, prepend.  Don't worry about the buffers.  This will 
dvander@893
   432
		 * work because the sizes are limited from earlier.
dvander@893
   433
		 */
dvander@893
   434
		char new_buf[80];
dvander@893
   435
		strcpy(new_buf, "sm_");
dvander@893
   436
		strncopy(&new_buf[3], cmd_buf, sizeof(new_buf)-3);
dvander@893
   437
dvander@893
   438
		/* Recheck */
dvander@893
   439
		if (!g_ConCmds.LookForSourceModCommand(new_buf))
dvander@893
   440
		{
dvander@893
   441
			return false;
dvander@893
   442
		}
systematicmania@4256
   443
dvander@893
   444
		prepended = true;
dvander@893
   445
	}
dvander@893
   446
dvander@893
   447
	/* See if we need to do extra string manipulation */
systematicmania@4260
   448
	if (prepended)
dvander@893
   449
	{
dvander@893
   450
		size_t len;
dvander@893
   451
dvander@893
   452
		/* Check if we need to prepend sm_ */
dvander@893
   453
		if (prepended)
dvander@893
   454
		{
dvander@1103
   455
			len = UTIL_Format(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
dvander@893
   456
		} else {
dvander@1103
   457
			len = strncopy(m_ToExecute, args, sizeof(m_ToExecute));
dvander@893
   458
		}
dvander@1103
   459
	} else {
dvander@1103
   460
		strncopy(m_ToExecute, args, sizeof(m_ToExecute));
dvander@893
   461
	}
dvander@893
   462
dvander@893
   463
	return true;
dvander@893
   464
}
dvander@893
   465
januk@4042
   466
cell_t ChatTriggers::CallOnClientSayCommand(int client)
januk@4042
   467
{
januk@4042
   468
	cell_t res = Pl_Continue;
systematicmania@4256
   469
	if (m_pOnClientSayCmd->GetFunctionCount() != 0)
skamonkey@4044
   470
	{
skamonkey@4044
   471
		m_pOnClientSayCmd->PushCell(client);
skamonkey@4044
   472
		m_pOnClientSayCmd->PushString(m_Arg0Backup);
skamonkey@4044
   473
		m_pOnClientSayCmd->PushString(m_ArgSBackup);
skamonkey@4044
   474
		m_pOnClientSayCmd->Execute(&res);
skamonkey@4044
   475
	}
systematicmania@4256
   476
systematicmania@4256
   477
	m_bPluginIgnored = (res >= Pl_Stop);
systematicmania@4256
   478
januk@4042
   479
	return res;
januk@4042
   480
}
januk@4042
   481
dvander@893
   482
unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
dvander@893
   483
{
dvander@893
   484
	unsigned int old = m_ReplyTo;
dvander@893
   485
dvander@893
   486
	m_ReplyTo = reply;
dvander@893
   487
dvander@893
   488
	return old;
dvander@893
   489
}
dvander@893
   490
dvander@893
   491
unsigned int ChatTriggers::GetReplyTo()
dvander@893
   492
{
dvander@893
   493
	return m_ReplyTo;
dvander@893
   494
}
dvander@1469
   495
dvander@1469
   496
bool ChatTriggers::IsChatTrigger()
dvander@1469
   497
{
dvander@1469
   498
	return m_bIsChatTrigger;
dvander@1469
   499
}
dvander@1925
   500
dvander@1925
   501
bool ChatTriggers::ClientIsFlooding(int client)
dvander@1925
   502
{
dvander@1925
   503
	bool is_flooding = false;
dvander@1925
   504
dvander@1925
   505
	if (m_pShouldFloodBlock->GetFunctionCount() != 0)
dvander@1925
   506
	{
dvander@1925
   507
		cell_t res = 0;
dvander@1925
   508
dvander@1925
   509
		m_pShouldFloodBlock->PushCell(client);
dvander@1925
   510
		m_pShouldFloodBlock->Execute(&res);
dvander@1925
   511
dvander@1925
   512
		if (res != 0)
dvander@1925
   513
		{
dvander@1925
   514
			is_flooding = true;
dvander@1925
   515
		}
dvander@1925
   516
	}
dvander@1925
   517
dvander@1925
   518
	if (m_pDidFloodBlock->GetFunctionCount() != 0)
dvander@1925
   519
	{
dvander@1925
   520
		m_pDidFloodBlock->PushCell(client);
dvander@1925
   521
		m_pDidFloodBlock->PushCell(is_flooding ? 1 : 0);
dvander@1925
   522
		m_pDidFloodBlock->Execute(NULL);
dvander@1925
   523
	}
dvander@1925
   524
dvander@1925
   525
	return is_flooding;
dvander@1925
   526
}
dvander@1925
   527
dvander@1925
   528
bool ChatTriggers::WasFloodedMessage()
dvander@1925
   529
{
dvander@1925
   530
	return m_bWasFloodedMessage;
dvander@1925
   531
}