3 * =============================================================================
4 * SourceMod Team Fortress 2 Extension
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
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.
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
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/>.
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>.
32 #include "extension.h"
35 #include "RegNatives.h"
37 // native TF2_MakeBleed(client, victim, Float:duration)
38 cell_t TF2_MakeBleed(IPluginContext *pContext, const cell_t *params)
40 static ICallWrapper *pWrapper = NULL;
42 // CTFPlayerShared::MakeBleed(CTFPlayer*, CTFWeaponBase*, float)
45 REGISTER_NATIVE_ADDR("MakeBleed",
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))
60 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
62 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
66 if (!(pTarget = UTIL_GetCBaseEntity(params[2], true)))
68 return pContext->ThrowNativeError("Client index %d is not valid", params[2]);
71 void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
73 unsigned char vstk[sizeof(void *) + 2*sizeof(CBaseEntity *) + sizeof(float)];
74 unsigned char *vptr = vstk;
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]);
84 pWrapper->Execute(vstk, NULL);
89 // native TF2_Burn(client, target)
90 cell_t TF2_Burn(IPluginContext *pContext, const cell_t *params)
92 static ICallWrapper *pWrapper = NULL;
94 // CTFPlayerShared::Burn(CTFPlayer*, CTFWeaponBase*)
97 REGISTER_NATIVE_ADDR("Burn",
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))
108 CBaseEntity *pEntity;
109 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
111 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
114 CBaseEntity *pTarget;
115 if (!(pTarget = UTIL_GetCBaseEntity(params[2], true)))
117 return pContext->ThrowNativeError("Client index %d is not valid", params[2]);
120 void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
122 unsigned char vstk[sizeof(void *) + 2*sizeof(CBaseEntity *)];
123 unsigned char *vptr = vstk;
125 *(void **)vptr = obj;
126 vptr += sizeof(void *);
127 *(CBaseEntity **)vptr = pTarget;
128 vptr += sizeof(CBaseEntity *);
129 *(CBaseEntity **)vptr = NULL;
131 pWrapper->Execute(vstk, NULL);
136 // native TF2_Invuln(client, bool:enabled)
137 cell_t TF2_Invuln(IPluginContext *pContext, const cell_t *params)
139 return pContext->ThrowNativeError("TF2_SetPlayerInvuln is no longer available");
142 cell_t TF2_Disguise(IPluginContext *pContext, const cell_t *params)
144 static ICallWrapper *pWrapper = NULL;
146 //CTFPlayerShared::Disguise(int, int, CTFPlayer *)
149 REGISTER_NATIVE_ADDR("Disguise",
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))
163 CBaseEntity *pEntity;
164 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
166 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
169 void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
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)))
175 return pContext->ThrowNativeError("Target client index %d is not valid", params[1]);
178 unsigned char vstk[sizeof(void *) + 2*sizeof(int)];
179 unsigned char *vptr = vstk;
182 *(void **)vptr = obj;
183 vptr += sizeof(void *);
184 *(int *)vptr = params[2];
186 *(int *)vptr = params[3];
188 *(CBaseEntity **)vptr = pTarget;
190 pWrapper->Execute(vstk, NULL);
195 cell_t TF2_RemoveDisguise(IPluginContext *pContext, const cell_t *params)
197 static ICallWrapper *pWrapper = NULL;
199 //CTFPlayerShared::RemoveDisguise()
202 REGISTER_NATIVE_ADDR("RemoveDisguise",
203 pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0))
206 CBaseEntity *pEntity;
207 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
209 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
212 void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
214 unsigned char vstk[sizeof(void *)];
215 unsigned char *vptr = vstk;
218 *(void **)vptr = obj;
220 pWrapper->Execute(vstk, NULL);
225 cell_t TF2_AddCondition(IPluginContext *pContext, const cell_t *params)
227 static ICallWrapper *pWrapper = NULL;
229 // CTFPlayerShared::AddCond(int, float)
232 REGISTER_NATIVE_ADDR("AddCondition",
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))
243 CBaseEntity *pEntity;
244 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
246 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
249 void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
251 unsigned char vstk[sizeof(void *) + sizeof(int) + sizeof(float)];
252 unsigned char *vptr = vstk;
254 *(void **)vptr = obj;
255 vptr += sizeof(void *);
256 *(int *)vptr = params[2];
258 *(float *)vptr = *(float *)¶ms[3];
260 pWrapper->Execute(vstk, NULL);
265 cell_t TF2_RemoveCondition(IPluginContext *pContext, const cell_t *params)
267 static ICallWrapper *pWrapper = NULL;
269 // CTFPlayerShared::RemoveCond(int, bool)
272 REGISTER_NATIVE_ADDR("RemoveCondition",
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))
283 CBaseEntity *pEntity;
284 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
286 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
289 void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
291 unsigned char vstk[sizeof(void *) + sizeof(int) + sizeof(bool)];
292 unsigned char *vptr = vstk;
294 *(void **)vptr = obj;
295 vptr += sizeof(void *);
296 *(int *)vptr = params[2];
298 *(bool *)vptr = false;
300 pWrapper->Execute(vstk, NULL);
305 cell_t TF2_StunPlayer(IPluginContext *pContext, const cell_t *params)
307 static ICallWrapper *pWrapper = NULL;
309 // CTFPlayerShared::StunPlayer(float, float, int, CTFPlayer *)
312 REGISTER_NATIVE_ADDR("StunPlayer",
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))
329 CBaseEntity *pEntity;
330 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
332 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
335 bool bByPlayer = (params[5] != 0);
336 CBaseEntity *pAttacker = NULL;
337 if (bByPlayer && !(pAttacker = UTIL_GetCBaseEntity(params[5], true)))
339 return pContext->ThrowNativeError("Attacker index %d is not valid", params[5]);
342 void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset);
344 unsigned char vstk[sizeof(void *) + 2*sizeof(float) + sizeof(int) + sizeof(CBaseEntity *)];
345 unsigned char *vptr = vstk;
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];
355 *(CBaseEntity **)vptr = pAttacker;
357 pWrapper->Execute(vstk, NULL);
362 cell_t TF2_SetPowerplayEnabled(IPluginContext *pContext, const cell_t *params)
364 static ICallWrapper *pWrapper = NULL;
366 // CTFPlayer::SetPowerPlayEnabled(bool)
369 REGISTER_NATIVE_ADDR("SetPowerplayEnabled",
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))
377 CBaseEntity *pEntity;
378 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
380 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
383 bool bEnablePP = false;
389 unsigned char vstk[sizeof(void *) + sizeof(bool)];
390 unsigned char *vptr = vstk;
392 *(void **)vptr = (void *)pEntity;
393 vptr += sizeof(void *);
394 *(bool *)vptr = bEnablePP;
396 pWrapper->Execute(vstk, NULL);
401 cell_t TF2_Respawn(IPluginContext *pContext, const cell_t *params)
403 static ICallWrapper *pWrapper = NULL;
405 //CTFPlayer::ForceRespawn()
411 if (!g_pGameConf->GetOffset("ForceRespawn", &offset))
413 return pContext->ThrowNativeError("Failed to locate function");
416 pWrapper = g_pBinTools->CreateVCall(offset,
423 g_RegNatives.Register(pWrapper);
426 CBaseEntity *pEntity;
427 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
429 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
432 unsigned char vstk[sizeof(void *)];
433 unsigned char *vptr = vstk;
436 *(void **)vptr = (void *)pEntity;
438 pWrapper->Execute(vstk, NULL);
443 cell_t TF2_Regenerate(IPluginContext *pContext, const cell_t *params)
445 static ICallWrapper *pWrapper = NULL;
447 //CTFPlayer::Regenerate()
451 REGISTER_NATIVE_ADDR("Regenerate",
452 pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0));
455 CBaseEntity *pEntity;
456 if (!(pEntity = UTIL_GetCBaseEntity(params[1], true)))
458 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
460 pWrapper->Execute(&pEntity, NULL);
465 cell_t TF2_GetResourceEntity(IPluginContext *pContext, const cell_t *params)
467 return g_resourceEntity;
470 cell_t TF2_GetClass(IPluginContext *pContext, const cell_t *params)
473 pContext->LocalToString(params[1], &str);
475 return (cell_t)ClassnameToType(str);
478 // native TF2_IsPlayerInDuel(client)
479 cell_t TF2_IsPlayerInDuel(IPluginContext *pContext, const cell_t *params)
481 static ICallWrapper *pWrapper = NULL;
483 // DuelMiniGame_IsPlayerInDuel(CTFPlayer *)
486 REGISTER_NATIVE_ADDR("IsPlayerInDuel",
488 pass[0].flags = PASSFLAG_BYVAL; \
489 pass[0].size = sizeof(CBaseEntity *); \
490 pass[0].type = PassType_Basic; \
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))
498 CBaseEntity *pPlayer;
499 if (!(pPlayer = UTIL_GetCBaseEntity(params[1], true)))
501 return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
504 unsigned char vstk[sizeof(CBaseEntity *)];
505 unsigned char *vptr = vstk;
506 *(CBaseEntity **)vptr = pPlayer;
509 pWrapper->Execute(vstk, &retValue);
511 return (retValue) ? 1 : 0;
514 sp_nativeinfo_t g_TFNatives[] =
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},