Update GivePlayerItem for new params in CS:GO.
3 * =============================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2010 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>.
33 #include <sh_string.h>
34 #include "extension.h"
35 #include "vcallbuilder.h"
39 #include "CellRecipientFilter.h"
40 #include <inetchannel.h>
44 SourceHook::List<ValveCall *> g_RegCalls;
45 SourceHook::List<ICallWrapper *> g_CallWraps;
47 inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsigned int flags, unsigned int decflags=0)
49 info.decflags = decflags;
56 #define START_CALL() \
57 unsigned char *vptr = pCall->stk_get();
59 #define FINISH_CALL_SIMPLE(vret) \
60 pCall->call->Execute(vptr, vret); \
63 #define ENCODE_VALVE_PARAM(num, which, vnum) \
64 if (EncodeValveParam(pContext, \
67 &pCall->which[vnum], \
74 #define DECODE_VALVE_PARAM(num, which, vnum) \
75 if (DecodeValveParam(pContext, \
78 &pCall->which[vnum], \
85 bool CreateBaseCall(const char *name,
86 ValveCallType vcalltype,
87 const ValvePassInfo *retinfo,
88 const ValvePassInfo params[],
89 unsigned int numParams,
94 if (g_pGameConf->GetOffset(name, &offset))
96 call = CreateValveVCall(offset, vcalltype, retinfo, params, numParams);
99 g_RegCalls.push_back(call);
105 if (g_pGameConf->GetMemSig(name, &addr) && addr != NULL)
107 call = CreateValveCall(addr, vcalltype, retinfo, params, numParams);
110 g_RegCalls.push_back(call);
119 static cell_t RemovePlayerItem(IPluginContext *pContext, const cell_t *params)
121 static ValveCall *pCall = NULL;
124 ValvePassInfo pass[2];
125 InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
126 InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
127 if (!CreateBaseCall("RemovePlayerItem", ValveCall_Player, &pass[1], pass, 1, &pCall))
129 return pContext->ThrowNativeError("\"RemovePlayerItem\" not supported by this mod");
131 return pContext->ThrowNativeError("\"RemovePlayerItem\" wrapper failed to initialize");
137 DECODE_VALVE_PARAM(1, thisinfo, 0);
138 DECODE_VALVE_PARAM(2, vparams, 0);
139 FINISH_CALL_SIMPLE(&ret);
143 #if SOURCE_ENGINE == SE_CSGO
145 static cell_t GiveNamedItem(IPluginContext *pContext, const cell_t *params)
147 static ValveCall *pCall = NULL;
150 ValvePassInfo pass[5];
151 InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
152 InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
153 InitPass(pass[2], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
154 InitPass(pass[3], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
155 InitPass(pass[4], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
156 if (!CreateBaseCall("GiveNamedItem", ValveCall_Player, &pass[4], pass, 4, &pCall))
158 return pContext->ThrowNativeError("\"GiveNamedItem\" not supported by this mod");
160 return pContext->ThrowNativeError("\"GiveNamedItem\" wrapper failed to initialize");
164 CBaseEntity *pEntity = NULL;
166 DECODE_VALVE_PARAM(1, thisinfo, 0);
167 DECODE_VALVE_PARAM(2, vparams, 0);
168 DECODE_VALVE_PARAM(3, vparams, 1);
169 *(CEconItemView **)(vptr + 12) = NULL;
170 *(bool *)(vptr + 16) = false;
171 FINISH_CALL_SIMPLE(&pEntity);
173 return gamehelpers->EntityToBCompatRef(pEntity);
176 static cell_t GiveNamedItem(IPluginContext *pContext, const cell_t *params)
178 static ValveCall *pCall = NULL;
181 ValvePassInfo pass[3];
182 InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
183 InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
184 InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
185 if (!CreateBaseCall("GiveNamedItem", ValveCall_Player, &pass[2], pass, 2, &pCall))
187 return pContext->ThrowNativeError("\"GiveNamedItem\" not supported by this mod");
189 return pContext->ThrowNativeError("\"GiveNamedItem\" wrapper failed to initialize");
193 CBaseEntity *pEntity = NULL;
195 DECODE_VALVE_PARAM(1, thisinfo, 0);
196 DECODE_VALVE_PARAM(2, vparams, 0);
197 DECODE_VALVE_PARAM(3, vparams, 1);
198 FINISH_CALL_SIMPLE(&pEntity);
200 return gamehelpers->EntityToBCompatRef(pEntity);
204 static cell_t GetPlayerWeaponSlot(IPluginContext *pContext, const cell_t *params)
206 static ValveCall *pCall = NULL;
209 ValvePassInfo pass[2];
210 InitPass(pass[0], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
211 InitPass(pass[1], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
212 if (!CreateBaseCall("Weapon_GetSlot", ValveCall_Player, &pass[1], pass, 1, &pCall))
214 return pContext->ThrowNativeError("\"Weapon_GetSlot\" not supported by this mod");
216 return pContext->ThrowNativeError("\"Weapon_GetSlot\" wrapper failed to initialize");
220 CBaseEntity *pEntity;
222 DECODE_VALVE_PARAM(1, thisinfo, 0);
223 DECODE_VALVE_PARAM(2, vparams, 0);
224 FINISH_CALL_SIMPLE(&pEntity);
226 return gamehelpers->EntityToBCompatRef(pEntity);
229 #if SOURCE_ENGINE != SE_DARKMESSIAH
230 static cell_t IgniteEntity(IPluginContext *pContext, const cell_t *params)
232 static ValveCall *pCall = NULL;
235 ValvePassInfo pass[4];
236 InitPass(pass[0], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
237 InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
238 InitPass(pass[2], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
239 InitPass(pass[3], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
240 if (!CreateBaseCall("Ignite", ValveCall_Entity, NULL, pass, 4, &pCall))
242 return pContext->ThrowNativeError("\"Ignite\" not supported by this mod");
244 return pContext->ThrowNativeError("\"Ignite\" wrapper failed to initialize");
249 DECODE_VALVE_PARAM(1, thisinfo, 0);
250 DECODE_VALVE_PARAM(2, vparams, 0);
251 DECODE_VALVE_PARAM(3, vparams, 1);
252 DECODE_VALVE_PARAM(4, vparams, 2);
253 DECODE_VALVE_PARAM(5, vparams, 3);
254 FINISH_CALL_SIMPLE(NULL);
259 /* Dark Messiah specific version */
260 static cell_t IgniteEntity(IPluginContext *pContext, const cell_t *params)
262 static ValveCall *pCall = NULL;
265 ValvePassInfo pass[6];
266 InitPass(pass[0], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
267 InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
268 InitPass(pass[2], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
269 InitPass(pass[3], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
270 InitPass(pass[4], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
271 InitPass(pass[5], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
272 if (!CreateBaseCall("Ignite", ValveCall_Entity, NULL, pass, 6, &pCall))
274 return pContext->ThrowNativeError("\"Ignite\" not supported by this mod");
276 return pContext->ThrowNativeError("\"Ignite\" wrapper failed to initialize");
281 DECODE_VALVE_PARAM(1, thisinfo, 0);
282 DECODE_VALVE_PARAM(2, vparams, 0);
283 DECODE_VALVE_PARAM(3, vparams, 1);
284 DECODE_VALVE_PARAM(4, vparams, 2);
285 DECODE_VALVE_PARAM(5, vparams, 3);
286 /* Not sure what these params do, but they appear to be the default values */
287 *(int *)(vptr + 14) = 3;
288 *(int *)(vptr + 18) = 0;
289 FINISH_CALL_SIMPLE(NULL);
295 static cell_t ExtinguishEntity(IPluginContext *pContext, const cell_t *params)
297 static ValveCall *pCall = NULL;
300 if (!CreateBaseCall("Extinguish", ValveCall_Entity, NULL, NULL, 0, &pCall))
302 return pContext->ThrowNativeError("\"Extinguish\" not supported by this mod");
304 return pContext->ThrowNativeError("\"Extinguish\" wrapper failed to initialize");
309 DECODE_VALVE_PARAM(1, thisinfo, 0);
310 FINISH_CALL_SIMPLE(NULL);
315 static cell_t TeleportEntity(IPluginContext *pContext, const cell_t *params)
317 static ValveCall *pCall = NULL;
320 ValvePassInfo pass[3];
321 InitPass(pass[0], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
322 InitPass(pass[1], Valve_QAngle, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
323 InitPass(pass[2], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
324 if (!CreateBaseCall("Teleport", ValveCall_Entity, NULL, pass, 3, &pCall))
326 return pContext->ThrowNativeError("\"Teleport\" not supported by this mod");
328 return pContext->ThrowNativeError("\"Teleport\" wrapper failed to initialize");
333 DECODE_VALVE_PARAM(1, thisinfo, 0);
334 DECODE_VALVE_PARAM(2, vparams, 0);
335 DECODE_VALVE_PARAM(3, vparams, 1);
336 DECODE_VALVE_PARAM(4, vparams, 2);
337 FINISH_CALL_SIMPLE(NULL);
342 #if SOURCE_ENGINE >= SE_ORANGEBOX
343 /* :TODO: This is Team Fortress 2 specific */
344 static cell_t ForcePlayerSuicide(IPluginContext *pContext, const cell_t *params)
346 static ValveCall *pCall = NULL;
349 ValvePassInfo pass[2];
350 InitPass(pass[0], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
351 InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
352 if (!CreateBaseCall("CommitSuicide", ValveCall_Player, NULL, pass, 2, &pCall))
354 return pContext->ThrowNativeError("\"CommitSuicide\" not supported by this mod");
358 return pContext->ThrowNativeError("\"CommitSuicide\" wrapper failed to initialize");
363 DECODE_VALVE_PARAM(1, thisinfo, 0);
364 *(bool *)(vptr + 4) = false;
365 *(bool *)(vptr + 5) = false;
366 FINISH_CALL_SIMPLE(NULL);
371 static cell_t ForcePlayerSuicide(IPluginContext *pContext, const cell_t *params)
373 static ValveCall *pCall = NULL;
376 if (!CreateBaseCall("CommitSuicide", ValveCall_Player, NULL, NULL, 0, &pCall))
378 return pContext->ThrowNativeError("\"CommitSuicide\" not supported by this mod");
380 return pContext->ThrowNativeError("\"CommitSuicide\" wrapper failed to initialize");
385 DECODE_VALVE_PARAM(1, thisinfo, 0);
386 FINISH_CALL_SIMPLE(NULL);
392 static cell_t SetClientViewEntity(IPluginContext *pContext, const cell_t *params)
394 IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
397 return pContext->ThrowNativeError("Invalid client index %d", params[1]);
399 if (!player->IsInGame())
401 return pContext->ThrowNativeError("Client %d is not in game", params[1]);
404 edict_t *pEdict = PEntityOfEntIndex(gamehelpers->ReferenceToIndex(params[2]));
405 if (!pEdict || pEdict->IsFree())
407 return pContext->ThrowNativeError("Entity %d is not valid", params[2]);
410 #if SOURCE_ENGINE == SE_DOTA
411 engine->SetView(params[1], params[2]);
413 engine->SetView(player->GetEdict(), pEdict);
419 static SourceHook::String *g_lightstyle[MAX_LIGHTSTYLES] = {NULL};
420 static cell_t SetLightStyle(IPluginContext *pContext, const cell_t *params)
422 int style = params[1];
423 if (style >= MAX_LIGHTSTYLES)
425 return pContext->ThrowNativeError("Light style %d is invalid (range: 0-%d)", style, MAX_LIGHTSTYLES - 1);
428 if (g_lightstyle[style] == NULL)
430 /* We allocate and never free this because the Engine wants to hold onto it :\
431 * in theory we could hook light style and know whether we're supposed to free
432 * this or not on shutdown, but for ~4K of memory MAX, it doesn't seem worth it yet.
435 g_lightstyle[style] = new SourceHook::String();
439 pContext->LocalToString(params[2], &str);
441 g_lightstyle[style]->assign(str);
443 engine->LightStyle(style, g_lightstyle[style]->c_str());
448 static cell_t SlapPlayer(IPluginContext *pContext, const cell_t *params)
450 static bool s_slap_supported = false;
451 static bool s_slap_setup = false;
452 static ICallWrapper *s_teleport = NULL;
453 static int s_health_offs = 0;
454 static int s_sound_count = 0;
455 static int s_frag_offs = 0;
463 if (IsTeleportSupported())
467 if (IsGetVelocitySupported())
473 if (g_pGameConf->GetOffset("m_iHealth", &s_health_offs) && s_health_offs)
480 s_slap_supported = true;
483 if ((key = g_pGameConf->GetKeyValue("SlapSoundCount")) != NULL)
485 s_sound_count = atoi(key);
490 if (!s_slap_supported)
492 return pContext->ThrowNativeError("This function is not supported on this mod");
495 /* First check if the client is valid */
496 IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
499 return pContext->ThrowNativeError("Client %d is not valid", params[1]);
500 } else if (!player->IsInGame()) {
501 return pContext->ThrowNativeError("Client %d is not in game", params[1]);
504 edict_t *pEdict = player->GetEdict();
505 CBaseEntity *pEntity = pEdict->GetUnknown()->GetBaseEntity();
507 /* See if we should be taking away health */
508 bool should_slay = false;
511 #if SOURCE_ENGINE != SE_DARKMESSIAH
512 int *health = (int *)((char *)pEntity + s_health_offs);
514 if (*health - params[2] <= 0)
519 *health -= params[2];
522 float *health = (float *)((char *)pEntity + s_health_offs);
524 if (*health - (float)params[2] <= 0)
529 *health -= (float)params[2];
534 /* Teleport in a random direction - thank you, Mani!*/
536 GetVelocity(pEntity, &velocity, NULL);
537 velocity.x += ((rand() % 180) + 50) * (((rand() % 2) == 1) ? -1 : 1);
538 velocity.y += ((rand() % 180) + 50) * (((rand() % 2) == 1) ? -1 : 1);
539 velocity.z += rand() % 200 + 100;
540 Teleport(pEntity, NULL, NULL, &velocity);
542 /* Play a random sound */
543 if (params[3] && s_sound_count > 0)
546 const char *sound_name;
547 cell_t player_list[256], total_players = 0;
548 int maxClients = playerhelpers->GetMaxClients();
550 int r = (rand() % s_sound_count) + 1;
551 snprintf(name, sizeof(name), "SlapSound%d", r);
553 if ((sound_name = g_pGameConf->GetKeyValue(name)) != NULL)
556 for (int i=1; i<=maxClients; i++)
558 other = playerhelpers->GetGamePlayer(i);
559 if (other->IsInGame())
561 player_list[total_players++] = i;
565 const Vector & pos = pEdict->GetCollideable()->GetCollisionOrigin();
566 CellRecipientFilter rf;
567 rf.SetToReliable(true);
568 rf.Initialize(player_list, total_players);
569 #if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2
570 engsound->EmitSound(rf, params[1], CHAN_AUTO, sound_name, VOL_NORM, ATTN_NORM, 0, PITCH_NORM, 0, &pos);
571 #elif SOURCE_ENGINE < SE_PORTAL2
572 engsound->EmitSound(rf, params[1], CHAN_AUTO, sound_name, VOL_NORM, ATTN_NORM, 0, PITCH_NORM, &pos);
574 engsound->EmitSound(rf, params[1], CHAN_AUTO, sound_name, -1, sound_name, VOL_NORM, ATTN_NORM, 0, 0, PITCH_NORM, &pos);
581 const char *frag_prop = g_pGameConf->GetKeyValue("m_iFrags");
584 datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
585 sm_datatable_info_t info;
586 if (gamehelpers->FindDataMapInfo(pMap, frag_prop, &info))
588 s_frag_offs = info.actual_offset;
600 old_frags = *(int *)((char *)pEntity + s_frag_offs);
606 #if SOURCE_ENGINE == SE_DOTA
607 engine->ClientCommand(params[1], "kill\n");
609 pluginhelpers->ClientCommand(pEdict, "kill\n");
615 *(int *)((char *)pEntity + s_frag_offs) = old_frags;
621 static cell_t GetClientEyePosition(IPluginContext *pContext, const cell_t *params)
623 IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
626 return pContext->ThrowNativeError("Invalid client index %d", params[1]);
628 if (!player->IsInGame())
630 return pContext->ThrowNativeError("Client %d is not in game", params[1]);
634 #if SOURCE_ENGINE == SE_DOTA
635 serverClients->ClientEarPosition(params[1], &pos);
637 serverClients->ClientEarPosition(player->GetEdict(), &pos);
641 pContext->LocalToPhysAddr(params[2], &addr);
642 addr[0] = sp_ftoc(pos.x);
643 addr[1] = sp_ftoc(pos.y);
644 addr[2] = sp_ftoc(pos.z);
649 static cell_t GetClientEyeAngles(IPluginContext *pContext, const cell_t *params)
651 IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(params[1]);
655 return pContext->ThrowNativeError("Invalid client index %d", params[1]);
657 else if (!pPlayer->IsInGame())
659 return pContext->ThrowNativeError("Client %d is not in game", params[1]);
662 edict_t *pEdict = pPlayer->GetEdict();
663 CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL;
665 /* We always set the angles for backwards compatibility --
666 * The original function had no return value.
669 bool got_angles = false;
673 got_angles = GetEyeAngles(pEntity, &angles);
677 pContext->LocalToPhysAddr(params[2], &addr);
678 addr[0] = sp_ftoc(angles.x);
679 addr[1] = sp_ftoc(angles.y);
680 addr[2] = sp_ftoc(angles.z);
682 return got_angles ? 1 : 0;
685 #if SOURCE_ENGINE >= SE_ORANGEBOX
686 static cell_t NativeFindEntityByClassname(IPluginContext *pContext, const cell_t *params)
689 CBaseEntity *pEntity;
693 pEntity = (CBaseEntity *)servertools->FirstEntity();
697 pEntity = gamehelpers->ReferenceToEntity(params[1]);
700 return pContext->ThrowNativeError("Entity %d (%d) is invalid",
701 gamehelpers->ReferenceToIndex(params[1]),
704 pEntity = (CBaseEntity *)servertools->NextEntity(pEntity);
707 // it's tough to find a good ent these days
713 pContext->LocalToString(params[2], &searchname);
715 const char *classname;
718 static int offset = -1;
721 sm_datatable_info_t info;
722 if (!gamehelpers->FindDataMapInfo(gamehelpers->GetDataMap(pEntity), "m_iClassname", &info))
727 offset = info.actual_offset;
734 if ((s = *(string_t *)((uint8_t *)pEntity + offset)) == NULL_STRING)
736 pEntity = (CBaseEntity *)servertools->NextEntity(pEntity);
740 classname = STRING(s);
742 lastletterpos = strlen(searchname) - 1;
743 if (searchname[lastletterpos] == '*')
745 if (strncasecmp(searchname, classname, lastletterpos) == 0)
747 return gamehelpers->EntityToBCompatRef(pEntity);
750 else if (strcasecmp(searchname, classname) == 0)
752 return gamehelpers->EntityToBCompatRef(pEntity);
755 pEntity = (CBaseEntity *)servertools->NextEntity(pEntity);
762 static cell_t FindEntityByClassname(IPluginContext *pContext, const cell_t *params)
764 static ValveCall *pCall = NULL;
765 static bool bProbablyNoFEBC = false;
767 #if SOURCE_ENGINE >= SE_ORANGEBOX
770 return NativeFindEntityByClassname(pContext, params);
776 ValvePassInfo pass[3];
777 InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL|VDECODE_FLAG_ALLOWWORLD);
778 InitPass(pass[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
779 InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
783 if (!CreateBaseCall("FindEntityByClassname", ValveCall_EntityList, &pass[2], pass, 2, &pCall))
785 g_pSM->Format(error, sizeof(error), "\"FindEntityByClassname\" not supported by this mod");
787 g_pSM->Format(error, sizeof(error), "\"FindEntityByClassname\" wrapper failed to initialize");
790 if (error[0] != '\0')
792 #if SOURCE_ENGINE >= SE_ORANGEBOX
793 if (!bProbablyNoFEBC)
795 bProbablyNoFEBC = true;
796 g_pSM->LogError(myself, "%s, falling back to IServerTools method.", error);
798 return NativeFindEntityByClassname(pContext, params);
800 return pContext->ThrowNativeError("%s", error);
805 CBaseEntity *pEntity;
807 *(void **)vptr = g_EntList;
808 DECODE_VALVE_PARAM(1, vparams, 0);
809 DECODE_VALVE_PARAM(2, vparams, 1);
810 FINISH_CALL_SIMPLE(&pEntity);
812 return gamehelpers->EntityToBCompatRef(pEntity);
815 #if SOURCE_ENGINE >= SE_ORANGEBOX
816 static cell_t CreateEntityByName(IPluginContext *pContext, const cell_t *params)
818 if (!g_pSM->IsMapRunning())
820 return pContext->ThrowNativeError("Cannot create new entity when no map is running");
824 pContext->LocalToString(params[1], &classname);
825 CBaseEntity *pEntity = (CBaseEntity *)servertools->CreateEntityByName(classname);
826 return gamehelpers->EntityToBCompatRef(pEntity);
829 static cell_t CreateEntityByName(IPluginContext *pContext, const cell_t *params)
831 if (!g_pSM->IsMapRunning())
833 return pContext->ThrowNativeError("Cannot create new entity when no map is running");
836 static ValveCall *pCall = NULL;
839 ValvePassInfo pass[3];
840 InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
841 InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
842 InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
843 if (!CreateBaseCall("CreateEntityByName", ValveCall_Static, &pass[2], pass, 2, &pCall))
845 return pContext->ThrowNativeError("\"CreateEntityByName\" not supported by this mod");
847 return pContext->ThrowNativeError("\"CreateEntityByName\" wrapper failed to initialize");
851 CBaseEntity *pEntity = NULL;
853 DECODE_VALVE_PARAM(1, vparams, 0);
854 DECODE_VALVE_PARAM(2, vparams, 1);
855 FINISH_CALL_SIMPLE(&pEntity);
857 return gamehelpers->EntityToBCompatRef(pEntity);
861 #if SOURCE_ENGINE >= SE_ORANGEBOX
862 static cell_t DispatchSpawn(IPluginContext *pContext, const cell_t *params)
864 CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
867 return pContext->ThrowNativeError("Entity %d (%d) is invalid", gamehelpers->ReferenceToIndex(params[1]), params[1]);
870 servertools->DispatchSpawn(pEntity);
875 static cell_t DispatchSpawn(IPluginContext *pContext, const cell_t *params)
877 static ValveCall *pCall = NULL;
880 ValvePassInfo pass[2];
881 InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
882 InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
883 if (!CreateBaseCall("DispatchSpawn", ValveCall_Static, &pass[1], pass, 1, &pCall))
885 return pContext->ThrowNativeError("\"DispatchSpawn\" not supported by this mod");
887 return pContext->ThrowNativeError("\"DispatchSpawn\" wrapper failed to initialize");
893 DECODE_VALVE_PARAM(1, vparams, 0);
894 FINISH_CALL_SIMPLE(&ret);
896 return (ret == -1) ? 0 : 1;
900 #if SOURCE_ENGINE >= SE_ORANGEBOX
901 static cell_t DispatchKeyValue(IPluginContext *pContext, const cell_t *params)
903 CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
906 return pContext->ThrowNativeError("Entity %d (%d) is invalid", gamehelpers->ReferenceToIndex(params[1]), params[1]);
911 pContext->LocalToString(params[2], &key);
912 pContext->LocalToString(params[3], &value);
914 return (servertools->SetKeyValue(pEntity, key, value) ? 1 : 0);
917 static cell_t DispatchKeyValue(IPluginContext *pContext, const cell_t *params)
919 static ValveCall *pCall = NULL;
922 ValvePassInfo pass[3];
923 InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
924 InitPass(pass[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
925 InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
926 if (!CreateBaseCall("DispatchKeyValue", ValveCall_Entity, &pass[2], pass, 2, &pCall))
928 return pContext->ThrowNativeError("\"DispatchKeyValue\" not supported by this mod");
930 return pContext->ThrowNativeError("\"DispatchKeyValue\" wrapper failed to initialize");
936 DECODE_VALVE_PARAM(1, thisinfo, 0);
937 DECODE_VALVE_PARAM(2, vparams, 0);
938 DECODE_VALVE_PARAM(3, vparams, 1);
939 FINISH_CALL_SIMPLE(&ret);
945 #if SOURCE_ENGINE >= SE_ORANGEBOX
946 static cell_t DispatchKeyValueFloat(IPluginContext *pContext, const cell_t *params)
948 CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
951 return pContext->ThrowNativeError("Entity %d (%d) is invalid", gamehelpers->ReferenceToIndex(params[1]), params[1]);
955 pContext->LocalToString(params[2], &key);
957 float value = sp_ctof(params[3]);
959 return (servertools->SetKeyValue(pEntity, key, value) ? 1 : 0);
962 static cell_t DispatchKeyValueFloat(IPluginContext *pContext, const cell_t *params)
964 static ValveCall *pCall = NULL;
967 ValvePassInfo pass[3];
968 InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
969 InitPass(pass[1], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
970 InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
971 if (!CreateBaseCall("DispatchKeyValueFloat", ValveCall_Entity, &pass[2], pass, 2, &pCall))
973 return pContext->ThrowNativeError("\"DispatchKeyValueFloat\" not supported by this mod");
975 return pContext->ThrowNativeError("\"DispatchKeyValueFloat\" wrapper failed to initialize");
981 DECODE_VALVE_PARAM(1, thisinfo, 0);
982 DECODE_VALVE_PARAM(2, vparams, 0);
983 DECODE_VALVE_PARAM(3, vparams, 1);
984 FINISH_CALL_SIMPLE(&ret);
990 #if SOURCE_ENGINE >= SE_ORANGEBOX
991 static cell_t DispatchKeyValueVector(IPluginContext *pContext, const cell_t *params)
993 CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
996 return pContext->ThrowNativeError("Entity %d (%d) is invalid", gamehelpers->ReferenceToIndex(params[1]), params[1]);
1000 pContext->LocalToString(params[2], &key);
1003 pContext->LocalToPhysAddr(params[3], &vec);
1005 const Vector *v = new Vector(
1010 return (servertools->SetKeyValue(pEntity, key, *v) ? 1 : 0);
1013 static cell_t DispatchKeyValueVector(IPluginContext *pContext, const cell_t *params)
1015 static ValveCall *pCall = NULL;
1018 ValvePassInfo pass[3];
1019 InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1020 #if SOURCE_ENGINE >= SE_ORANGEBOX
1021 InitPass(pass[1], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL);
1023 InitPass(pass[1], Valve_Vector, PassType_Object, PASSFLAG_BYVAL|PASSFLAG_OCTOR|PASSFLAG_OASSIGNOP);
1025 InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
1026 if (!CreateBaseCall("DispatchKeyValueVector", ValveCall_Entity, &pass[2], pass, 2, &pCall))
1028 return pContext->ThrowNativeError("\"DispatchKeyValueVector\" not supported by this mod");
1029 } else if (!pCall) {
1030 return pContext->ThrowNativeError("\"DispatchKeyValueVector\" wrapper failed to initialize");
1036 DECODE_VALVE_PARAM(1, thisinfo, 0);
1037 DECODE_VALVE_PARAM(2, vparams, 0);
1038 DECODE_VALVE_PARAM(3, vparams, 1);
1039 FINISH_CALL_SIMPLE(&ret);
1045 static cell_t sm_GetClientAimTarget(IPluginContext *pContext, const cell_t *params)
1047 IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(params[1]);
1051 return pContext->ThrowNativeError("Invalid client index %d", params[1]);
1053 else if (!pPlayer->IsInGame())
1055 return pContext->ThrowNativeError("Client %d is not in game", params[1]);
1058 return GetClientAimTarget(pPlayer->GetEdict(), params[2] ? true : false);
1061 static cell_t sm_SetEntityModel(IPluginContext *pContext, const cell_t *params)
1063 static ValveCall *pCall = NULL;
1066 ValvePassInfo pass[1];
1067 InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1068 if (!CreateBaseCall("SetEntityModel", ValveCall_Entity, NULL, pass, 1, &pCall))
1070 return pContext->ThrowNativeError("\"SetEntityModel\" not supported by this mod");
1071 } else if (!pCall) {
1072 return pContext->ThrowNativeError("\"SetEntityModel\" wrapper failed to initialize");
1077 DECODE_VALVE_PARAM(1, thisinfo, 0);
1078 DECODE_VALVE_PARAM(2, vparams, 0);
1079 FINISH_CALL_SIMPLE(NULL);
1084 static cell_t GetPlayerDecalFile(IPluginContext *pContext, const cell_t *params)
1086 IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
1089 return pContext->ThrowNativeError("Invalid client index %d", params[1]);
1091 if (!player->IsInGame())
1093 return pContext->ThrowNativeError("Client %d is not in game", params[1]);
1099 if (!GetPlayerInfo(params[1], &info) || !info.customFiles[0])
1104 pContext->LocalToString(params[2], &buffer);
1105 Q_binarytohex((byte *)&info.customFiles[0], sizeof(info.customFiles[0]), buffer, params[3]);
1110 static cell_t GetPlayerJingleFile(IPluginContext *pContext, const cell_t *params)
1112 IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
1115 return pContext->ThrowNativeError("Invalid client index %d", params[1]);
1117 if (!player->IsInGame())
1119 return pContext->ThrowNativeError("Client %d is not in game", params[1]);
1125 if (!GetPlayerInfo(params[1], &info) || !info.customFiles[1])
1130 pContext->LocalToString(params[2], &buffer);
1131 Q_binarytohex((byte *)&info.customFiles[1], sizeof(info.customFiles[1]), buffer, params[3]);
1136 static cell_t GetServerNetStats(IPluginContext *pContext, const cell_t *params)
1138 if (iserver == NULL)
1140 return pContext->ThrowNativeError("IServer interface not supported, file a bug report.");
1146 pContext->LocalToPhysAddr(params[1], &pIn);
1147 pContext->LocalToPhysAddr(params[2], &pOut);
1148 iserver->GetNetStats(in, out);
1151 *pOut = sp_ftoc(out);
1156 static cell_t WeaponEquip(IPluginContext *pContext, const cell_t *params)
1158 static ValveCall *pCall = NULL;
1161 ValvePassInfo pass[1];
1162 InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
1163 if (!CreateBaseCall("WeaponEquip", ValveCall_Player, NULL, pass, 1, &pCall))
1165 return pContext->ThrowNativeError("\"WeaponEquip\" not supported by this mod");
1166 } else if (!pCall) {
1167 return pContext->ThrowNativeError("\"WeaponEquip\" wrapper failed to initialize");
1172 DECODE_VALVE_PARAM(1, thisinfo, 0);
1173 DECODE_VALVE_PARAM(2, vparams, 0);
1174 FINISH_CALL_SIMPLE(NULL);
1179 static cell_t ActivateEntity(IPluginContext *pContext, const cell_t *params)
1181 static ValveCall *pCall = NULL;
1184 if (!CreateBaseCall("Activate", ValveCall_Entity, NULL, NULL, 0, &pCall))
1186 return pContext->ThrowNativeError("\"Activate\" not supported by this mod");
1190 return pContext->ThrowNativeError("\"Activate\" wrapper failed to initialize");
1195 DECODE_VALVE_PARAM(1, thisinfo, 0);
1196 FINISH_CALL_SIMPLE(NULL);
1201 static cell_t SetClientInfo(IPluginContext *pContext, const cell_t *params)
1203 if (iserver == NULL)
1205 return pContext->ThrowNativeError("IServer interface not supported, file a bug report.");
1208 IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
1209 IClient *pClient = iserver->GetClient(params[1] - 1);
1211 if (player == NULL || pClient == NULL)
1213 return pContext->ThrowNativeError("Invalid client index %d", params[1]);
1215 if (!player->IsConnected())
1217 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1220 static ValveCall *pCall = NULL;
1223 ValvePassInfo params[2];
1224 InitPass(params[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1225 InitPass(params[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1227 if (!CreateBaseCall("SetUserCvar", ValveCall_Entity, NULL, params, 2, &pCall))
1229 return pContext->ThrowNativeError("\"SetUserCvar\" not supported by this mod");
1233 return pContext->ThrowNativeError("\"SetUserCvar\" wrapper failed to initialize");
1237 /* TODO: Use UpdateUserSettings function for all engines */
1238 #if SOURCE_ENGINE == SE_DARKMESSIAH
1239 static ValveCall *pUpdateSettings = NULL;
1240 if (!pUpdateSettings)
1242 if (!CreateBaseCall("UpdateUserSettings", ValveCall_Entity, NULL, NULL, 0, &pUpdateSettings))
1244 return pContext->ThrowNativeError("\"SetUserCvar\" not supported by this mod");
1246 else if (!pUpdateSettings)
1248 return pContext->ThrowNativeError("\"SetUserCvar\" wrapper failed to initialize");
1252 static int changedOffset = -1;
1254 if (changedOffset == -1)
1256 if (!g_pGameConf->GetOffset("InfoChanged", &changedOffset))
1258 return pContext->ThrowNativeError("\"SetUserCvar\" not supported by this mod");
1263 unsigned char *CGameClient = (unsigned char *)pClient - 4;
1266 /* Not really a CBaseEntity* but this works */
1267 CBaseEntity **ebuf = (CBaseEntity **)vptr;
1268 *ebuf = (CBaseEntity *)CGameClient;
1269 DECODE_VALVE_PARAM(2, vparams, 0);
1270 DECODE_VALVE_PARAM(3, vparams, 1);
1271 FINISH_CALL_SIMPLE(NULL);
1273 #if SOURCE_ENGINE == SE_DARKMESSIAH
1274 unsigned char *args = pUpdateSettings->stk_get();
1275 *(void **)args = CGameClient;
1276 pUpdateSettings->call->Execute(args, NULL);
1277 pUpdateSettings->stk_put(args);
1279 uint8_t* changed = (uint8_t *)(CGameClient + changedOffset);
1286 static cell_t GetPlayerResourceEntity(IPluginContext *pContext, const cell_t *params)
1288 if (gamehelpers->GetHandleEntity(g_ResourceEntity) != NULL)
1290 return g_ResourceEntity.GetEntryIndex();
1296 sp_nativeinfo_t g_Natives[] =
1298 {"ExtinguishEntity", ExtinguishEntity},
1299 {"ForcePlayerSuicide", ForcePlayerSuicide},
1300 {"GivePlayerItem", GiveNamedItem},
1301 {"GetPlayerWeaponSlot", GetPlayerWeaponSlot},
1302 {"IgniteEntity", IgniteEntity},
1303 {"RemovePlayerItem", RemovePlayerItem},
1304 {"TeleportEntity", TeleportEntity},
1305 {"SetClientViewEntity", SetClientViewEntity},
1306 {"SetLightStyle", SetLightStyle},
1307 {"SlapPlayer", SlapPlayer},
1308 {"GetClientEyePosition", GetClientEyePosition},
1309 {"GetClientEyeAngles", GetClientEyeAngles},
1310 {"FindEntityByClassname", FindEntityByClassname},
1311 {"CreateEntityByName", CreateEntityByName},
1312 {"DispatchSpawn", DispatchSpawn},
1313 {"DispatchKeyValue", DispatchKeyValue},
1314 {"DispatchKeyValueFloat", DispatchKeyValueFloat},
1315 {"DispatchKeyValueVector", DispatchKeyValueVector},
1316 {"GetClientAimTarget", sm_GetClientAimTarget},
1317 {"SetEntityModel", sm_SetEntityModel},
1318 {"GetPlayerDecalFile", GetPlayerDecalFile},
1319 {"GetPlayerJingleFile", GetPlayerJingleFile},
1320 {"GetServerNetStats", GetServerNetStats},
1321 {"EquipPlayerWeapon", WeaponEquip},
1322 {"ActivateEntity", ActivateEntity},
1323 {"SetClientInfo", SetClientInfo},
1324 {"GetPlayerResourceEntity", GetPlayerResourceEntity},