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: };