extensions/tf2/natives.cpp
author Kyle Sanderson <kyle.leet@gmail.com>
Mon Aug 12 00:42:56 2013 +0100 (2013-08-12)
changeset 3994 4bc73bac0f4c
parent 3818 f25d64a5cd7a
child 4158 ec9737f0382a
permissions -rw-r--r--
Added helper stock to check if a command exists. (bug 5510, r=asherkin)
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Team Fortress 2 Extension
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "extension.h"
    33 #include "util.h"
    34 #include "time.h"
    35 #include "RegNatives.h"
    36 
    37 // native TF2_MakeBleed(client, attacker, Float:duration)
    38 cell_t TF2_MakeBleed(IPluginContext *pContext, const cell_t *params)
    39 {
    40 	static ICallWrapper *pWrapper = NULL;
    41 
    42 	// CTFPlayerShared::MakeBleed(CTFPlayer*, CTFWeaponBase*, float, int=4)
    43 	if(!pWrapper)
    44 	{
    45 		REGISTER_NATIVE_ADDR("MakeBleed",
    46 			PassInfo pass[4]; \
    47 			pass[0].flags = PASSFLAG_BYVAL; \
    48 			pass[0].size = sizeof(CBaseEntity *); \
    49 			pass[0].type = PassType_Basic; \
    50 			pass[1].flags = PASSFLAG_BYVAL; \
    51 			pass[1].size = sizeof(CBaseEntity *); \
    52 			pass[1].type = PassType_Basic; \
    53 			pass[2].flags = PASSFLAG_BYVAL; \
    54 			pass[2].size = sizeof(float); \
    55 			pass[2].type = PassType_Basic; \
    56 			pass[3].flags = PASSFLAG_BYVAL; \
    57 			pass[3].size = sizeof(int); \
    58 			pass[3].type = PassType_Basic; \
    59 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 4))
    60 	}
    61 
    62 	CBaseEntity *pEntity;
    63 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
    64 	{
    65 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
    66 	}
    67 
    68 	CBaseEntity *pAttacker;
    69 	if (!(pAttacker = UTIL_GetCBaseEntity(params[2], true)))
    70 	{
    71 		return pContext->ThrowNativeError("Client index %d is not valid", params[2]);
    72 	}
    73 
    74 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
    75 
    76 	unsigned char vstk[sizeof(void *) + 2*sizeof(CBaseEntity *) + sizeof(float)];
    77 	unsigned char *vptr = vstk;
    78 
    79 	*(void **)vptr = obj;
    80 	vptr += sizeof(void *);
    81 	*(CBaseEntity **)vptr = pAttacker;
    82 	vptr += sizeof(CBaseEntity *);
    83 	*(CBaseEntity **)vptr = NULL;
    84 	vptr += sizeof(CBaseEntity *);
    85 	*(float *)vptr = sp_ctof(params[3]);
    86 	vptr += sizeof(float);
    87 	*(int *)vptr = 4;
    88 
    89 	pWrapper->Execute(vstk, NULL);
    90 
    91 	return 1;
    92 }
    93 
    94 // native TF2_Burn(client, target)
    95 cell_t TF2_Burn(IPluginContext *pContext, const cell_t *params)
    96 {
    97 	static ICallWrapper *pWrapper = NULL;
    98 
    99 	// CTFPlayerShared::Burn(CTFPlayer*, CTFWeaponBase*)
   100 	if (!pWrapper)
   101 	{
   102 		REGISTER_NATIVE_ADDR("Burn", 
   103 			PassInfo pass[2]; \
   104 			pass[0].flags = PASSFLAG_BYVAL; \
   105 			pass[0].size = sizeof(CBaseEntity *); \
   106 			pass[0].type = PassType_Basic; \
   107 			pass[1].flags = PASSFLAG_BYVAL; \
   108 			pass[1].size = sizeof(CBaseEntity *); \
   109 			pass[1].type = PassType_Basic; \
   110 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
   111 	}
   112 
   113 	CBaseEntity *pEntity;
   114 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   115 	{
   116 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   117 	}
   118 
   119 	CBaseEntity *pTarget;
   120 	if (!(pTarget = UTIL_GetCBaseEntity(params[2], true)))
   121 	{
   122 		return pContext->ThrowNativeError("Client index %d is not valid", params[2]);
   123 	}
   124 
   125 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   126 
   127 	unsigned char vstk[sizeof(void *) + 2*sizeof(CBaseEntity *)];
   128 	unsigned char *vptr = vstk;
   129 
   130 	*(void **)vptr = obj;
   131 	vptr += sizeof(void *);
   132 	*(CBaseEntity **)vptr = pTarget;
   133 	vptr += sizeof(CBaseEntity *);
   134 	*(CBaseEntity **)vptr = NULL;
   135 
   136 	pWrapper->Execute(vstk, NULL);
   137 
   138 	return 1;
   139 }
   140 
   141 // native TF2_Invuln(client, bool:enabled)
   142 cell_t TF2_Invuln(IPluginContext *pContext, const cell_t *params)
   143 {
   144 	return pContext->ThrowNativeError("TF2_SetPlayerInvuln is no longer available");
   145 }
   146 
   147 cell_t TF2_Disguise(IPluginContext *pContext, const cell_t *params)
   148 {
   149 	static ICallWrapper *pWrapper = NULL;
   150 
   151 	//CTFPlayerShared::Disguise(int, int, CTFPlayer *)
   152 	if (!pWrapper)
   153 	{
   154 		REGISTER_NATIVE_ADDR("Disguise", 
   155 			PassInfo pass[4]; \
   156 			pass[0].flags = PASSFLAG_BYVAL; \
   157 			pass[0].size = sizeof(int); \
   158 			pass[0].type = PassType_Basic; \
   159 			pass[1].flags = PASSFLAG_BYVAL; \
   160 			pass[1].size = sizeof(int); \
   161 			pass[1].type = PassType_Basic; \
   162 			pass[2].flags = PASSFLAG_BYVAL; \
   163 			pass[2].size = sizeof(CBaseEntity *); \
   164 			pass[2].type = PassType_Basic; \
   165 			pass[3].flags = PASSFLAG_BYVAL; \
   166 			pass[3].size = sizeof(bool); \
   167 			pass[3].type = PassType_Basic; \
   168 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 4))
   169 	}
   170 
   171 	CBaseEntity *pEntity;
   172 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   173 	{
   174 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   175 	}
   176 
   177 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   178 	
   179 	CBaseEntity *pTarget = NULL;
   180 	// Compatibility fix for the newly-added target parameter
   181 	if (params[0] >= 4 && params[4] > 0 && !(pTarget = UTIL_GetCBaseEntity(params[4], true)))
   182 	{
   183 		return pContext->ThrowNativeError("Target client index %d is not valid", params[4]);
   184 	}
   185 
   186 	unsigned char vstk[sizeof(void *) + 2*sizeof(int) + sizeof(bool)];
   187 	unsigned char *vptr = vstk;
   188 
   189 
   190 	*(void **)vptr = obj;
   191 	vptr += sizeof(void *);
   192 	*(int *)vptr = params[2];
   193 	vptr += sizeof(int);
   194 	*(int *)vptr = params[3];
   195 	vptr += sizeof(int);
   196 	*(CBaseEntity **)vptr = pTarget;
   197 	vptr += sizeof(CBaseEntity *);
   198 	*(bool *)vptr = true;
   199 	
   200 	pWrapper->Execute(vstk, NULL);
   201 
   202 	return 1;
   203 }
   204 
   205 cell_t TF2_RemoveDisguise(IPluginContext *pContext, const cell_t *params)
   206 {
   207 	static ICallWrapper *pWrapper = NULL;
   208 
   209 	//CTFPlayerShared::RemoveDisguise()
   210 	if (!pWrapper)
   211 	{
   212 		REGISTER_NATIVE_ADDR("RemoveDisguise", 
   213 				pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0))
   214 	}
   215 
   216 	CBaseEntity *pEntity;
   217 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   218 	{
   219 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   220 	}
   221 
   222 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   223 
   224 	unsigned char vstk[sizeof(void *)];
   225 	unsigned char *vptr = vstk;
   226 
   227 
   228 	*(void **)vptr = obj;
   229 
   230 	pWrapper->Execute(vstk, NULL);
   231 
   232 	return 1;
   233 }
   234 
   235 cell_t TF2_AddCondition(IPluginContext *pContext, const cell_t *params)
   236 {
   237 	static ICallWrapper *pWrapper = NULL;
   238 
   239 	// CTFPlayerShared::AddCond(int, float, CBaseEntity *)
   240 	if (!pWrapper)
   241 	{
   242 		REGISTER_NATIVE_ADDR("AddCondition", 
   243 			PassInfo pass[3]; \
   244 			pass[0].flags = PASSFLAG_BYVAL; \
   245 			pass[0].size = sizeof(int); \
   246 			pass[0].type = PassType_Basic; \
   247 			pass[1].flags = PASSFLAG_BYVAL; \
   248 			pass[1].size = sizeof(float); \
   249 			pass[1].type = PassType_Basic; \
   250 			pass[2].flags = PASSFLAG_BYVAL; \
   251 			pass[2].size = sizeof(CBaseEntity *); \
   252 			pass[2].type = PassType_Basic; \
   253 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 3))
   254 	}
   255 
   256 	CBaseEntity *pEntity;
   257 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   258 	{
   259 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   260 	}
   261 
   262 	CBaseEntity *pInflictor = NULL;
   263 	// Compatibility fix for the new inflictor parameter; TF2 seems to only use player entities in it
   264 	if (params[0] >= 4 && params[4] > 0 && !(pInflictor = UTIL_GetCBaseEntity(params[4], true)))
   265 	{
   266 		return pContext->ThrowNativeError("Inflictor index %d is not valid", params[4]);
   267 	}
   268 
   269 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   270 
   271 	unsigned char vstk[sizeof(void *) + sizeof(int) + sizeof(float) + sizeof(CBaseEntity *)];
   272 	unsigned char *vptr = vstk;
   273 
   274 	*(void **)vptr = obj;
   275 	vptr += sizeof(void *);
   276 	*(int *)vptr = params[2];
   277 	vptr += sizeof(int);
   278 	*(float *)vptr = *(float *)&params[3];
   279 	vptr += sizeof(float);
   280 	*(CBaseEntity **)vptr = pInflictor;
   281 
   282 	pWrapper->Execute(vstk, NULL);
   283 
   284 	return 1;
   285 }
   286 
   287 cell_t TF2_RemoveCondition(IPluginContext *pContext, const cell_t *params)
   288 {
   289 	static ICallWrapper *pWrapper = NULL;
   290 
   291 	// CTFPlayerShared::RemoveCond(int, bool)
   292 	if (!pWrapper)
   293 	{
   294 		REGISTER_NATIVE_ADDR("RemoveCondition", 
   295 			PassInfo pass[2]; \
   296 			pass[0].flags = PASSFLAG_BYVAL; \
   297 			pass[0].size = sizeof(int); \
   298 			pass[0].type = PassType_Basic; \
   299 			pass[1].flags = PASSFLAG_BYVAL; \
   300 			pass[1].size = sizeof(bool); \
   301 			pass[1].type = PassType_Basic; \
   302 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
   303 	}
   304 
   305 	CBaseEntity *pEntity;
   306 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   307 	{
   308 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   309 	}
   310 
   311 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   312 
   313 	unsigned char vstk[sizeof(void *) + sizeof(int) + sizeof(bool)];
   314 	unsigned char *vptr = vstk;
   315 
   316 	*(void **)vptr = obj;
   317 	vptr += sizeof(void *);
   318 	*(int *)vptr = params[2];
   319 	vptr += sizeof(int);
   320 	*(bool *)vptr = true;
   321 
   322 	pWrapper->Execute(vstk, NULL);
   323 
   324 	return 1;
   325 }
   326 
   327 cell_t TF2_StunPlayer(IPluginContext *pContext, const cell_t *params)
   328 {
   329 	static ICallWrapper *pWrapper = NULL;
   330 
   331 	// CTFPlayerShared::StunPlayer(float, float, int, CTFPlayer *)
   332 	if (!pWrapper)
   333 	{
   334 		REGISTER_NATIVE_ADDR("StunPlayer", 
   335 			PassInfo pass[4]; \
   336 			pass[0].flags = PASSFLAG_BYVAL; \
   337 			pass[0].size = sizeof(float); \
   338 			pass[0].type = PassType_Basic; \
   339 			pass[1].flags = PASSFLAG_BYVAL; \
   340 			pass[1].size = sizeof(float); \
   341 			pass[1].type = PassType_Basic; \
   342 			pass[2].flags = PASSFLAG_BYVAL; \
   343 			pass[2].size = sizeof(int); \
   344 			pass[2].type = PassType_Basic; \
   345 			pass[3].flags = PASSFLAG_BYVAL; \
   346 			pass[3].size = sizeof(CBaseEntity *); \
   347 			pass[3].type = PassType_Basic; \
   348 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 4))
   349 	}
   350 
   351 	CBaseEntity *pEntity;
   352 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   353 	{
   354 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   355 	}
   356 
   357 	bool bByPlayer = (params[5] != 0);
   358 	CBaseEntity *pAttacker = NULL;
   359 	if (bByPlayer && !(pAttacker = UTIL_GetCBaseEntity(params[5], true)))
   360 	{
   361 		return pContext->ThrowNativeError("Attacker index %d is not valid", params[5]);
   362 	}
   363 
   364 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   365 
   366 	unsigned char vstk[sizeof(void *) + 2*sizeof(float) + sizeof(int) + sizeof(CBaseEntity *)];
   367 	unsigned char *vptr = vstk;
   368 
   369 	*(void **)vptr = obj;
   370 	vptr += sizeof(void *);
   371 	*(float *)vptr = sp_ctof(params[2]);
   372 	vptr += sizeof(float);
   373 	*(float *)vptr = sp_ctof(params[3]);
   374 	vptr += sizeof(float);
   375 	*(int *)vptr = params[4];
   376 	vptr += sizeof(int);
   377 	*(CBaseEntity **)vptr = pAttacker;
   378 
   379 	pWrapper->Execute(vstk, NULL);
   380 
   381 	return 1;
   382 }
   383 
   384 cell_t TF2_SetPowerplayEnabled(IPluginContext *pContext, const cell_t *params)
   385 {
   386 	static ICallWrapper *pWrapper = NULL;
   387 
   388 	// CTFPlayer::SetPowerPlayEnabled(bool)
   389 	if (!pWrapper)
   390 	{
   391 		REGISTER_NATIVE_ADDR("SetPowerplayEnabled", 
   392 			PassInfo pass[1]; \
   393 			pass[0].flags = PASSFLAG_BYVAL; \
   394 			pass[0].size = sizeof(bool); \
   395 			pass[0].type = PassType_Basic; \
   396 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 1))
   397 	}
   398 
   399 	CBaseEntity *pEntity;
   400 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   401 	{
   402 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   403 	}
   404 
   405 	bool bEnablePP = false;
   406 	if (params[2] != 0)
   407 	{
   408 		bEnablePP = true;
   409 	}
   410 
   411 	unsigned char vstk[sizeof(void *) + sizeof(bool)];
   412 	unsigned char *vptr = vstk;
   413 
   414 	*(void **)vptr = (void *)pEntity;
   415 	vptr += sizeof(void *);
   416 	*(bool *)vptr = bEnablePP;
   417 
   418 	pWrapper->Execute(vstk, NULL);
   419 
   420 	return 1;
   421 }
   422 
   423 cell_t TF2_Respawn(IPluginContext *pContext, const cell_t *params)
   424 {
   425 	static ICallWrapper *pWrapper = NULL;
   426 
   427 	//CTFPlayer::ForceRespawn()
   428 
   429 	if (!pWrapper)
   430 	{
   431 		int offset;
   432 
   433 		if (!g_pGameConf->GetOffset("ForceRespawn", &offset))
   434 		{
   435 			return pContext->ThrowNativeError("Failed to locate function");
   436 		}
   437 
   438 		pWrapper = g_pBinTools->CreateVCall(offset,
   439 											0,
   440 											0,
   441 											NULL,
   442 											NULL,
   443 											0);
   444 
   445 		g_RegNatives.Register(pWrapper);
   446 	}
   447 
   448 	CBaseEntity *pEntity;
   449 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   450 	{
   451 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   452 	}
   453 
   454 	unsigned char vstk[sizeof(void *)];
   455 	unsigned char *vptr = vstk;
   456 
   457 
   458 	*(void **)vptr = (void *)pEntity;
   459 
   460 	pWrapper->Execute(vstk, NULL);
   461 
   462 	return 1;
   463 }
   464 
   465 cell_t TF2_Regenerate(IPluginContext *pContext, const cell_t *params)
   466 {
   467 	static ICallWrapper *pWrapper = NULL;
   468 
   469 	//CTFPlayer::Regenerate( bool=true )
   470 
   471 	if (!pWrapper)
   472 	{
   473 		REGISTER_NATIVE_ADDR("Regenerate", 
   474 			PassInfo pass[1]; \
   475 			pass[0].flags = PASSFLAG_BYVAL; \
   476 			pass[0].size = sizeof(bool); \
   477 			pass[0].type = PassType_Basic; \
   478 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 1))
   479 	}
   480 
   481 	CBaseEntity *pEntity;
   482 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   483 	{
   484 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   485 	}
   486 	
   487 	unsigned char vstk[sizeof(void *) + sizeof(bool)];
   488 	unsigned char *vptr = vstk;
   489 
   490 	*(void **)vptr = (void *)pEntity;
   491 	vptr += sizeof(void *);
   492 	*(bool *)vptr = true;
   493 
   494 	pWrapper->Execute(vstk, NULL);
   495 
   496 	return 1;
   497 }
   498 
   499 cell_t TF2_GetResourceEntity(IPluginContext *pContext, const cell_t *params)
   500 {
   501 	return g_resourceEntity;
   502 }
   503 
   504 cell_t TF2_GetClass(IPluginContext *pContext, const cell_t *params)
   505 {
   506 	char *str;
   507 	pContext->LocalToString(params[1], &str);
   508 
   509 	return (cell_t)ClassnameToType(str);
   510 }
   511 
   512 // native TF2_IsPlayerInDuel(client)
   513 cell_t TF2_IsPlayerInDuel(IPluginContext *pContext, const cell_t *params)
   514 {
   515 	static ICallWrapper *pWrapper = NULL;
   516 
   517 	// DuelMiniGame_IsPlayerInDuel(CTFPlayer *)
   518 	if (!pWrapper)
   519 	{
   520 		REGISTER_NATIVE_ADDR("IsPlayerInDuel", 
   521 			PassInfo pass[1]; \
   522 			pass[0].flags = PASSFLAG_BYVAL; \
   523 			pass[0].size = sizeof(CBaseEntity *); \
   524 			pass[0].type = PassType_Basic; \
   525 			PassInfo ret; \
   526 			ret.flags = PASSFLAG_BYVAL; \
   527 			ret.size = sizeof(bool); \
   528 			ret.type = PassType_Basic; \
   529 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &ret, pass, 1))
   530 	}
   531 
   532 	CBaseEntity *pPlayer;
   533 	if (!(pPlayer = UTIL_GetCBaseEntity(params[1], true)))
   534 	{
   535 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   536 	}
   537 
   538 	unsigned char vstk[sizeof(CBaseEntity *)];
   539 	unsigned char *vptr = vstk;
   540 	*(CBaseEntity **)vptr = pPlayer;
   541 
   542 	bool retValue;
   543 	pWrapper->Execute(vstk, &retValue);
   544 
   545 	return (retValue) ? 1 : 0;
   546 }
   547 
   548 sp_nativeinfo_t g_TFNatives[] = 
   549 {
   550 	{"TF2_IgnitePlayer",			TF2_Burn},
   551 	{"TF2_SetPlayerInvuln",			TF2_Invuln},
   552 	{"TF2_RespawnPlayer",			TF2_Respawn},
   553 	{"TF2_DisguisePlayer",			TF2_Disguise},
   554 	{"TF2_RemovePlayerDisguise",	TF2_RemoveDisguise},
   555 	{"TF2_GetResourceEntity",		TF2_GetResourceEntity},
   556 	{"TF2_GetClass",				TF2_GetClass},
   557 	{"TF2_RegeneratePlayer",		TF2_Regenerate},
   558 	{"TF2_AddCondition",			TF2_AddCondition},
   559 	{"TF2_RemoveCondition",			TF2_RemoveCondition},
   560 	{"TF2_SetPlayerPowerPlay",		TF2_SetPowerplayEnabled},
   561 	{"TF2_StunPlayer",				TF2_StunPlayer},
   562 	{"TF2_MakeBleed",				TF2_MakeBleed},
   563 	{"TF2_IsPlayerInDuel",				TF2_IsPlayerInDuel},
   564 	{NULL,							NULL}
   565 };