1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/extensions/sdktools/vnatives.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,899 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod SDKTools Extension
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include <stdlib.h>
1.36 +#include <sh_string.h>
1.37 +#include "extension.h"
1.38 +#include "vcallbuilder.h"
1.39 +#include "vnatives.h"
1.40 +#include "vhelpers.h"
1.41 +#include "vglobals.h"
1.42 +#include "CellRecipientFilter.h"
1.43 +
1.44 +SourceHook::List<ValveCall *> g_RegCalls;
1.45 +SourceHook::List<ICallWrapper *> g_CallWraps;
1.46 +
1.47 +inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsigned int flags, unsigned int decflags=0)
1.48 +{
1.49 + info.decflags = decflags;
1.50 + info.encflags = 0;
1.51 + info.flags = flags;
1.52 + info.type = type;
1.53 + info.vtype = vtype;
1.54 +}
1.55 +
1.56 +#define START_CALL() \
1.57 + unsigned char *vptr = pCall->stk_get();
1.58 +
1.59 +#define FINISH_CALL_SIMPLE(vret) \
1.60 + pCall->call->Execute(vptr, vret); \
1.61 + pCall->stk_put(vptr);
1.62 +
1.63 +#define ENCODE_VALVE_PARAM(num, which, vnum) \
1.64 + if (EncodeValveParam(pContext, \
1.65 + params[num], \
1.66 + pCall, \
1.67 + &pCall->which[vnum], \
1.68 + vptr) \
1.69 + == Data_Fail) \
1.70 + { \
1.71 + return 0; \
1.72 + }
1.73 +
1.74 +#define DECODE_VALVE_PARAM(num, which, vnum) \
1.75 + if (DecodeValveParam(pContext, \
1.76 + params[num], \
1.77 + pCall, \
1.78 + &pCall->which[vnum], \
1.79 + vptr) \
1.80 + == Data_Fail) \
1.81 + { \
1.82 + return 0; \
1.83 + }
1.84 +
1.85 +bool CreateBaseCall(const char *name,
1.86 + ValveCallType vcalltype,
1.87 + const ValvePassInfo *retinfo,
1.88 + const ValvePassInfo params[],
1.89 + unsigned int numParams,
1.90 + ValveCall **vaddr)
1.91 +{
1.92 + int offset;
1.93 + ValveCall *call;
1.94 + if (g_pGameConf->GetOffset(name, &offset))
1.95 + {
1.96 + call = CreateValveVCall(offset, vcalltype, retinfo, params, numParams);
1.97 + if (call)
1.98 + {
1.99 + g_RegCalls.push_back(call);
1.100 + }
1.101 + *vaddr = call;
1.102 + return true;
1.103 + } else {
1.104 + void *addr;
1.105 + if (g_pGameConf->GetMemSig(name, &addr))
1.106 + {
1.107 + call = CreateValveCall(addr, vcalltype, retinfo, params, numParams);
1.108 + if (call)
1.109 + {
1.110 + g_RegCalls.push_back(call);
1.111 + }
1.112 + *vaddr = call;
1.113 + return true;
1.114 + }
1.115 + }
1.116 + return false;
1.117 +}
1.118 +
1.119 +static cell_t RemovePlayerItem(IPluginContext *pContext, const cell_t *params)
1.120 +{
1.121 + static ValveCall *pCall = NULL;
1.122 + if (!pCall)
1.123 + {
1.124 + ValvePassInfo pass[2];
1.125 + InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
1.126 + InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
1.127 + if (!CreateBaseCall("RemovePlayerItem", ValveCall_Player, &pass[1], pass, 1, &pCall))
1.128 + {
1.129 + return pContext->ThrowNativeError("\"RemovePlayerItem\" not supported by this mod");
1.130 + } else if (!pCall) {
1.131 + return pContext->ThrowNativeError("\"RemovePlayerItem\" wrapper failed to initialized");
1.132 + }
1.133 + }
1.134 +
1.135 + bool ret;
1.136 + START_CALL();
1.137 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.138 + DECODE_VALVE_PARAM(2, vparams, 0);
1.139 + FINISH_CALL_SIMPLE(&ret);
1.140 + return ret ? 1 : 0;
1.141 +}
1.142 +
1.143 +static cell_t GiveNamedItem(IPluginContext *pContext, const cell_t *params)
1.144 +{
1.145 + static ValveCall *pCall = NULL;
1.146 + if (!pCall)
1.147 + {
1.148 + ValvePassInfo pass[3];
1.149 + InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1.150 + InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
1.151 + InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
1.152 + if (!CreateBaseCall("GiveNamedItem", ValveCall_Player, &pass[2], pass, 2, &pCall))
1.153 + {
1.154 + return pContext->ThrowNativeError("\"GiveNamedItem\" not supported by this mod");
1.155 + } else if (!pCall) {
1.156 + return pContext->ThrowNativeError("\"GiveNamedItem\" wrapper failed to initialized");
1.157 + }
1.158 + }
1.159 +
1.160 + CBaseEntity *pEntity = NULL;
1.161 + START_CALL();
1.162 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.163 + DECODE_VALVE_PARAM(2, vparams, 0);
1.164 + DECODE_VALVE_PARAM(3, vparams, 1);
1.165 + FINISH_CALL_SIMPLE(&pEntity);
1.166 +
1.167 + if (pEntity == NULL)
1.168 + {
1.169 + return -1;
1.170 + }
1.171 +
1.172 + edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
1.173 + if (!pEdict)
1.174 + {
1.175 + return -1;
1.176 + }
1.177 +
1.178 + return engine->IndexOfEdict(pEdict);
1.179 +}
1.180 +
1.181 +static cell_t GetPlayerWeaponSlot(IPluginContext *pContext, const cell_t *params)
1.182 +{
1.183 + static ValveCall *pCall = NULL;
1.184 + if (!pCall)
1.185 + {
1.186 + ValvePassInfo pass[2];
1.187 + InitPass(pass[0], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
1.188 + InitPass(pass[1], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
1.189 + if (!CreateBaseCall("Weapon_GetSlot", ValveCall_Player, &pass[1], pass, 1, &pCall))
1.190 + {
1.191 + return pContext->ThrowNativeError("\"Weapon_GetSlot\" not supported by this mod");
1.192 + } else if (!pCall) {
1.193 + return pContext->ThrowNativeError("\"Weapon_GetSlot\" wrapper failed to initialized");
1.194 + }
1.195 + }
1.196 +
1.197 + CBaseEntity *pEntity;
1.198 + START_CALL();
1.199 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.200 + DECODE_VALVE_PARAM(2, vparams, 0);
1.201 + FINISH_CALL_SIMPLE(&pEntity);
1.202 +
1.203 + if (pEntity == NULL)
1.204 + {
1.205 + return -1;
1.206 + }
1.207 +
1.208 + edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
1.209 + if (!pEdict)
1.210 + {
1.211 + return -1;
1.212 + }
1.213 +
1.214 + return engine->IndexOfEdict(pEdict);
1.215 +}
1.216 +
1.217 +static cell_t IgniteEntity(IPluginContext *pContext, const cell_t *params)
1.218 +{
1.219 + static ValveCall *pCall = NULL;
1.220 + if (!pCall)
1.221 + {
1.222 + ValvePassInfo pass[4];
1.223 + InitPass(pass[0], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
1.224 + InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
1.225 + InitPass(pass[2], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
1.226 + InitPass(pass[3], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
1.227 + if (!CreateBaseCall("Ignite", ValveCall_Entity, NULL, pass, 4, &pCall))
1.228 + {
1.229 + return pContext->ThrowNativeError("\"Ignite\" not supported by this mod");
1.230 + } else if (!pCall) {
1.231 + return pContext->ThrowNativeError("\"Ignite\" wrapper failed to initialized");
1.232 + }
1.233 + }
1.234 +
1.235 + START_CALL();
1.236 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.237 + DECODE_VALVE_PARAM(2, vparams, 0);
1.238 + DECODE_VALVE_PARAM(3, vparams, 1);
1.239 + DECODE_VALVE_PARAM(4, vparams, 2);
1.240 + DECODE_VALVE_PARAM(5, vparams, 3);
1.241 + FINISH_CALL_SIMPLE(NULL);
1.242 +
1.243 + return 1;
1.244 +}
1.245 +
1.246 +static cell_t ExtinguishEntity(IPluginContext *pContext, const cell_t *params)
1.247 +{
1.248 + static ValveCall *pCall = NULL;
1.249 + if (!pCall)
1.250 + {
1.251 + if (!CreateBaseCall("Extinguish", ValveCall_Entity, NULL, NULL, 0, &pCall))
1.252 + {
1.253 + return pContext->ThrowNativeError("\"Extinguish\" not supported by this mod");
1.254 + } else if (!pCall) {
1.255 + return pContext->ThrowNativeError("\"Extinguish\" wrapper failed to initialized");
1.256 + }
1.257 + }
1.258 +
1.259 + START_CALL();
1.260 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.261 + FINISH_CALL_SIMPLE(NULL);
1.262 +
1.263 + return 1;
1.264 +}
1.265 +
1.266 +static cell_t TeleportEntity(IPluginContext *pContext, const cell_t *params)
1.267 +{
1.268 + static ValveCall *pCall = NULL;
1.269 + if (!pCall)
1.270 + {
1.271 + ValvePassInfo pass[3];
1.272 + InitPass(pass[0], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
1.273 + InitPass(pass[1], Valve_QAngle, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
1.274 + InitPass(pass[2], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
1.275 + if (!CreateBaseCall("Teleport", ValveCall_Entity, NULL, pass, 3, &pCall))
1.276 + {
1.277 + return pContext->ThrowNativeError("\"Teleport\" not supported by this mod");
1.278 + } else if (!pCall) {
1.279 + return pContext->ThrowNativeError("\"Teleport\" wrapper failed to initialized");
1.280 + }
1.281 + }
1.282 +
1.283 + START_CALL();
1.284 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.285 + DECODE_VALVE_PARAM(2, vparams, 0);
1.286 + DECODE_VALVE_PARAM(3, vparams, 1);
1.287 + DECODE_VALVE_PARAM(4, vparams, 2);
1.288 + FINISH_CALL_SIMPLE(NULL);
1.289 +
1.290 + return 1;
1.291 +}
1.292 +
1.293 +#if defined ORANGEBOX_BUILD
1.294 +/* :TODO: This is Team Fortress 2 specific */
1.295 +static cell_t ForcePlayerSuicide(IPluginContext *pContext, const cell_t *params)
1.296 +{
1.297 + static ValveCall *pCall = NULL;
1.298 + if (!pCall)
1.299 + {
1.300 + ValvePassInfo pass[2];
1.301 + InitPass(pass[0], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
1.302 + InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
1.303 + if (!CreateBaseCall("CommitSuicide", ValveCall_Player, NULL, pass, 2, &pCall))
1.304 + {
1.305 + return pContext->ThrowNativeError("\"CommitSuicide\" not supported by this mod");
1.306 + }
1.307 + else if (!pCall)
1.308 + {
1.309 + return pContext->ThrowNativeError("\"CommitSuicide\" wrapper failed to initialized");
1.310 + }
1.311 + }
1.312 +
1.313 + START_CALL();
1.314 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.315 + *(bool *)(vptr + 4) = false;
1.316 + *(bool *)(vptr + 5) = false;
1.317 + FINISH_CALL_SIMPLE(NULL);
1.318 +
1.319 + return 1;
1.320 +}
1.321 +#else
1.322 +static cell_t ForcePlayerSuicide(IPluginContext *pContext, const cell_t *params)
1.323 +{
1.324 + static ValveCall *pCall = NULL;
1.325 + if (!pCall)
1.326 + {
1.327 + if (!CreateBaseCall("CommitSuicide", ValveCall_Player, NULL, NULL, 0, &pCall))
1.328 + {
1.329 + return pContext->ThrowNativeError("\"CommitSuicide\" not supported by this mod");
1.330 + } else if (!pCall) {
1.331 + return pContext->ThrowNativeError("\"CommitSuicide\" wrapper failed to initialized");
1.332 + }
1.333 + }
1.334 +
1.335 + START_CALL();
1.336 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.337 + FINISH_CALL_SIMPLE(NULL);
1.338 +
1.339 + return 1;
1.340 +}
1.341 +#endif
1.342 +
1.343 +static cell_t SetClientViewEntity(IPluginContext *pContext, const cell_t *params)
1.344 +{
1.345 + IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
1.346 + if (player == NULL)
1.347 + {
1.348 + return pContext->ThrowNativeError("Invalid client index %d", params[1]);
1.349 + }
1.350 + if (!player->IsInGame())
1.351 + {
1.352 + return pContext->ThrowNativeError("Client %d is not in game", params[1]);
1.353 + }
1.354 +
1.355 + edict_t *pEdict = engine->PEntityOfEntIndex(params[2]);
1.356 + if (!pEdict || pEdict->IsFree())
1.357 + {
1.358 + return pContext->ThrowNativeError("Entity %d is not valid", params[2]);
1.359 + }
1.360 +
1.361 + engine->SetView(player->GetEdict(), pEdict);
1.362 +
1.363 + return 1;
1.364 +}
1.365 +
1.366 +static SourceHook::String *g_lightstyle[MAX_LIGHTSTYLES] = {NULL};
1.367 +static cell_t SetLightStyle(IPluginContext *pContext, const cell_t *params)
1.368 +{
1.369 + int style = params[1];
1.370 + if (style >= MAX_LIGHTSTYLES)
1.371 + {
1.372 + return pContext->ThrowNativeError("Light style %d is invalid (range: 0-%d)", style, MAX_LIGHTSTYLES - 1);
1.373 + }
1.374 +
1.375 + if (g_lightstyle[style] == NULL)
1.376 + {
1.377 + /* We allocate and never free this because the Engine wants to hold onto it :\
1.378 + * in theory we could hook light style and know whether we're supposed to free
1.379 + * this or not on shutdown, but for ~4K of memory MAX, it doesn't seem worth it yet.
1.380 + * So, it's a :TODO:!
1.381 + */
1.382 + g_lightstyle[style] = new SourceHook::String();
1.383 + }
1.384 +
1.385 + char *str;
1.386 + pContext->LocalToString(params[2], &str);
1.387 +
1.388 + g_lightstyle[style]->assign(str);
1.389 +
1.390 + engine->LightStyle(style, g_lightstyle[style]->c_str());
1.391 +
1.392 + return 1;
1.393 +}
1.394 +
1.395 +static cell_t SlapPlayer(IPluginContext *pContext, const cell_t *params)
1.396 +{
1.397 + static bool s_slap_supported = false;
1.398 + static bool s_slap_setup = false;
1.399 + static ICallWrapper *s_teleport = NULL;
1.400 + static int s_health_offs = 0;
1.401 + static int s_sound_count = 0;
1.402 + static int s_frag_offs = 0;
1.403 +
1.404 + if (!s_slap_setup)
1.405 + {
1.406 + int tries = 0;
1.407 +
1.408 + s_slap_setup = true;
1.409 +
1.410 + if (IsTeleportSupported())
1.411 + {
1.412 + tries++;
1.413 + }
1.414 + if (IsGetVelocitySupported())
1.415 + {
1.416 + tries++;
1.417 + }
1.418 +
1.419 + /* Setup health */
1.420 + if (g_pGameConf->GetOffset("m_iHealth", &s_health_offs) && s_health_offs)
1.421 + {
1.422 + tries++;
1.423 + }
1.424 +
1.425 + if (tries == 3)
1.426 + {
1.427 + s_slap_supported = true;
1.428 +
1.429 + const char *key;
1.430 + if ((key = g_pGameConf->GetKeyValue("SlapSoundCount")) != NULL)
1.431 + {
1.432 + s_sound_count = atoi(key);
1.433 + }
1.434 + }
1.435 + }
1.436 +
1.437 + if (!s_slap_supported)
1.438 + {
1.439 + return pContext->ThrowNativeError("This function is not supported on this mod");
1.440 + }
1.441 +
1.442 + /* First check if the client is valid */
1.443 + int client = params[1];
1.444 + IGamePlayer *player = playerhelpers->GetGamePlayer(client);
1.445 + if (!player)
1.446 + {
1.447 + return pContext->ThrowNativeError("Client %d is not valid", client);
1.448 + } else if (!player->IsInGame()) {
1.449 + return pContext->ThrowNativeError("Client %d is not in game", client);
1.450 + }
1.451 +
1.452 + edict_t *pEdict = player->GetEdict();
1.453 + CBaseEntity *pEntity = pEdict->GetUnknown()->GetBaseEntity();
1.454 +
1.455 + /* See if we should be taking away health */
1.456 + bool should_slay = false;
1.457 + if (params[2])
1.458 + {
1.459 + int *health = (int *)((char *)pEntity + s_health_offs);
1.460 + if (*health - params[2] <= 0)
1.461 + {
1.462 + *health = 1;
1.463 + should_slay = true;
1.464 + } else {
1.465 + *health -= params[2];
1.466 + }
1.467 + }
1.468 +
1.469 + /* Teleport in a random direction - thank you, Mani!*/
1.470 + Vector velocity;
1.471 + GetVelocity(pEntity, &velocity, NULL);
1.472 + velocity.x += ((rand() % 180) + 50) * (((rand() % 2) == 1) ? -1 : 1);
1.473 + velocity.y += ((rand() % 180) + 50) * (((rand() % 2) == 1) ? -1 : 1);
1.474 + velocity.z += rand() % 200 + 100;
1.475 + Teleport(pEntity, NULL, NULL, &velocity);
1.476 +
1.477 + /* Play a random sound */
1.478 + if (params[3] && s_sound_count > 0)
1.479 + {
1.480 + char name[48];
1.481 + const char *sound_name;
1.482 + cell_t player_list[256], total_players = 0;
1.483 + int maxClients = playerhelpers->GetMaxClients();
1.484 +
1.485 + int r = (rand() % s_sound_count) + 1;
1.486 + snprintf(name, sizeof(name), "SlapSound%d", r);
1.487 +
1.488 + if ((sound_name = g_pGameConf->GetKeyValue(name)) != NULL)
1.489 + {
1.490 + IGamePlayer *other;
1.491 + for (int i=1; i<=maxClients; i++)
1.492 + {
1.493 + other = playerhelpers->GetGamePlayer(i);
1.494 + if (other->IsInGame())
1.495 + {
1.496 + player_list[total_players++] = i;
1.497 + }
1.498 + }
1.499 +
1.500 + const Vector & pos = pEdict->GetCollideable()->GetCollisionOrigin();
1.501 + CellRecipientFilter rf;
1.502 + rf.SetToReliable(true);
1.503 + rf.Initialize(player_list, total_players);
1.504 + engsound->EmitSound(rf, client, CHAN_AUTO, sound_name, VOL_NORM, ATTN_NORM, 0, PITCH_NORM, &pos);
1.505 + }
1.506 + }
1.507 +
1.508 + if (!s_frag_offs)
1.509 + {
1.510 + const char *frag_prop = g_pGameConf->GetKeyValue("m_iFrags");
1.511 + if (frag_prop)
1.512 + {
1.513 + datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
1.514 + typedescription_t *pType = gamehelpers->FindInDataMap(pMap, frag_prop);
1.515 + if (pType != NULL)
1.516 + {
1.517 + s_frag_offs = pType->fieldOffset[TD_OFFSET_NORMAL];
1.518 + }
1.519 + }
1.520 + if (!s_frag_offs)
1.521 + {
1.522 + s_frag_offs = -1;
1.523 + }
1.524 + }
1.525 +
1.526 + int old_frags = 0;
1.527 + if (s_frag_offs > 0)
1.528 + {
1.529 + old_frags = *(int *)((char *)pEntity + s_frag_offs);
1.530 + }
1.531 +
1.532 + /* Force suicide */
1.533 + if (should_slay)
1.534 + {
1.535 + pluginhelpers->ClientCommand(pEdict, "kill\n");
1.536 + }
1.537 +
1.538 + if (s_frag_offs > 0)
1.539 + {
1.540 + *(int *)((char *)pEntity + s_frag_offs) = old_frags;
1.541 + }
1.542 +
1.543 + return 1;
1.544 +}
1.545 +
1.546 +static cell_t GetClientEyePosition(IPluginContext *pContext, const cell_t *params)
1.547 +{
1.548 + IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
1.549 + if (player == NULL)
1.550 + {
1.551 + return pContext->ThrowNativeError("Invalid client index %d", params[1]);
1.552 + }
1.553 + if (!player->IsInGame())
1.554 + {
1.555 + return pContext->ThrowNativeError("Client %d is not in game", params[1]);
1.556 + }
1.557 +
1.558 + Vector pos;
1.559 + serverClients->ClientEarPosition(player->GetEdict(), &pos);
1.560 +
1.561 + cell_t *addr;
1.562 + pContext->LocalToPhysAddr(params[2], &addr);
1.563 + addr[0] = sp_ftoc(pos.x);
1.564 + addr[1] = sp_ftoc(pos.y);
1.565 + addr[2] = sp_ftoc(pos.z);
1.566 +
1.567 + return 1;
1.568 +}
1.569 +
1.570 +static cell_t GetClientEyeAngles(IPluginContext *pContext, const cell_t *params)
1.571 +{
1.572 + int client = params[1];
1.573 + IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
1.574 +
1.575 + if (!pPlayer)
1.576 + {
1.577 + return pContext->ThrowNativeError("Invalid client index %d", client);
1.578 + }
1.579 + else if (!pPlayer->IsInGame())
1.580 + {
1.581 + return pContext->ThrowNativeError("Client %d is not in game", client);
1.582 + }
1.583 +
1.584 + edict_t *pEdict = pPlayer->GetEdict();
1.585 + CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL;
1.586 +
1.587 + /* We always set the angles for backwards compatibility --
1.588 + * The original function had no return value.
1.589 + */
1.590 + QAngle angles;
1.591 + bool got_angles = false;
1.592 +
1.593 + if (pEntity != NULL)
1.594 + {
1.595 + got_angles = GetEyeAngles(pEntity, &angles);
1.596 + }
1.597 +
1.598 + cell_t *addr;
1.599 + pContext->LocalToPhysAddr(params[2], &addr);
1.600 + addr[0] = sp_ftoc(angles.x);
1.601 + addr[1] = sp_ftoc(angles.y);
1.602 + addr[2] = sp_ftoc(angles.z);
1.603 +
1.604 + return got_angles ? 1 : 0;
1.605 +}
1.606 +
1.607 +static cell_t FindEntityByClassname(IPluginContext *pContext, const cell_t *params)
1.608 +{
1.609 + static ValveCall *pCall = NULL;
1.610 + if (!pCall)
1.611 + {
1.612 + ValvePassInfo pass[3];
1.613 + InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL|VDECODE_FLAG_ALLOWWORLD);
1.614 + InitPass(pass[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1.615 + InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
1.616 + if (!CreateBaseCall("FindEntityByClassname", ValveCall_EntityList, &pass[2], pass, 2, &pCall))
1.617 + {
1.618 + return pContext->ThrowNativeError("\"FindEntityByClassname\" not supported by this mod");
1.619 + } else if (!pCall) {
1.620 + return pContext->ThrowNativeError("\"FindEntityByClassname\" wrapper failed to initialized");
1.621 + }
1.622 + }
1.623 +
1.624 + CBaseEntity *pEntity;
1.625 + START_CALL();
1.626 + *(void **)vptr = g_EntList;
1.627 + DECODE_VALVE_PARAM(1, vparams, 0);
1.628 + DECODE_VALVE_PARAM(2, vparams, 1);
1.629 + FINISH_CALL_SIMPLE(&pEntity);
1.630 +
1.631 + if (pEntity == NULL)
1.632 + {
1.633 + return -1;
1.634 + }
1.635 +
1.636 + edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
1.637 + if (!pEdict)
1.638 + {
1.639 + return -1;
1.640 + }
1.641 +
1.642 + return engine->IndexOfEdict(pEdict);
1.643 +}
1.644 +
1.645 +static cell_t CreateEntityByName(IPluginContext *pContext, const cell_t *params)
1.646 +{
1.647 + static ValveCall *pCall = NULL;
1.648 + if (!pCall)
1.649 + {
1.650 + ValvePassInfo pass[3];
1.651 + InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1.652 + InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
1.653 + InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
1.654 + if (!CreateBaseCall("CreateEntityByName", ValveCall_Static, &pass[2], pass, 2, &pCall))
1.655 + {
1.656 + return pContext->ThrowNativeError("\"CreateEntityByName\" not supported by this mod");
1.657 + } else if (!pCall) {
1.658 + return pContext->ThrowNativeError("\"CreateEntityByName\" wrapper failed to initialized");
1.659 + }
1.660 + }
1.661 +
1.662 + CBaseEntity *pEntity = NULL;
1.663 + START_CALL();
1.664 + DECODE_VALVE_PARAM(1, vparams, 0);
1.665 + DECODE_VALVE_PARAM(2, vparams, 1);
1.666 + FINISH_CALL_SIMPLE(&pEntity);
1.667 +
1.668 + if (pEntity == NULL)
1.669 + {
1.670 + return -1;
1.671 + }
1.672 +
1.673 + edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
1.674 + if (!pEdict)
1.675 + {
1.676 + return -1;
1.677 + }
1.678 +
1.679 + return engine->IndexOfEdict(pEdict);
1.680 +}
1.681 +
1.682 +static cell_t DispatchSpawn(IPluginContext *pContext, const cell_t *params)
1.683 +{
1.684 + static ValveCall *pCall = NULL;
1.685 + if (!pCall)
1.686 + {
1.687 + ValvePassInfo pass[2];
1.688 + InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
1.689 + InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
1.690 + if (!CreateBaseCall("DispatchSpawn", ValveCall_Static, &pass[1], pass, 1, &pCall))
1.691 + {
1.692 + return pContext->ThrowNativeError("\"DispatchSpawn\" not supported by this mod");
1.693 + } else if (!pCall) {
1.694 + return pContext->ThrowNativeError("\"DispatchSpawn\" wrapper failed to initialized");
1.695 + }
1.696 + }
1.697 +
1.698 + int ret;
1.699 + START_CALL();
1.700 + DECODE_VALVE_PARAM(1, vparams, 0);
1.701 + FINISH_CALL_SIMPLE(&ret);
1.702 +
1.703 + return (ret == -1) ? 0 : 1;
1.704 +}
1.705 +
1.706 +static cell_t DispatchKeyValue(IPluginContext *pContext, const cell_t *params)
1.707 +{
1.708 + static ValveCall *pCall = NULL;
1.709 + if (!pCall)
1.710 + {
1.711 + ValvePassInfo pass[3];
1.712 + InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1.713 + InitPass(pass[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1.714 + InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
1.715 + if (!CreateBaseCall("DispatchKeyValue", ValveCall_Entity, &pass[2], pass, 2, &pCall))
1.716 + {
1.717 + return pContext->ThrowNativeError("\"DispatchKeyValue\" not supported by this mod");
1.718 + } else if (!pCall) {
1.719 + return pContext->ThrowNativeError("\"DispatchKeyValue\" wrapper failed to initialized");
1.720 + }
1.721 + }
1.722 +
1.723 + bool ret;
1.724 + START_CALL();
1.725 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.726 + DECODE_VALVE_PARAM(2, vparams, 0);
1.727 + DECODE_VALVE_PARAM(3, vparams, 1);
1.728 + FINISH_CALL_SIMPLE(&ret);
1.729 +
1.730 + return (ret) ? 1 : 0;
1.731 +}
1.732 +
1.733 +static cell_t DispatchKeyValueFloat(IPluginContext *pContext, const cell_t *params)
1.734 +{
1.735 + static ValveCall *pCall = NULL;
1.736 + if (!pCall)
1.737 + {
1.738 + ValvePassInfo pass[3];
1.739 + InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1.740 + InitPass(pass[1], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
1.741 + InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
1.742 + if (!CreateBaseCall("DispatchKeyValueFloat", ValveCall_Entity, &pass[2], pass, 2, &pCall))
1.743 + {
1.744 + return pContext->ThrowNativeError("\"DispatchKeyValueFloat\" not supported by this mod");
1.745 + } else if (!pCall) {
1.746 + return pContext->ThrowNativeError("\"DispatchKeyValueFloat\" wrapper failed to initialized");
1.747 + }
1.748 + }
1.749 +
1.750 + bool ret;
1.751 + START_CALL();
1.752 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.753 + DECODE_VALVE_PARAM(2, vparams, 0);
1.754 + DECODE_VALVE_PARAM(3, vparams, 1);
1.755 + FINISH_CALL_SIMPLE(&ret);
1.756 +
1.757 + return (ret) ? 1 : 0;
1.758 +}
1.759 +
1.760 +static cell_t DispatchKeyValueVector(IPluginContext *pContext, const cell_t *params)
1.761 +{
1.762 + static ValveCall *pCall = NULL;
1.763 + if (!pCall)
1.764 + {
1.765 + ValvePassInfo pass[3];
1.766 + InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1.767 +#if defined ORANGEBOX_BUILD
1.768 + InitPass(pass[1], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL);
1.769 +#else
1.770 + InitPass(pass[1], Valve_Vector, PassType_Object, PASSFLAG_BYVAL|PASSFLAG_OCTOR|PASSFLAG_OASSIGNOP);
1.771 +#endif
1.772 + InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
1.773 + if (!CreateBaseCall("DispatchKeyValueVector", ValveCall_Entity, &pass[2], pass, 2, &pCall))
1.774 + {
1.775 + return pContext->ThrowNativeError("\"DispatchKeyValueVector\" not supported by this mod");
1.776 + } else if (!pCall) {
1.777 + return pContext->ThrowNativeError("\"DispatchKeyValueVector\" wrapper failed to initialized");
1.778 + }
1.779 + }
1.780 +
1.781 + bool ret;
1.782 + START_CALL();
1.783 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.784 + DECODE_VALVE_PARAM(2, vparams, 0);
1.785 + DECODE_VALVE_PARAM(3, vparams, 1);
1.786 + FINISH_CALL_SIMPLE(&ret);
1.787 +
1.788 + return (ret) ? 1 : 0;
1.789 +}
1.790 +
1.791 +static cell_t sm_GetClientAimTarget(IPluginContext *pContext, const cell_t *params)
1.792 +{
1.793 + int client = params[1];
1.794 + IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
1.795 +
1.796 + if (!pPlayer)
1.797 + {
1.798 + return pContext->ThrowNativeError("Invalid client index %d", client);
1.799 + }
1.800 + else if (!pPlayer->IsInGame())
1.801 + {
1.802 + return pContext->ThrowNativeError("Client %d is not in game", client);
1.803 + }
1.804 +
1.805 + return GetClientAimTarget(pPlayer->GetEdict(), params[2] ? true : false);
1.806 +}
1.807 +
1.808 +static cell_t sm_SetEntityModel(IPluginContext *pContext, const cell_t *params)
1.809 +{
1.810 + static ValveCall *pCall = NULL;
1.811 + if (!pCall)
1.812 + {
1.813 + ValvePassInfo pass[1];
1.814 + InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
1.815 + if (!CreateBaseCall("SetEntityModel", ValveCall_Entity, NULL, pass, 1, &pCall))
1.816 + {
1.817 + return pContext->ThrowNativeError("\"SetEntityModel\" not supported by this mod");
1.818 + } else if (!pCall) {
1.819 + return pContext->ThrowNativeError("\"SetEntityModel\" wrapper failed to initialized");
1.820 + }
1.821 + }
1.822 +
1.823 + START_CALL();
1.824 + DECODE_VALVE_PARAM(1, thisinfo, 0);
1.825 + DECODE_VALVE_PARAM(2, vparams, 0);
1.826 + FINISH_CALL_SIMPLE(NULL);
1.827 +
1.828 + return 1;
1.829 +}
1.830 +
1.831 +static cell_t GetPlayerDecalFile(IPluginContext *pContext, const cell_t *params)
1.832 +{
1.833 + IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
1.834 + if (player == NULL)
1.835 + {
1.836 + return pContext->ThrowNativeError("Invalid client index %d", params[1]);
1.837 + }
1.838 + if (!player->IsInGame())
1.839 + {
1.840 + return pContext->ThrowNativeError("Client %d is not in game", params[1]);
1.841 + }
1.842 +
1.843 + player_info_t info;
1.844 + char *buffer;
1.845 +
1.846 + if (!GetPlayerInfo(params[1], &info) || !info.customFiles[0])
1.847 + {
1.848 + return 0;
1.849 + }
1.850 +
1.851 + pContext->LocalToString(params[2], &buffer);
1.852 + Q_binarytohex((byte *)&info.customFiles[0], sizeof(info.customFiles[0]), buffer, params[3]);
1.853 +
1.854 + return 1;
1.855 +}
1.856 +
1.857 +static cell_t GetServerNetStats(IPluginContext *pContext, const cell_t *params)
1.858 +{
1.859 + if (iserver == NULL)
1.860 + {
1.861 + return pContext->ThrowNativeError("IServer interface not supported, file a bug report.");
1.862 + }
1.863 +
1.864 + float in, out;
1.865 + cell_t *pIn, *pOut;
1.866 +
1.867 + pContext->LocalToPhysAddr(params[1], &pIn);
1.868 + pContext->LocalToPhysAddr(params[2], &pOut);
1.869 + iserver->GetNetStats(in, out);
1.870 +
1.871 + *pIn = sp_ftoc(in);
1.872 + *pOut = sp_ftoc(out);
1.873 +
1.874 + return 1;
1.875 +}
1.876 +
1.877 +sp_nativeinfo_t g_Natives[] =
1.878 +{
1.879 + {"ExtinguishEntity", ExtinguishEntity},
1.880 + {"ForcePlayerSuicide", ForcePlayerSuicide},
1.881 + {"GivePlayerItem", GiveNamedItem},
1.882 + {"GetPlayerWeaponSlot", GetPlayerWeaponSlot},
1.883 + {"IgniteEntity", IgniteEntity},
1.884 + {"RemovePlayerItem", RemovePlayerItem},
1.885 + {"TeleportEntity", TeleportEntity},
1.886 + {"SetClientViewEntity", SetClientViewEntity},
1.887 + {"SetLightStyle", SetLightStyle},
1.888 + {"SlapPlayer", SlapPlayer},
1.889 + {"GetClientEyePosition", GetClientEyePosition},
1.890 + {"GetClientEyeAngles", GetClientEyeAngles},
1.891 + {"FindEntityByClassname", FindEntityByClassname},
1.892 + {"CreateEntityByName", CreateEntityByName},
1.893 + {"DispatchSpawn", DispatchSpawn},
1.894 + {"DispatchKeyValue", DispatchKeyValue},
1.895 + {"DispatchKeyValueFloat", DispatchKeyValueFloat},
1.896 + {"DispatchKeyValueVector", DispatchKeyValueVector},
1.897 + {"GetClientAimTarget", sm_GetClientAimTarget},
1.898 + {"SetEntityModel", sm_SetEntityModel},
1.899 + {"GetPlayerDecalFile", GetPlayerDecalFile},
1.900 + {"GetServerNetStats", GetServerNetStats},
1.901 + {NULL, NULL},
1.902 +};