extensions/tf2/natives.cpp
author A.W. Stanley <tf2@swixel.net>
Sun Nov 07 19:05:32 2010 -0500 (2010-11-07)
changeset 3147 b6db3d09eb79
parent 3128 337f190aaf4b
child 3255 328938c6ca59
permissions -rw-r--r--
Added TF2_IsPlayerInDuel native to TF2 extension (bug 4695, r=psychonic).
     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, victim, 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)
    43 	if(!pWrapper)
    44 	{
    45 		REGISTER_NATIVE_ADDR("MakeBleed",
    46 			PassInfo pass[3]; \
    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 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 3))
    57 	}
    58 
    59 	CBaseEntity *pEntity;
    60 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
    61 	{
    62 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
    63 	}
    64 
    65 	CBaseEntity *pTarget;
    66 	if (!(pTarget = UTIL_GetCBaseEntity(params[2], true)))
    67 	{
    68 		return pContext->ThrowNativeError("Client index %d is not valid", params[2]);
    69 	}
    70 
    71 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
    72 
    73 	unsigned char vstk[sizeof(void *) + 2*sizeof(CBaseEntity *) + sizeof(float)];
    74 	unsigned char *vptr = vstk;
    75 
    76 	*(void **)vptr = obj;
    77 	vptr += sizeof(void *);
    78 	*(CBaseEntity **)vptr = pTarget;
    79 	vptr += sizeof(CBaseEntity *);
    80 	*(CBaseEntity **)vptr = NULL;
    81 	vptr += sizeof(CBaseEntity *);
    82 	*(float *)vptr = sp_ctof(params[3]);
    83 
    84 	pWrapper->Execute(vstk, NULL);
    85 
    86 	return 1;
    87 }
    88 
    89 // native TF2_Burn(client, target)
    90 cell_t TF2_Burn(IPluginContext *pContext, const cell_t *params)
    91 {
    92 	static ICallWrapper *pWrapper = NULL;
    93 
    94 	// CTFPlayerShared::Burn(CTFPlayer*, CTFWeaponBase*)
    95 	if (!pWrapper)
    96 	{
    97 		REGISTER_NATIVE_ADDR("Burn", 
    98 			PassInfo pass[2]; \
    99 			pass[0].flags = PASSFLAG_BYVAL; \
   100 			pass[0].size = sizeof(CBaseEntity *); \
   101 			pass[0].type = PassType_Basic; \
   102 			pass[1].flags = PASSFLAG_BYVAL; \
   103 			pass[1].size = sizeof(CBaseEntity *); \
   104 			pass[1].type = PassType_Basic; \
   105 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
   106 	}
   107 
   108 	CBaseEntity *pEntity;
   109 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   110 	{
   111 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   112 	}
   113 
   114 	CBaseEntity *pTarget;
   115 	if (!(pTarget = UTIL_GetCBaseEntity(params[2], true)))
   116 	{
   117 		return pContext->ThrowNativeError("Client index %d is not valid", params[2]);
   118 	}
   119 
   120 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   121 
   122 	unsigned char vstk[sizeof(void *) + 2*sizeof(CBaseEntity *)];
   123 	unsigned char *vptr = vstk;
   124 
   125 	*(void **)vptr = obj;
   126 	vptr += sizeof(void *);
   127 	*(CBaseEntity **)vptr = pTarget;
   128 	vptr += sizeof(CBaseEntity *);
   129 	*(CBaseEntity **)vptr = NULL;
   130 
   131 	pWrapper->Execute(vstk, NULL);
   132 
   133 	return 1;
   134 }
   135 
   136 // native TF2_Invuln(client, bool:enabled)
   137 cell_t TF2_Invuln(IPluginContext *pContext, const cell_t *params)
   138 {
   139 	return pContext->ThrowNativeError("TF2_SetPlayerInvuln is no longer available");
   140 }
   141 
   142 cell_t TF2_Disguise(IPluginContext *pContext, const cell_t *params)
   143 {
   144 	static ICallWrapper *pWrapper = NULL;
   145 
   146 	//CTFPlayerShared::Disguise(int, int, CTFPlayer *)
   147 	if (!pWrapper)
   148 	{
   149 		REGISTER_NATIVE_ADDR("Disguise", 
   150 			PassInfo pass[3]; \
   151 			pass[0].flags = PASSFLAG_BYVAL; \
   152 			pass[0].size = sizeof(int); \
   153 			pass[0].type = PassType_Basic; \
   154 			pass[1].flags = PASSFLAG_BYVAL; \
   155 			pass[1].size = sizeof(int); \
   156 			pass[1].type = PassType_Basic; \
   157 			pass[2].flags = PASSFLAG_BYVAL; \
   158 			pass[2].size = sizeof(CBaseEntity *); \
   159 			pass[2].type = PassType_Basic; \
   160 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 3))
   161 	}
   162 
   163 	CBaseEntity *pEntity;
   164 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   165 	{
   166 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   167 	}
   168 
   169 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   170 	
   171 	CBaseEntity *pTarget = NULL;
   172 	// Compatibility fix for the newly-added target parameter
   173 	if (params[0] >= 4 && params[4] > 0 && !(pTarget = UTIL_GetCBaseEntity(params[4], true)))
   174 	{
   175 		return pContext->ThrowNativeError("Target client index %d is not valid", params[1]);
   176 	}
   177 
   178 	unsigned char vstk[sizeof(void *) + 2*sizeof(int)];
   179 	unsigned char *vptr = vstk;
   180 
   181 
   182 	*(void **)vptr = obj;
   183 	vptr += sizeof(void *);
   184 	*(int *)vptr = params[2];
   185 	vptr += sizeof(int);
   186 	*(int *)vptr = params[3];
   187 	vptr += sizeof(int);
   188 	*(CBaseEntity **)vptr = pTarget;
   189 
   190 	pWrapper->Execute(vstk, NULL);
   191 
   192 	return 1;
   193 }
   194 
   195 cell_t TF2_RemoveDisguise(IPluginContext *pContext, const cell_t *params)
   196 {
   197 	static ICallWrapper *pWrapper = NULL;
   198 
   199 	//CTFPlayerShared::RemoveDisguise()
   200 	if (!pWrapper)
   201 	{
   202 		REGISTER_NATIVE_ADDR("RemoveDisguise", 
   203 				pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0))
   204 	}
   205 
   206 	CBaseEntity *pEntity;
   207 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   208 	{
   209 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   210 	}
   211 
   212 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   213 
   214 	unsigned char vstk[sizeof(void *)];
   215 	unsigned char *vptr = vstk;
   216 
   217 
   218 	*(void **)vptr = obj;
   219 
   220 	pWrapper->Execute(vstk, NULL);
   221 
   222 	return 1;
   223 }
   224 
   225 cell_t TF2_AddCondition(IPluginContext *pContext, const cell_t *params)
   226 {
   227 	static ICallWrapper *pWrapper = NULL;
   228 
   229 	// CTFPlayerShared::AddCond(int, float)
   230 	if (!pWrapper)
   231 	{
   232 		REGISTER_NATIVE_ADDR("AddCondition", 
   233 			PassInfo pass[2]; \
   234 			pass[0].flags = PASSFLAG_BYVAL; \
   235 			pass[0].size = sizeof(int); \
   236 			pass[0].type = PassType_Basic; \
   237 			pass[1].flags = PASSFLAG_BYVAL; \
   238 			pass[1].size = sizeof(float); \
   239 			pass[1].type = PassType_Basic; \
   240 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
   241 	}
   242 
   243 	CBaseEntity *pEntity;
   244 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   245 	{
   246 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   247 	}
   248 
   249 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   250 
   251 	unsigned char vstk[sizeof(void *) + sizeof(int) + sizeof(float)];
   252 	unsigned char *vptr = vstk;
   253 
   254 	*(void **)vptr = obj;
   255 	vptr += sizeof(void *);
   256 	*(int *)vptr = params[2];
   257 	vptr += sizeof(int);
   258 	*(float *)vptr = *(float *)&params[3];
   259 
   260 	pWrapper->Execute(vstk, NULL);
   261 
   262 	return 1;
   263 }
   264 
   265 cell_t TF2_RemoveCondition(IPluginContext *pContext, const cell_t *params)
   266 {
   267 	static ICallWrapper *pWrapper = NULL;
   268 
   269 	// CTFPlayerShared::RemoveCond(int, bool)
   270 	if (!pWrapper)
   271 	{
   272 		REGISTER_NATIVE_ADDR("RemoveCondition", 
   273 			PassInfo pass[2]; \
   274 			pass[0].flags = PASSFLAG_BYVAL; \
   275 			pass[0].size = sizeof(int); \
   276 			pass[0].type = PassType_Basic; \
   277 			pass[1].flags = PASSFLAG_BYVAL; \
   278 			pass[1].size = sizeof(bool); \
   279 			pass[1].type = PassType_Basic; \
   280 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
   281 	}
   282 
   283 	CBaseEntity *pEntity;
   284 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   285 	{
   286 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   287 	}
   288 
   289 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   290 
   291 	unsigned char vstk[sizeof(void *) + sizeof(int) + sizeof(bool)];
   292 	unsigned char *vptr = vstk;
   293 
   294 	*(void **)vptr = obj;
   295 	vptr += sizeof(void *);
   296 	*(int *)vptr = params[2];
   297 	vptr += sizeof(int);
   298 	*(bool *)vptr = false;
   299 
   300 	pWrapper->Execute(vstk, NULL);
   301 
   302 	return 1;
   303 }
   304 
   305 cell_t TF2_StunPlayer(IPluginContext *pContext, const cell_t *params)
   306 {
   307 	static ICallWrapper *pWrapper = NULL;
   308 
   309 	// CTFPlayerShared::StunPlayer(float, float, int, CTFPlayer *)
   310 	if (!pWrapper)
   311 	{
   312 		REGISTER_NATIVE_ADDR("StunPlayer", 
   313 			PassInfo pass[4]; \
   314 			pass[0].flags = PASSFLAG_BYVAL; \
   315 			pass[0].size = sizeof(float); \
   316 			pass[0].type = PassType_Basic; \
   317 			pass[1].flags = PASSFLAG_BYVAL; \
   318 			pass[1].size = sizeof(float); \
   319 			pass[1].type = PassType_Basic; \
   320 			pass[2].flags = PASSFLAG_BYVAL; \
   321 			pass[2].size = sizeof(int); \
   322 			pass[2].type = PassType_Basic; \
   323 			pass[3].flags = PASSFLAG_BYVAL; \
   324 			pass[3].size = sizeof(CBaseEntity *); \
   325 			pass[3].type = PassType_Basic; \
   326 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 4))
   327 	}
   328 
   329 	CBaseEntity *pEntity;
   330 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   331 	{
   332 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   333 	}
   334 
   335 	bool bByPlayer = (params[5] != 0);
   336 	CBaseEntity *pAttacker = NULL;
   337 	if (bByPlayer && !(pAttacker = UTIL_GetCBaseEntity(params[5], true)))
   338 	{
   339 		return pContext->ThrowNativeError("Attacker index %d is not valid", params[5]);
   340 	}
   341 
   342 	void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
   343 
   344 	unsigned char vstk[sizeof(void *) + 2*sizeof(float) + sizeof(int) + sizeof(CBaseEntity *)];
   345 	unsigned char *vptr = vstk;
   346 
   347 	*(void **)vptr = obj;
   348 	vptr += sizeof(void *);
   349 	*(float *)vptr = sp_ctof(params[2]);
   350 	vptr += sizeof(float);
   351 	*(float *)vptr = sp_ctof(params[3]);
   352 	vptr += sizeof(float);
   353 	*(int *)vptr = params[4];
   354 	vptr += sizeof(int);
   355 	*(CBaseEntity **)vptr = pAttacker;
   356 
   357 	pWrapper->Execute(vstk, NULL);
   358 
   359 	return 1;
   360 }
   361 
   362 cell_t TF2_SetPowerplayEnabled(IPluginContext *pContext, const cell_t *params)
   363 {
   364 	static ICallWrapper *pWrapper = NULL;
   365 
   366 	// CTFPlayer::SetPowerPlayEnabled(bool)
   367 	if (!pWrapper)
   368 	{
   369 		REGISTER_NATIVE_ADDR("SetPowerplayEnabled", 
   370 			PassInfo pass[1]; \
   371 			pass[0].flags = PASSFLAG_BYVAL; \
   372 			pass[0].size = sizeof(bool); \
   373 			pass[0].type = PassType_Basic; \
   374 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 1))
   375 	}
   376 
   377 	CBaseEntity *pEntity;
   378 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   379 	{
   380 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   381 	}
   382 
   383 	bool bEnablePP = false;
   384 	if (params[2] != 0)
   385 	{
   386 		bEnablePP = true;
   387 	}
   388 
   389 	unsigned char vstk[sizeof(void *) + sizeof(bool)];
   390 	unsigned char *vptr = vstk;
   391 
   392 	*(void **)vptr = (void *)pEntity;
   393 	vptr += sizeof(void *);
   394 	*(bool *)vptr = bEnablePP;
   395 
   396 	pWrapper->Execute(vstk, NULL);
   397 
   398 	return 1;
   399 }
   400 
   401 cell_t TF2_Respawn(IPluginContext *pContext, const cell_t *params)
   402 {
   403 	static ICallWrapper *pWrapper = NULL;
   404 
   405 	//CTFPlayer::ForceRespawn()
   406 
   407 	if (!pWrapper)
   408 	{
   409 		int offset;
   410 
   411 		if (!g_pGameConf->GetOffset("ForceRespawn", &offset))
   412 		{
   413 			return pContext->ThrowNativeError("Failed to locate function");
   414 		}
   415 
   416 		pWrapper = g_pBinTools->CreateVCall(offset,
   417 											0,
   418 											0,
   419 											NULL,
   420 											NULL,
   421 											0);
   422 
   423 		g_RegNatives.Register(pWrapper);
   424 	}
   425 
   426 	CBaseEntity *pEntity;
   427 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   428 	{
   429 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   430 	}
   431 
   432 	unsigned char vstk[sizeof(void *)];
   433 	unsigned char *vptr = vstk;
   434 
   435 
   436 	*(void **)vptr = (void *)pEntity;
   437 
   438 	pWrapper->Execute(vstk, NULL);
   439 
   440 	return 1;
   441 }
   442 
   443 cell_t TF2_Regenerate(IPluginContext *pContext, const cell_t *params)
   444 {
   445 	static ICallWrapper *pWrapper = NULL;
   446 
   447 	//CTFPlayer::Regenerate()
   448 
   449 	if (!pWrapper)
   450 	{
   451 		REGISTER_NATIVE_ADDR("Regenerate", 
   452 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0));
   453 	}
   454 
   455 	CBaseEntity *pEntity;
   456 	if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
   457 	{
   458 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   459 	}
   460 	pWrapper->Execute(&pEntity, NULL);
   461 
   462 	return 1;
   463 }
   464 
   465 cell_t TF2_GetResourceEntity(IPluginContext *pContext, const cell_t *params)
   466 {
   467 	return g_resourceEntity;
   468 }
   469 
   470 cell_t TF2_GetClass(IPluginContext *pContext, const cell_t *params)
   471 {
   472 	char *str;
   473 	pContext->LocalToString(params[1], &str);
   474 
   475 	return (cell_t)ClassnameToType(str);
   476 }
   477 
   478 // native TF2_IsPlayerInDuel(client)
   479 cell_t TF2_IsPlayerInDuel(IPluginContext *pContext, const cell_t *params)
   480 {
   481 	static ICallWrapper *pWrapper = NULL;
   482 
   483 	// DuelMiniGame_IsPlayerInDuel(CTFPlayer *)
   484 	if (!pWrapper)
   485 	{
   486 		REGISTER_NATIVE_ADDR("IsPlayerInDuel", 
   487 			PassInfo pass[1]; \
   488 			pass[0].flags = PASSFLAG_BYVAL; \
   489 			pass[0].size = sizeof(CBaseEntity *); \
   490 			pass[0].type = PassType_Basic; \
   491 			PassInfo ret; \
   492 			ret.flags = PASSFLAG_BYVAL; \
   493 			ret.size = sizeof(bool); \
   494 			ret.type = PassType_Basic; \
   495 			pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &ret, pass, 1))
   496 	}
   497 
   498 	CBaseEntity *pPlayer;
   499 	if (!(pPlayer = UTIL_GetCBaseEntity(params[1], true)))
   500 	{
   501 		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   502 	}
   503 
   504 	unsigned char vstk[sizeof(CBaseEntity *)];
   505 	unsigned char *vptr = vstk;
   506 	*(CBaseEntity **)vptr = pPlayer;
   507 
   508 	bool retValue;
   509 	pWrapper->Execute(vstk, &retValue);
   510 
   511 	return (retValue) ? 1 : 0;
   512 }
   513 
   514 sp_nativeinfo_t g_TFNatives[] = 
   515 {
   516 	{"TF2_IgnitePlayer",			TF2_Burn},
   517 	{"TF2_SetPlayerInvuln",			TF2_Invuln},
   518 	{"TF2_RespawnPlayer",			TF2_Respawn},
   519 	{"TF2_DisguisePlayer",			TF2_Disguise},
   520 	{"TF2_RemovePlayerDisguise",	TF2_RemoveDisguise},
   521 	{"TF2_GetResourceEntity",		TF2_GetResourceEntity},
   522 	{"TF2_GetClass",				TF2_GetClass},
   523 	{"TF2_RegeneratePlayer",		TF2_Regenerate},
   524 	{"TF2_AddCondition",			TF2_AddCondition},
   525 	{"TF2_RemoveCondition",			TF2_RemoveCondition},
   526 	{"TF2_SetPlayerPowerPlay",		TF2_SetPowerplayEnabled},
   527 	{"TF2_StunPlayer",				TF2_StunPlayer},
   528 	{"TF2_MakeBleed",				TF2_MakeBleed},
   529 	{"TF2_IsPlayerInDuel",				TF2_IsPlayerInDuel},
   530 	{NULL,							NULL}
   531 };