ds@1952: /**
ds@1952: * vim: set ts=4 :
ds@1952: * =============================================================================
ds@1952: * SourceMod SDKTools Extension
ds@1952: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
ds@1952: * =============================================================================
ds@1952: *
ds@1952: * This program is free software; you can redistribute it and/or modify it under
ds@1952: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952: * Free Software Foundation.
ds@1952: *
ds@1952: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1952: * details.
ds@1952: *
ds@1952: * You should have received a copy of the GNU General Public License along with
ds@1952: * this program. If not, see .
ds@1952: *
ds@1952: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1952: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1952: * this exception to all derivative works. AlliedModders LLC defines further
ds@1952: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952: * or .
ds@1952: *
ds@1952: * Version: $Id$
ds@1952: */
ds@1952:
ds@1952: #include
ds@1952: #include
ds@1952: #include "extension.h"
ds@1952: #include "vcallbuilder.h"
ds@1952: #include "vnatives.h"
ds@1952: #include "vhelpers.h"
ds@1952: #include "vglobals.h"
ds@1952: #include "CellRecipientFilter.h"
pred@2107: #include
pred@2107: #include
ds@1952:
ds@1952: SourceHook::List g_RegCalls;
ds@1952: SourceHook::List g_CallWraps;
ds@1952:
ds@1952: inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsigned int flags, unsigned int decflags=0)
ds@1952: {
ds@1952: info.decflags = decflags;
ds@1952: info.encflags = 0;
ds@1952: info.flags = flags;
ds@1952: info.type = type;
ds@1952: info.vtype = vtype;
ds@1952: }
ds@1952:
ds@1952: #define START_CALL() \
ds@1952: unsigned char *vptr = pCall->stk_get();
ds@1952:
ds@1952: #define FINISH_CALL_SIMPLE(vret) \
ds@1952: pCall->call->Execute(vptr, vret); \
ds@1952: pCall->stk_put(vptr);
ds@1952:
ds@1952: #define ENCODE_VALVE_PARAM(num, which, vnum) \
ds@1952: if (EncodeValveParam(pContext, \
ds@1952: params[num], \
ds@1952: pCall, \
ds@1952: &pCall->which[vnum], \
ds@1952: vptr) \
ds@1952: == Data_Fail) \
ds@1952: { \
ds@1952: return 0; \
ds@1952: }
ds@1952:
ds@1952: #define DECODE_VALVE_PARAM(num, which, vnum) \
ds@1952: if (DecodeValveParam(pContext, \
ds@1952: params[num], \
ds@1952: pCall, \
ds@1952: &pCall->which[vnum], \
ds@1952: vptr) \
ds@1952: == Data_Fail) \
ds@1952: { \
ds@1952: return 0; \
ds@1952: }
ds@1952:
ds@1952: bool CreateBaseCall(const char *name,
ds@1952: ValveCallType vcalltype,
ds@1952: const ValvePassInfo *retinfo,
ds@1952: const ValvePassInfo params[],
ds@1952: unsigned int numParams,
ds@1952: ValveCall **vaddr)
ds@1952: {
ds@1952: int offset;
ds@1952: ValveCall *call;
ds@1952: if (g_pGameConf->GetOffset(name, &offset))
ds@1952: {
ds@1952: call = CreateValveVCall(offset, vcalltype, retinfo, params, numParams);
ds@1952: if (call)
ds@1952: {
ds@1952: g_RegCalls.push_back(call);
ds@1952: }
ds@1952: *vaddr = call;
ds@1952: return true;
ds@1952: } else {
ds@1952: void *addr;
ds@1952: if (g_pGameConf->GetMemSig(name, &addr))
ds@1952: {
ds@1952: call = CreateValveCall(addr, vcalltype, retinfo, params, numParams);
ds@1952: if (call)
ds@1952: {
ds@1952: g_RegCalls.push_back(call);
ds@1952: }
ds@1952: *vaddr = call;
ds@1952: return true;
ds@1952: }
ds@1952: }
ds@1952: return false;
ds@1952: }
ds@1952:
ds@1952: static cell_t RemovePlayerItem(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[2];
ds@1952: InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("RemovePlayerItem", ValveCall_Player, &pass[1], pass, 1, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"RemovePlayerItem\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"RemovePlayerItem\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: bool ret;
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 0);
ds@1952: FINISH_CALL_SIMPLE(&ret);
ds@1952: return ret ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t GiveNamedItem(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[3];
ds@1952: InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("GiveNamedItem", ValveCall_Player, &pass[2], pass, 2, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"GiveNamedItem\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"GiveNamedItem\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: CBaseEntity *pEntity = NULL;
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 0);
ds@1952: DECODE_VALVE_PARAM(3, vparams, 1);
ds@1952: FINISH_CALL_SIMPLE(&pEntity);
ds@1952:
ds@1952: if (pEntity == NULL)
ds@1952: {
ds@1952: return -1;
ds@1952: }
ds@1952:
ds@1952: edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
ds@1952: if (!pEdict)
ds@1952: {
ds@1952: return -1;
ds@1952: }
ds@1952:
ds@1952: return engine->IndexOfEdict(pEdict);
ds@1952: }
ds@1952:
ds@1952: static cell_t GetPlayerWeaponSlot(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[2];
ds@1952: InitPass(pass[0], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[1], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("Weapon_GetSlot", ValveCall_Player, &pass[1], pass, 1, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"Weapon_GetSlot\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"Weapon_GetSlot\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: CBaseEntity *pEntity;
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 0);
ds@1952: FINISH_CALL_SIMPLE(&pEntity);
ds@1952:
ds@1952: if (pEntity == NULL)
ds@1952: {
ds@1952: return -1;
ds@1952: }
ds@1952:
ds@1952: edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
ds@1952: if (!pEdict)
ds@1952: {
ds@1952: return -1;
ds@1952: }
ds@1952:
ds@1952: return engine->IndexOfEdict(pEdict);
ds@1952: }
ds@1952:
ds@1952: static cell_t IgniteEntity(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[4];
ds@1952: InitPass(pass[0], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[2], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[3], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("Ignite", ValveCall_Entity, NULL, pass, 4, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"Ignite\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"Ignite\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 0);
ds@1952: DECODE_VALVE_PARAM(3, vparams, 1);
ds@1952: DECODE_VALVE_PARAM(4, vparams, 2);
ds@1952: DECODE_VALVE_PARAM(5, vparams, 3);
ds@1952: FINISH_CALL_SIMPLE(NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t ExtinguishEntity(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: if (!CreateBaseCall("Extinguish", ValveCall_Entity, NULL, NULL, 0, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"Extinguish\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"Extinguish\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: FINISH_CALL_SIMPLE(NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t TeleportEntity(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[3];
ds@1952: InitPass(pass[0], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
ds@1952: InitPass(pass[1], Valve_QAngle, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
ds@1952: InitPass(pass[2], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
ds@1952: if (!CreateBaseCall("Teleport", ValveCall_Entity, NULL, pass, 3, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"Teleport\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"Teleport\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 0);
ds@1952: DECODE_VALVE_PARAM(3, vparams, 1);
ds@1952: DECODE_VALVE_PARAM(4, vparams, 2);
ds@1952: FINISH_CALL_SIMPLE(NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: #if defined ORANGEBOX_BUILD
ds@1952: /* :TODO: This is Team Fortress 2 specific */
ds@1952: static cell_t ForcePlayerSuicide(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[2];
ds@1952: InitPass(pass[0], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("CommitSuicide", ValveCall_Player, NULL, pass, 2, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"CommitSuicide\" not supported by this mod");
ds@1952: }
ds@1952: else if (!pCall)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"CommitSuicide\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: *(bool *)(vptr + 4) = false;
ds@1952: *(bool *)(vptr + 5) = false;
ds@1952: FINISH_CALL_SIMPLE(NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952: #else
ds@1952: static cell_t ForcePlayerSuicide(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: if (!CreateBaseCall("CommitSuicide", ValveCall_Player, NULL, NULL, 0, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"CommitSuicide\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"CommitSuicide\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: FINISH_CALL_SIMPLE(NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952: #endif
ds@1952:
ds@1952: static cell_t SetClientViewEntity(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
ds@1952: if (player == NULL)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid client index %d", params[1]);
ds@1952: }
ds@1952: if (!player->IsInGame())
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Client %d is not in game", params[1]);
ds@1952: }
ds@1952:
ds@1952: edict_t *pEdict = engine->PEntityOfEntIndex(params[2]);
ds@1952: if (!pEdict || pEdict->IsFree())
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Entity %d is not valid", params[2]);
ds@1952: }
ds@1952:
ds@1952: engine->SetView(player->GetEdict(), pEdict);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static SourceHook::String *g_lightstyle[MAX_LIGHTSTYLES] = {NULL};
ds@1952: static cell_t SetLightStyle(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: int style = params[1];
ds@1952: if (style >= MAX_LIGHTSTYLES)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Light style %d is invalid (range: 0-%d)", style, MAX_LIGHTSTYLES - 1);
ds@1952: }
ds@1952:
ds@1952: if (g_lightstyle[style] == NULL)
ds@1952: {
ds@1952: /* We allocate and never free this because the Engine wants to hold onto it :\
ds@1952: * in theory we could hook light style and know whether we're supposed to free
ds@1952: * this or not on shutdown, but for ~4K of memory MAX, it doesn't seem worth it yet.
ds@1952: * So, it's a :TODO:!
ds@1952: */
ds@1952: g_lightstyle[style] = new SourceHook::String();
ds@1952: }
ds@1952:
ds@1952: char *str;
ds@1952: pContext->LocalToString(params[2], &str);
ds@1952:
ds@1952: g_lightstyle[style]->assign(str);
ds@1952:
ds@1952: engine->LightStyle(style, g_lightstyle[style]->c_str());
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SlapPlayer(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static bool s_slap_supported = false;
ds@1952: static bool s_slap_setup = false;
ds@1952: static ICallWrapper *s_teleport = NULL;
ds@1952: static int s_health_offs = 0;
ds@1952: static int s_sound_count = 0;
ds@1952: static int s_frag_offs = 0;
ds@1952:
ds@1952: if (!s_slap_setup)
ds@1952: {
ds@1952: int tries = 0;
ds@1952:
ds@1952: s_slap_setup = true;
ds@1952:
ds@1952: if (IsTeleportSupported())
ds@1952: {
ds@1952: tries++;
ds@1952: }
ds@1952: if (IsGetVelocitySupported())
ds@1952: {
ds@1952: tries++;
ds@1952: }
ds@1952:
ds@1952: /* Setup health */
ds@1952: if (g_pGameConf->GetOffset("m_iHealth", &s_health_offs) && s_health_offs)
ds@1952: {
ds@1952: tries++;
ds@1952: }
ds@1952:
ds@1952: if (tries == 3)
ds@1952: {
ds@1952: s_slap_supported = true;
ds@1952:
ds@1952: const char *key;
ds@1952: if ((key = g_pGameConf->GetKeyValue("SlapSoundCount")) != NULL)
ds@1952: {
ds@1952: s_sound_count = atoi(key);
ds@1952: }
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: if (!s_slap_supported)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("This function is not supported on this mod");
ds@1952: }
ds@1952:
ds@1952: /* First check if the client is valid */
ds@1952: int client = params[1];
ds@1952: IGamePlayer *player = playerhelpers->GetGamePlayer(client);
ds@1952: if (!player)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Client %d is not valid", client);
ds@1952: } else if (!player->IsInGame()) {
ds@1952: return pContext->ThrowNativeError("Client %d is not in game", client);
ds@1952: }
ds@1952:
ds@1952: edict_t *pEdict = player->GetEdict();
ds@1952: CBaseEntity *pEntity = pEdict->GetUnknown()->GetBaseEntity();
ds@1952:
ds@1952: /* See if we should be taking away health */
ds@1952: bool should_slay = false;
ds@1952: if (params[2])
ds@1952: {
ds@1952: int *health = (int *)((char *)pEntity + s_health_offs);
ds@1952: if (*health - params[2] <= 0)
ds@1952: {
ds@1952: *health = 1;
ds@1952: should_slay = true;
ds@1952: } else {
ds@1952: *health -= params[2];
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: /* Teleport in a random direction - thank you, Mani!*/
ds@1952: Vector velocity;
ds@1952: GetVelocity(pEntity, &velocity, NULL);
ds@1952: velocity.x += ((rand() % 180) + 50) * (((rand() % 2) == 1) ? -1 : 1);
ds@1952: velocity.y += ((rand() % 180) + 50) * (((rand() % 2) == 1) ? -1 : 1);
ds@1952: velocity.z += rand() % 200 + 100;
ds@1952: Teleport(pEntity, NULL, NULL, &velocity);
ds@1952:
ds@1952: /* Play a random sound */
ds@1952: if (params[3] && s_sound_count > 0)
ds@1952: {
ds@1952: char name[48];
ds@1952: const char *sound_name;
ds@1952: cell_t player_list[256], total_players = 0;
ds@1952: int maxClients = playerhelpers->GetMaxClients();
ds@1952:
ds@1952: int r = (rand() % s_sound_count) + 1;
ds@1952: snprintf(name, sizeof(name), "SlapSound%d", r);
ds@1952:
ds@1952: if ((sound_name = g_pGameConf->GetKeyValue(name)) != NULL)
ds@1952: {
ds@1952: IGamePlayer *other;
ds@1952: for (int i=1; i<=maxClients; i++)
ds@1952: {
ds@1952: other = playerhelpers->GetGamePlayer(i);
ds@1952: if (other->IsInGame())
ds@1952: {
ds@1952: player_list[total_players++] = i;
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: const Vector & pos = pEdict->GetCollideable()->GetCollisionOrigin();
ds@1952: CellRecipientFilter rf;
ds@1952: rf.SetToReliable(true);
ds@1952: rf.Initialize(player_list, total_players);
ds@1952: engsound->EmitSound(rf, client, CHAN_AUTO, sound_name, VOL_NORM, ATTN_NORM, 0, PITCH_NORM, &pos);
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: if (!s_frag_offs)
ds@1952: {
ds@1952: const char *frag_prop = g_pGameConf->GetKeyValue("m_iFrags");
ds@1952: if (frag_prop)
ds@1952: {
ds@1952: datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
ds@1952: typedescription_t *pType = gamehelpers->FindInDataMap(pMap, frag_prop);
ds@1952: if (pType != NULL)
ds@1952: {
ds@1952: s_frag_offs = pType->fieldOffset[TD_OFFSET_NORMAL];
ds@1952: }
ds@1952: }
ds@1952: if (!s_frag_offs)
ds@1952: {
ds@1952: s_frag_offs = -1;
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: int old_frags = 0;
ds@1952: if (s_frag_offs > 0)
ds@1952: {
ds@1952: old_frags = *(int *)((char *)pEntity + s_frag_offs);
ds@1952: }
ds@1952:
ds@1952: /* Force suicide */
ds@1952: if (should_slay)
ds@1952: {
ds@1952: pluginhelpers->ClientCommand(pEdict, "kill\n");
ds@1952: }
ds@1952:
ds@1952: if (s_frag_offs > 0)
ds@1952: {
ds@1952: *(int *)((char *)pEntity + s_frag_offs) = old_frags;
ds@1952: }
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t GetClientEyePosition(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
ds@1952: if (player == NULL)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid client index %d", params[1]);
ds@1952: }
ds@1952: if (!player->IsInGame())
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Client %d is not in game", params[1]);
ds@1952: }
ds@1952:
ds@1952: Vector pos;
ds@1952: serverClients->ClientEarPosition(player->GetEdict(), &pos);
ds@1952:
ds@1952: cell_t *addr;
ds@1952: pContext->LocalToPhysAddr(params[2], &addr);
ds@1952: addr[0] = sp_ftoc(pos.x);
ds@1952: addr[1] = sp_ftoc(pos.y);
ds@1952: addr[2] = sp_ftoc(pos.z);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t GetClientEyeAngles(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: int client = params[1];
ds@1952: IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
ds@1952:
ds@1952: if (!pPlayer)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid client index %d", client);
ds@1952: }
ds@1952: else if (!pPlayer->IsInGame())
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Client %d is not in game", client);
ds@1952: }
ds@1952:
ds@1952: edict_t *pEdict = pPlayer->GetEdict();
ds@1952: CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL;
ds@1952:
ds@1952: /* We always set the angles for backwards compatibility --
ds@1952: * The original function had no return value.
ds@1952: */
ds@1952: QAngle angles;
ds@1952: bool got_angles = false;
ds@1952:
ds@1952: if (pEntity != NULL)
ds@1952: {
ds@1952: got_angles = GetEyeAngles(pEntity, &angles);
ds@1952: }
ds@1952:
ds@1952: cell_t *addr;
ds@1952: pContext->LocalToPhysAddr(params[2], &addr);
ds@1952: addr[0] = sp_ftoc(angles.x);
ds@1952: addr[1] = sp_ftoc(angles.y);
ds@1952: addr[2] = sp_ftoc(angles.z);
ds@1952:
ds@1952: return got_angles ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t FindEntityByClassname(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[3];
ds@1952: InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL|VDECODE_FLAG_ALLOWWORLD);
ds@1952: InitPass(pass[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("FindEntityByClassname", ValveCall_EntityList, &pass[2], pass, 2, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"FindEntityByClassname\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"FindEntityByClassname\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: CBaseEntity *pEntity;
ds@1952: START_CALL();
ds@1952: *(void **)vptr = g_EntList;
ds@1952: DECODE_VALVE_PARAM(1, vparams, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 1);
ds@1952: FINISH_CALL_SIMPLE(&pEntity);
ds@1952:
ds@1952: if (pEntity == NULL)
ds@1952: {
ds@1952: return -1;
ds@1952: }
ds@1952:
ds@1952: edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
ds@1952: if (!pEdict)
ds@1952: {
ds@1952: return -1;
ds@1952: }
ds@1952:
ds@1952: return engine->IndexOfEdict(pEdict);
ds@1952: }
ds@1952:
ds@1952: static cell_t CreateEntityByName(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[3];
ds@1952: InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("CreateEntityByName", ValveCall_Static, &pass[2], pass, 2, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"CreateEntityByName\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"CreateEntityByName\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: CBaseEntity *pEntity = NULL;
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, vparams, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 1);
ds@1952: FINISH_CALL_SIMPLE(&pEntity);
ds@1952:
ds@1952: if (pEntity == NULL)
ds@1952: {
ds@1952: return -1;
ds@1952: }
ds@1952:
ds@1952: edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
ds@1952: if (!pEdict)
ds@1952: {
ds@1952: return -1;
ds@1952: }
ds@1952:
ds@1952: return engine->IndexOfEdict(pEdict);
ds@1952: }
ds@1952:
ds@1952: static cell_t DispatchSpawn(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[2];
ds@1952: InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("DispatchSpawn", ValveCall_Static, &pass[1], pass, 1, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"DispatchSpawn\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"DispatchSpawn\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: int ret;
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, vparams, 0);
ds@1952: FINISH_CALL_SIMPLE(&ret);
ds@1952:
ds@1952: return (ret == -1) ? 0 : 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t DispatchKeyValue(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[3];
ds@1952: InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("DispatchKeyValue", ValveCall_Entity, &pass[2], pass, 2, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"DispatchKeyValue\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"DispatchKeyValue\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: bool ret;
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 0);
ds@1952: DECODE_VALVE_PARAM(3, vparams, 1);
ds@1952: FINISH_CALL_SIMPLE(&ret);
ds@1952:
ds@1952: return (ret) ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t DispatchKeyValueFloat(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[3];
ds@1952: InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[1], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
ds@1952: InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("DispatchKeyValueFloat", ValveCall_Entity, &pass[2], pass, 2, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"DispatchKeyValueFloat\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"DispatchKeyValueFloat\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: bool ret;
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 0);
ds@1952: DECODE_VALVE_PARAM(3, vparams, 1);
ds@1952: FINISH_CALL_SIMPLE(&ret);
ds@1952:
ds@1952: return (ret) ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t DispatchKeyValueVector(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[3];
ds@1952: InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: #if defined ORANGEBOX_BUILD
ds@1952: InitPass(pass[1], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: #else
ds@1952: InitPass(pass[1], Valve_Vector, PassType_Object, PASSFLAG_BYVAL|PASSFLAG_OCTOR|PASSFLAG_OASSIGNOP);
ds@1952: #endif
ds@1952: InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("DispatchKeyValueVector", ValveCall_Entity, &pass[2], pass, 2, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"DispatchKeyValueVector\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"DispatchKeyValueVector\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: bool ret;
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 0);
ds@1952: DECODE_VALVE_PARAM(3, vparams, 1);
ds@1952: FINISH_CALL_SIMPLE(&ret);
ds@1952:
ds@1952: return (ret) ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t sm_GetClientAimTarget(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: int client = params[1];
ds@1952: IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
ds@1952:
ds@1952: if (!pPlayer)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid client index %d", client);
ds@1952: }
ds@1952: else if (!pPlayer->IsInGame())
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Client %d is not in game", client);
ds@1952: }
ds@1952:
ds@1952: return GetClientAimTarget(pPlayer->GetEdict(), params[2] ? true : false);
ds@1952: }
ds@1952:
ds@1952: static cell_t sm_SetEntityModel(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: static ValveCall *pCall = NULL;
ds@1952: if (!pCall)
ds@1952: {
ds@1952: ValvePassInfo pass[1];
ds@1952: InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
ds@1952: if (!CreateBaseCall("SetEntityModel", ValveCall_Entity, NULL, pass, 1, &pCall))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("\"SetEntityModel\" not supported by this mod");
ds@1952: } else if (!pCall) {
ds@1952: return pContext->ThrowNativeError("\"SetEntityModel\" wrapper failed to initialized");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: START_CALL();
ds@1952: DECODE_VALVE_PARAM(1, thisinfo, 0);
ds@1952: DECODE_VALVE_PARAM(2, vparams, 0);
ds@1952: FINISH_CALL_SIMPLE(NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t GetPlayerDecalFile(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
ds@1952: if (player == NULL)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid client index %d", params[1]);
ds@1952: }
ds@1952: if (!player->IsInGame())
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Client %d is not in game", params[1]);
ds@1952: }
ds@1952:
ds@1952: player_info_t info;
ds@1952: char *buffer;
ds@1952:
ds@1952: if (!GetPlayerInfo(params[1], &info) || !info.customFiles[0])
ds@1952: {
ds@1952: return 0;
ds@1952: }
ds@1952:
ds@1952: pContext->LocalToString(params[2], &buffer);
ds@1952: Q_binarytohex((byte *)&info.customFiles[0], sizeof(info.customFiles[0]), buffer, params[3]);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t GetServerNetStats(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: if (iserver == NULL)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("IServer interface not supported, file a bug report.");
ds@1952: }
ds@1952:
ds@1952: float in, out;
ds@1952: cell_t *pIn, *pOut;
ds@1952:
ds@1952: pContext->LocalToPhysAddr(params[1], &pIn);
ds@1952: pContext->LocalToPhysAddr(params[2], &pOut);
ds@1952: iserver->GetNetStats(in, out);
ds@1952:
ds@1952: *pIn = sp_ftoc(in);
ds@1952: *pOut = sp_ftoc(out);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
pred@1956: static cell_t WeaponEquip(IPluginContext *pContext, const cell_t *params)
pred@1956: {
pred@1956: static ValveCall *pCall = NULL;
pred@1956: if (!pCall)
pred@1956: {
pred@1956: ValvePassInfo pass[1];
pred@1956: InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
pred@1956: if (!CreateBaseCall("WeaponEquip", ValveCall_Player, NULL, pass, 1, &pCall))
pred@1956: {
pred@1956: return pContext->ThrowNativeError("\"WeaponEquip\" not supported by this mod");
pred@1956: } else if (!pCall) {
pred@1956: return pContext->ThrowNativeError("\"WeaponEquip\" wrapper failed to initialized");
pred@1956: }
pred@1956: }
pred@1956:
pred@1956: START_CALL();
pred@1956: DECODE_VALVE_PARAM(1, thisinfo, 0);
pred@1956: DECODE_VALVE_PARAM(2, vparams, 0);
pred@1956: FINISH_CALL_SIMPLE(NULL);
pred@1956:
pred@1956: return 1;
pred@1956: }
pred@1956:
dvander@2007: static cell_t ActivateEntity(IPluginContext *pContext, const cell_t *params)
dvander@2007: {
dvander@2007: static ValveCall *pCall = NULL;
dvander@2007: if (!pCall)
dvander@2007: {
dvander@2007: if (!CreateBaseCall("Activate", ValveCall_Entity, NULL, NULL, 0, &pCall))
dvander@2007: {
dvander@2007: return pContext->ThrowNativeError("\"Activate\" not supported by this mod");
dvander@2007: }
dvander@2007: else if (!pCall)
dvander@2007: {
dvander@2007: return pContext->ThrowNativeError("\"Activate\" wrapper failed to initialized");
dvander@2007: }
dvander@2007: }
dvander@2007:
dvander@2007: START_CALL();
dvander@2007: DECODE_VALVE_PARAM(1, thisinfo, 0);
dvander@2007: FINISH_CALL_SIMPLE(NULL);
dvander@2007:
dvander@2007: return 1;
dvander@2007: }
dvander@2007:
pred@2107: static cell_t SetClientInfo(IPluginContext *pContext, const cell_t *params)
pred@2107: {
pred@2107: IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
pred@2107: if (player == NULL)
pred@2107: {
pred@2107: return pContext->ThrowNativeError("Invalid client index %d", params[1]);
pred@2107: }
pred@2107: if (!player->IsConnected())
pred@2107: {
pred@2107: return pContext->ThrowNativeError("Client %d is not connected", params[1]);
pred@2107: }
pred@2107:
pred@2107: static ValveCall *pCall = NULL;
pred@2107: if (!pCall)
pred@2107: {
pred@2107: ValvePassInfo params[2];
pred@2107: InitPass(params[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
pred@2107: InitPass(params[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
pred@2107:
pred@2107: if (!CreateBaseCall("SetUserCvar", ValveCall_Entity, NULL, params, 2, &pCall))
pred@2107: {
pred@2107: return pContext->ThrowNativeError("\"SetUserCvar\" not supported by this mod");
pred@2107: }
pred@2107: else if (!pCall)
pred@2107: {
pred@2107: return pContext->ThrowNativeError("\"SetUserCvar\" wrapper failed to initialized");
pred@2107: }
pred@2107: }
pred@2107:
pred@2107: static int changedOffset = -1;
pred@2107:
pred@2107: if (changedOffset == -1)
pred@2107: {
pred@2107: if (!g_pGameConf->GetOffset("InfoChanged", &changedOffset))
pred@2107: {
pred@2107: return pContext->ThrowNativeError("\"SetUserCvar\" not supported by this mod");
pred@2107: }
pred@2107: }
pred@2107:
pred@2107: INetChannel *pNetChan = static_cast(engine->GetPlayerNetInfo(params[1]));
pred@2107: IClient *pClient = static_cast(pNetChan->GetMsgHandler());
pred@2107:
pred@2107: unsigned char *CGameClient = (unsigned char *)pClient - 4;
pred@2107:
pred@2107: START_CALL();
pred@2107: /* Not really a CBaseEntity* but this works */
pred@2107: CBaseEntity **ebuf = (CBaseEntity **)vptr;
pred@2107: *ebuf = (CBaseEntity *)CGameClient;
pred@2107: DECODE_VALVE_PARAM(2, vparams, 0);
pred@2107: DECODE_VALVE_PARAM(3, vparams, 1);
pred@2107: FINISH_CALL_SIMPLE(NULL);
pred@2107:
pred@2107: uint8_t* changed = (uint8_t *)(CGameClient + changedOffset);
pred@2107: *changed = 1;
pred@2107:
pred@2107: return 1;
pred@2107: }
pred@2107:
ds@1952: sp_nativeinfo_t g_Natives[] =
ds@1952: {
ds@1952: {"ExtinguishEntity", ExtinguishEntity},
ds@1952: {"ForcePlayerSuicide", ForcePlayerSuicide},
ds@1952: {"GivePlayerItem", GiveNamedItem},
ds@1952: {"GetPlayerWeaponSlot", GetPlayerWeaponSlot},
ds@1952: {"IgniteEntity", IgniteEntity},
ds@1952: {"RemovePlayerItem", RemovePlayerItem},
ds@1952: {"TeleportEntity", TeleportEntity},
ds@1952: {"SetClientViewEntity", SetClientViewEntity},
ds@1952: {"SetLightStyle", SetLightStyle},
ds@1952: {"SlapPlayer", SlapPlayer},
ds@1952: {"GetClientEyePosition", GetClientEyePosition},
ds@1952: {"GetClientEyeAngles", GetClientEyeAngles},
ds@1952: {"FindEntityByClassname", FindEntityByClassname},
ds@1952: {"CreateEntityByName", CreateEntityByName},
ds@1952: {"DispatchSpawn", DispatchSpawn},
ds@1952: {"DispatchKeyValue", DispatchKeyValue},
ds@1952: {"DispatchKeyValueFloat", DispatchKeyValueFloat},
ds@1952: {"DispatchKeyValueVector", DispatchKeyValueVector},
ds@1952: {"GetClientAimTarget", sm_GetClientAimTarget},
ds@1952: {"SetEntityModel", sm_SetEntityModel},
ds@1952: {"GetPlayerDecalFile", GetPlayerDecalFile},
ds@1952: {"GetServerNetStats", GetServerNetStats},
pred@1956: {"EquipPlayerWeapon", WeaponEquip},
dvander@2007: {"ActivateEntity", ActivateEntity},
pred@2107: {"SetClientInfo", SetClientInfo},
ds@1952: {NULL, NULL},
ds@1952: };