extensions/tf2/natives.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Wed Dec 19 07:55:03 2012 -0500 (2012-12-19)
changeset 3713 a825343bb3f2
parent 3606 e75ddff9d0b9
child 3818 f25d64a5cd7a
permissions -rw-r--r--
Added new param for CTFPlayerShared::AddCond call in TF2 ext.
     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)
   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 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   263 
   264 	unsigned char vstk[sizeof(void *) + sizeof(int) + sizeof(float) + sizeof(CBaseEntity *)];
   265 	unsigned char *vptr = vstk;
   266 
   267 	*(void **)vptr = obj;
   268 	vptr += sizeof(void *);
   269 	*(int *)vptr = params[2];
   270 	vptr += sizeof(int);
   271 	*(float *)vptr = *(float *)&params[3];
   272 	vptr += sizeof(float);
   273 	*(CBaseEntity **)vptr = NULL;
   274 
   275 	pWrapper->Execute(vstk, NULL);
   276 
   277 	return 1;
   278 }
   279 
   280 cell_t TF2_RemoveCondition(IPluginContext *pContext, const cell_t *params)
   281 {
   282 	static ICallWrapper *pWrapper = NULL;
   283 
   284 	// CTFPlayerShared::RemoveCond(int, bool)
   285 	if (!pWrapper)
   286 	{
   287 		REGISTER_NATIVE_ADDR("RemoveCondition", 
   288 			PassInfo pass[2]; \
   289 			pass[0].flags = PASSFLAG_BYVAL; \
   290 			pass[0].size = sizeof(int); \
   291 			pass[0].type = PassType_Basic; \
   292 			pass[1].flags = PASSFLAG_BYVAL; \
   293 			pass[1].size = sizeof(bool); \
   294 			pass[1].type = PassType_Basic; \
   295 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
   296 	}
   297 
   298 	CBaseEntity *pEntity;
   299 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   300 	{
   301 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   302 	}
   303 
   304 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   305 
   306 	unsigned char vstk[sizeof(void *) + sizeof(int) + sizeof(bool)];
   307 	unsigned char *vptr = vstk;
   308 
   309 	*(void **)vptr = obj;
   310 	vptr += sizeof(void *);
   311 	*(int *)vptr = params[2];
   312 	vptr += sizeof(int);
   313 	*(bool *)vptr = true;
   314 
   315 	pWrapper->Execute(vstk, NULL);
   316 
   317 	return 1;
   318 }
   319 
   320 cell_t TF2_StunPlayer(IPluginContext *pContext, const cell_t *params)
   321 {
   322 	static ICallWrapper *pWrapper = NULL;
   323 
   324 	// CTFPlayerShared::StunPlayer(float, float, int, CTFPlayer *)
   325 	if (!pWrapper)
   326 	{
   327 		REGISTER_NATIVE_ADDR("StunPlayer", 
   328 			PassInfo pass[4]; \
   329 			pass[0].flags = PASSFLAG_BYVAL; \
   330 			pass[0].size = sizeof(float); \
   331 			pass[0].type = PassType_Basic; \
   332 			pass[1].flags = PASSFLAG_BYVAL; \
   333 			pass[1].size = sizeof(float); \
   334 			pass[1].type = PassType_Basic; \
   335 			pass[2].flags = PASSFLAG_BYVAL; \
   336 			pass[2].size = sizeof(int); \
   337 			pass[2].type = PassType_Basic; \
   338 			pass[3].flags = PASSFLAG_BYVAL; \
   339 			pass[3].size = sizeof(CBaseEntity *); \
   340 			pass[3].type = PassType_Basic; \
   341 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 4))
   342 	}
   343 
   344 	CBaseEntity *pEntity;
   345 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   346 	{
   347 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   348 	}
   349 
   350 	bool bByPlayer = (params[5] != 0);
   351 	CBaseEntity *pAttacker = NULL;
   352 	if (bByPlayer && !(pAttacker = UTIL_GetCBaseEntity(params[5], true)))
   353 	{
   354 		return pContext->ThrowNativeError("Attacker index %d is not valid", params[5]);
   355 	}
   356 
   357 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   358 
   359 	unsigned char vstk[sizeof(void *) + 2*sizeof(float) + sizeof(int) + sizeof(CBaseEntity *)];
   360 	unsigned char *vptr = vstk;
   361 
   362 	*(void **)vptr = obj;
   363 	vptr += sizeof(void *);
   364 	*(float *)vptr = sp_ctof(params[2]);
   365 	vptr += sizeof(float);
   366 	*(float *)vptr = sp_ctof(params[3]);
   367 	vptr += sizeof(float);
   368 	*(int *)vptr = params[4];
   369 	vptr += sizeof(int);
   370 	*(CBaseEntity **)vptr = pAttacker;
   371 
   372 	pWrapper->Execute(vstk, NULL);
   373 
   374 	return 1;
   375 }
   376 
   377 cell_t TF2_SetPowerplayEnabled(IPluginContext *pContext, const cell_t *params)
   378 {
   379 	static ICallWrapper *pWrapper = NULL;
   380 
   381 	// CTFPlayer::SetPowerPlayEnabled(bool)
   382 	if (!pWrapper)
   383 	{
   384 		REGISTER_NATIVE_ADDR("SetPowerplayEnabled", 
   385 			PassInfo pass[1]; \
   386 			pass[0].flags = PASSFLAG_BYVAL; \
   387 			pass[0].size = sizeof(bool); \
   388 			pass[0].type = PassType_Basic; \
   389 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 1))
   390 	}
   391 
   392 	CBaseEntity *pEntity;
   393 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   394 	{
   395 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   396 	}
   397 
   398 	bool bEnablePP = false;
   399 	if (params[2] != 0)
   400 	{
   401 		bEnablePP = true;
   402 	}
   403 
   404 	unsigned char vstk[sizeof(void *) + sizeof(bool)];
   405 	unsigned char *vptr = vstk;
   406 
   407 	*(void **)vptr = (void *)pEntity;
   408 	vptr += sizeof(void *);
   409 	*(bool *)vptr = bEnablePP;
   410 
   411 	pWrapper->Execute(vstk, NULL);
   412 
   413 	return 1;
   414 }
   415 
   416 cell_t TF2_Respawn(IPluginContext *pContext, const cell_t *params)
   417 {
   418 	static ICallWrapper *pWrapper = NULL;
   419 
   420 	//CTFPlayer::ForceRespawn()
   421 
   422 	if (!pWrapper)
   423 	{
   424 		int offset;
   425 
   426 		if (!g_pGameConf->GetOffset("ForceRespawn", &offset))
   427 		{
   428 			return pContext->ThrowNativeError("Failed to locate function");
   429 		}
   430 
   431 		pWrapper = g_pBinTools->CreateVCall(offset,
   432 											0,
   433 											0,
   434 											NULL,
   435 											NULL,
   436 											0);
   437 
   438 		g_RegNatives.Register(pWrapper);
   439 	}
   440 
   441 	CBaseEntity *pEntity;
   442 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   443 	{
   444 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   445 	}
   446 
   447 	unsigned char vstk[sizeof(void *)];
   448 	unsigned char *vptr = vstk;
   449 
   450 
   451 	*(void **)vptr = (void *)pEntity;
   452 
   453 	pWrapper->Execute(vstk, NULL);
   454 
   455 	return 1;
   456 }
   457 
   458 cell_t TF2_Regenerate(IPluginContext *pContext, const cell_t *params)
   459 {
   460 	static ICallWrapper *pWrapper = NULL;
   461 
   462 	//CTFPlayer::Regenerate( bool=true )
   463 
   464 	if (!pWrapper)
   465 	{
   466 		REGISTER_NATIVE_ADDR("Regenerate", 
   467 			PassInfo pass[1]; \
   468 			pass[0].flags = PASSFLAG_BYVAL; \
   469 			pass[0].size = sizeof(bool); \
   470 			pass[0].type = PassType_Basic; \
   471 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 1))
   472 	}
   473 
   474 	CBaseEntity *pEntity;
   475 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   476 	{
   477 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   478 	}
   479 	
   480 	unsigned char vstk[sizeof(void *) + sizeof(bool)];
   481 	unsigned char *vptr = vstk;
   482 
   483 	*(void **)vptr = (void *)pEntity;
   484 	vptr += sizeof(void *);
   485 	*(bool *)vptr = true;
   486 
   487 	pWrapper->Execute(vstk, NULL);
   488 
   489 	return 1;
   490 }
   491 
   492 cell_t TF2_GetResourceEntity(IPluginContext *pContext, const cell_t *params)
   493 {
   494 	return g_resourceEntity;
   495 }
   496 
   497 cell_t TF2_GetClass(IPluginContext *pContext, const cell_t *params)
   498 {
   499 	char *str;
   500 	pContext->LocalToString(params[1], &str);
   501 
   502 	return (cell_t)ClassnameToType(str);
   503 }
   504 
   505 // native TF2_IsPlayerInDuel(client)
   506 cell_t TF2_IsPlayerInDuel(IPluginContext *pContext, const cell_t *params)
   507 {
   508 	static ICallWrapper *pWrapper = NULL;
   509 
   510 	// DuelMiniGame_IsPlayerInDuel(CTFPlayer *)
   511 	if (!pWrapper)
   512 	{
   513 		REGISTER_NATIVE_ADDR("IsPlayerInDuel", 
   514 			PassInfo pass[1]; \
   515 			pass[0].flags = PASSFLAG_BYVAL; \
   516 			pass[0].size = sizeof(CBaseEntity *); \
   517 			pass[0].type = PassType_Basic; \
   518 			PassInfo ret; \
   519 			ret.flags = PASSFLAG_BYVAL; \
   520 			ret.size = sizeof(bool); \
   521 			ret.type = PassType_Basic; \
   522 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &ret, pass, 1))
   523 	}
   524 
   525 	CBaseEntity *pPlayer;
   526 	if (!(pPlayer = UTIL_GetCBaseEntity(params[1], true)))
   527 	{
   528 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   529 	}
   530 
   531 	unsigned char vstk[sizeof(CBaseEntity *)];
   532 	unsigned char *vptr = vstk;
   533 	*(CBaseEntity **)vptr = pPlayer;
   534 
   535 	bool retValue;
   536 	pWrapper->Execute(vstk, &retValue);
   537 
   538 	return (retValue) ? 1 : 0;
   539 }
   540 
   541 sp_nativeinfo_t g_TFNatives[] = 
   542 {
   543 	{"TF2_IgnitePlayer",			TF2_Burn},
   544 	{"TF2_SetPlayerInvuln",			TF2_Invuln},
   545 	{"TF2_RespawnPlayer",			TF2_Respawn},
   546 	{"TF2_DisguisePlayer",			TF2_Disguise},
   547 	{"TF2_RemovePlayerDisguise",	TF2_RemoveDisguise},
   548 	{"TF2_GetResourceEntity",		TF2_GetResourceEntity},
   549 	{"TF2_GetClass",				TF2_GetClass},
   550 	{"TF2_RegeneratePlayer",		TF2_Regenerate},
   551 	{"TF2_AddCondition",			TF2_AddCondition},
   552 	{"TF2_RemoveCondition",			TF2_RemoveCondition},
   553 	{"TF2_SetPlayerPowerPlay",		TF2_SetPowerplayEnabled},
   554 	{"TF2_StunPlayer",				TF2_StunPlayer},
   555 	{"TF2_MakeBleed",				TF2_MakeBleed},
   556 	{"TF2_IsPlayerInDuel",				TF2_IsPlayerInDuel},
   557 	{NULL,							NULL}
   558 };