From 63fa8a2335bb8d812b55ccd2b4583d82af04c735 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Feb 2004 03:29:47 +0000 Subject: [PATCH] Initial Import. --- dlls/engine/build.sh | 8 + dlls/engine/meta_api.cpp | 2843 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 2851 insertions(+) create mode 100755 dlls/engine/build.sh create mode 100755 dlls/engine/meta_api.cpp diff --git a/dlls/engine/build.sh b/dlls/engine/build.sh new file mode 100755 index 00000000..aedc749f --- /dev/null +++ b/dlls/engine/build.sh @@ -0,0 +1,8 @@ +rm meta_api.o +rm engine.so + +#use VexD's optimizations + +gcc -static -march=i586 -O6 -ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations -fno-exceptions -fno-rtti -s -Wall -Wno-unknown-pragmas -DOPT_TYPE=\"optimized\" -fPIC -I. -I../metamod -I../../multiplayer/engine -I../../multiplayer/common -I../../multiplayer/pm_shared -I../../multiplayer/dlls -I../../multiplayer -c meta_api.cpp -o meta_api.o + +gcc -static -march=i586 -O6 -ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 -falign-jumps=2 -falign-functions=2 -fno-exceptions -fno-rtti -s -Wall -Wno-unknown-pragmas -DOPT_TYPE=\"optimized\" -shared -ldl -lm -lstdc++ meta_api.o -o engine.so diff --git a/dlls/engine/meta_api.cpp b/dlls/engine/meta_api.cpp new file mode 100755 index 00000000..17e6d9fd --- /dev/null +++ b/dlls/engine/meta_api.cpp @@ -0,0 +1,2843 @@ +/* <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> + * Project:Vexd Utility Module + * By: Vexd + * + * Purpose:This module provides more options for working with entities and other + * things that are half-life related using amxmod scripts. + * + * Notes: This module is in 1 large file because it used to be multiple smaller + * modules. I never intended this module to have so many functions, but I kept + * adding things, never splitting into more files, so it ended up like this. + * You must have the Half-life software development kit, and the include directories + * properly set up to compile this module. You also may need the metamod source. + * + * Licence: + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Full licence can be found at: + * http://www.gnu.org/licenses/gpl.txt + * <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> */ + +#include +#include +#include +#include "sdk_util.h" +#include +#include "modules.h" +#include +#include + +meta_globals_t *gpMetaGlobals; +gamedll_funcs_t *gpGamedllFuncs; +mutil_funcs_t *gpMetaUtilFuncs; +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; +pfnamx_engine_g* g_engAmxFunc; +pfnms_engine_g* g_engModuleFunc; +static META_FUNCTIONS gMetaFunctionTable; +DLL_FUNCTIONS gFunctionTable; +enginefuncs_t meta_engfuncs; + +struct AmxCall { + plugin_t *pPlugin; + int iFunctionIdx; +}; + +std::vector vTouchCallList; +std::vector vServerFrameCallList; + +//This was originally by VexD + +#define NAME "Engine Module" +#define AUTHOR "BAILOPAN" +#define VERSION "0.1" +#define URL "No Website" +#define LOGTAG "AMXXE" +#define DATE __DATE__ + +#define AMS_OFFSET 0.01 + +#define SPEAK_NORMAL 0 +#define SPEAK_MUTED 1 +#define SPEAK_ALL 2 +#define SPEAK_LISTENALL 4 + +#define CAMERA_NONE 0 +#define CAMERA_3RDPERSON 1 +#define CAMERA_UPLEFT 2 +#define CAMERA_TOPDOWN 3 + +#define MAX_MESSAGES 255 + +#define BLOCK_NOT 0 +#define BLOCK_ONCE 1 +#define BLOCK_SET 2 + +enum { + gamestate, + oldbuttons, + groupinfo, + iuser1, + iuser2, + iuser3, + iuser4, + weaponanim, + pushmsec, + bInDuck, + flTimeStepSound, + flSwimTime, + flDuckTime, + iStepLeft, + movetype, + solid, + skin, + body, + effects, + light_level, + sequence, + gaitsequence, + modelindex, + playerclass, + waterlevel, + watertype, + spawnflags, + flags, + colormap, + team, + fixangle, + weapons, + rendermode, + renderfx, + button, + impulse, + deadflag, +}; + +enum { + impacttime, + starttime, + idealpitch, + pitch_speed, + ideal_yaw, + yaw_speed, + ltime, + nextthink, + gravity, + friction, + frame, + animtime, + framerate, + health, + frags, + takedamage, + max_health, + teleport_time, + armortype, + armorvalue, + dmg_take, + dmg_save, + dmg, + dmgtime, + speed, + air_finished, + pain_finished, + radsuit_finished, + scale, + renderamt, + maxspeed, + fov, + flFallVelocity, + fuser1, + fuser2, + fuser3, + fuser4, +}; + +enum { + origin, + oldorigin, + velocity, + basevelocity, + clbasevelocity, + movedir, + angles, + avelocity, + punchangle, + v_angle, + endpos, + startpos, + absmin, + absmax, + mins, + maxs, + size, + rendercolor, + view_ofs, + vuser1, + vuser2, + vuser3, + vuser4, +}; + +enum { + chain, + dmg_inflictor, + enemy, + aiment, + owner, + groundentity, + pContainingEntity, + euser1, + euser2, + euser3, + euser4, +}; + +enum { + classname, + globalname, + model, + target, + targetname, + netname, + message, + noise, + noise1, + noise2, + noise3, + viewmodel, + weaponmodel, +}; + +enum { + controller1, + controller2, + controller3, + controller4, + blending1, + blending2, +}; + +struct PlayerInfo { + bool bModeled; + char szModel[32]; + float fModelSet; + + int iSpeakFlags; + + edict_t *pViewEnt; + int iViewType; + int iRenderMode; + float fRenderAmt; +}; + +PlayerInfo PlInfo[33]; + +struct GlobalInfo { + bool bLights; + float fNextLights; + char *szLastLights[128]; + char *szRealLights[128]; + + int iMessageBlock[MAX_MESSAGES]; + bool bBlocking; +}; + +GlobalInfo GlInfo; + +cvar_t vx_version = {"vx_version", VERSION, FCVAR_SERVER, 0}; + +plugin_info_t Plugin_info = { + META_INTERFACE_VERSION, + NAME, + VERSION, + DATE, + AUTHOR, + URL, + LOGTAG, + PT_STARTUP, + PT_NEVER, +}; + +module_info_s AMXInfo = { + NAME, + AUTHOR, + VERSION, + AMX_INTERFACE_VERSION, + RELOAD_MODULE, +}; + +/********************* Begin Utility Functions ******************************/ + +// Finds edict points that are in a sphere, used in RadiusDamage. +edict_t *UTIL_FindEntityInSphere(edict_t *pStart, const Vector &vecCenter, float flRadius) { + if (!pStart) pStart = NULL; + + pStart = FIND_ENTITY_IN_SPHERE(pStart, vecCenter, flRadius); + + if (!FNullEnt(pStart)) return pStart; + return NULL; +} + +// Makes A Half-Life string (which is just an integer, an index of the string +// half-life uses to refer to the string) out of an AMX cell. +int AMX_MAKE_STRING(AMX *oPlugin, cell tParam, int &iLength) { + char *szNewValue = GET_AMXSTRING(oPlugin, tParam, 0, iLength); + + char* szCopyValue = new char[iLength + 1]; + strncpy(szCopyValue , szNewValue, iLength); + *(szCopyValue + iLength) = '\0'; + + return MAKE_STRING(szCopyValue); +} + +// Makes a char pointer out of an AMX cell. +char *AMX_GET_STRING(AMX *oPlugin, cell tParam, int &iLength) { + char *szNewValue = GET_AMXSTRING(oPlugin, tParam, 0, iLength); + + char* szCopyValue = new char[iLength + 1]; + strncpy(szCopyValue , szNewValue, iLength); + *(szCopyValue + iLength) = '\0'; + + return szCopyValue; +} + +/********************* Begin Exported Functions *****************************/ + +// Get an integer from an entities entvars. +static cell AMX_NATIVE_CALL Entvars_Get_Int(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + int iRetValue = 0; + + // Is it a valid entity? + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + // get its edict pointer. + edict_t* pEntity = INDEXENT(iTargetEntity); + + // Is it a real entity? + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case gamestate: + iRetValue = pEntity->v.gamestate; + break; + case oldbuttons: + iRetValue = pEntity->v.oldbuttons; + break; + case groupinfo: + iRetValue = pEntity->v.groupinfo; + break; + case iuser1: + iRetValue = pEntity->v.iuser1; + break; + case iuser2: + iRetValue = pEntity->v.iuser2; + break; + case iuser3: + iRetValue = pEntity->v.iuser3; + break; + case iuser4: + iRetValue = pEntity->v.iuser4; + break; + case weaponanim: + iRetValue = pEntity->v.weaponanim; + break; + case pushmsec: + iRetValue = pEntity->v.pushmsec; + break; + case bInDuck: + iRetValue = pEntity->v.bInDuck; + break; + case flTimeStepSound: + iRetValue = pEntity->v.flTimeStepSound; + break; + case flSwimTime: + iRetValue = pEntity->v.flSwimTime; + break; + case flDuckTime: + iRetValue = pEntity->v.flDuckTime; + break; + case iStepLeft: + iRetValue = pEntity->v.iStepLeft; + break; + case movetype: + iRetValue = pEntity->v.movetype; + break; + case solid: + iRetValue = pEntity->v.solid; + break; + case skin: + iRetValue = pEntity->v.skin; + break; + case body: + iRetValue = pEntity->v.body; + break; + case effects: + iRetValue = pEntity->v.effects; + break; + case light_level: + iRetValue = pEntity->v.light_level; + break; + case sequence: + iRetValue = pEntity->v.sequence; + break; + case gaitsequence: + iRetValue = pEntity->v.gaitsequence; + break; + case modelindex: + iRetValue = pEntity->v.modelindex; + break; + case playerclass: + iRetValue = pEntity->v.playerclass; + break; + case waterlevel: + iRetValue = pEntity->v.waterlevel; + break; + case watertype: + iRetValue = pEntity->v.watertype; + break; + case spawnflags: + iRetValue = pEntity->v.spawnflags; + break; + case flags: + iRetValue = pEntity->v.flags; + break; + case colormap: + iRetValue = pEntity->v.colormap; + break; + case team: + iRetValue = pEntity->v.team; + break; + case fixangle: + iRetValue = pEntity->v.fixangle; + break; + case weapons: + iRetValue = pEntity->v.weapons; + break; + case rendermode: + iRetValue = pEntity->v.rendermode; + break; + case renderfx: + iRetValue = pEntity->v.renderfx; + break; + case button: + iRetValue = pEntity->v.button; + break; + case impulse: + iRetValue = pEntity->v.impulse; + break; + case deadflag: + iRetValue = pEntity->v.deadflag; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return iRetValue; +} + +// Set an integer in entvars. mostly the same as get_integer. look there for comments. +static cell AMX_NATIVE_CALL Entvars_Set_Int(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + int iNewValue = params[3]; + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEntity = INDEXENT(iTargetEntity); + + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case gamestate: + pEntity->v.gamestate = iNewValue; + break; + case oldbuttons: + pEntity->v.oldbuttons = iNewValue; + break; + case groupinfo: + pEntity->v.groupinfo = iNewValue; + break; + case iuser1: + pEntity->v.iuser1 = iNewValue; + break; + case iuser2: + pEntity->v.iuser2 = iNewValue; + break; + case iuser3: + pEntity->v.iuser3 = iNewValue; + break; + case iuser4: + pEntity->v.iuser4 = iNewValue; + break; + case weaponanim: + pEntity->v.weaponanim = iNewValue; + break; + case pushmsec: + pEntity->v.pushmsec = iNewValue; + break; + case bInDuck: + pEntity->v.bInDuck = iNewValue; + break; + case flTimeStepSound: + pEntity->v.flTimeStepSound = iNewValue; + break; + case flSwimTime: + pEntity->v.flSwimTime = iNewValue; + break; + case flDuckTime: + pEntity->v.flDuckTime = iNewValue; + break; + case iStepLeft: + pEntity->v.iStepLeft = iNewValue; + break; + case movetype: + pEntity->v.movetype = iNewValue; + break; + case solid: + pEntity->v.solid = iNewValue; + break; + case skin: + pEntity->v.skin = iNewValue; + break; + case body: + pEntity->v.body = iNewValue; + break; + case effects: + pEntity->v.effects = iNewValue; + break; + case light_level: + pEntity->v.light_level = iNewValue; + break; + case sequence: + pEntity->v.sequence = iNewValue; + break; + case gaitsequence: + pEntity->v.gaitsequence = iNewValue; + break; + case modelindex: + pEntity->v.modelindex = iNewValue; + break; + case playerclass: + pEntity->v.playerclass = iNewValue; + break; + case waterlevel: + pEntity->v.waterlevel = iNewValue; + break; + case watertype: + pEntity->v.watertype = iNewValue; + break; + case spawnflags: + pEntity->v.spawnflags = iNewValue; + break; + case flags: + pEntity->v.flags = iNewValue; + break; + case colormap: + pEntity->v.colormap = iNewValue; + break; + case team: + pEntity->v.team = iNewValue; + break; + case fixangle: + pEntity->v.fixangle = iNewValue; + break; + case weapons: + pEntity->v.weapons = iNewValue; + break; + case rendermode: + pEntity->v.rendermode = iNewValue; + break; + case renderfx: + pEntity->v.renderfx = iNewValue; + break; + case button: + pEntity->v.button = iNewValue; + break; + case impulse: + pEntity->v.impulse = iNewValue; + break; + case deadflag: + pEntity->v.deadflag = iNewValue; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return 1; +} + +// Gets a float out of entvars. +static cell AMX_NATIVE_CALL Entvars_Get_Float(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + float fRetValue = 0; + + // Valid entity? + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + // Get pointer. + edict_t* pEntity = INDEXENT(iTargetEntity); + + // is it a valid entity? + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case impacttime: + fRetValue = pEntity->v.impacttime; + break; + case starttime: + fRetValue = pEntity->v.starttime; + break; + case idealpitch: + fRetValue = pEntity->v.idealpitch; + break; + case pitch_speed: + fRetValue = pEntity->v.pitch_speed; + break; + case ideal_yaw: + fRetValue = pEntity->v.ideal_yaw; + break; + case yaw_speed: + fRetValue = pEntity->v.yaw_speed; + break; + case ltime: + fRetValue = pEntity->v.ltime; + break; + case nextthink: + fRetValue = pEntity->v.nextthink; + break; + case gravity: + fRetValue = pEntity->v.gravity; + break; + case friction: + fRetValue = pEntity->v.friction; + break; + case frame: + fRetValue = pEntity->v.frame; + break; + case animtime: + fRetValue = pEntity->v.animtime; + break; + case framerate: + fRetValue = pEntity->v.framerate; + break; + case health: + fRetValue = pEntity->v.health; + break; + case frags: + fRetValue = pEntity->v.frags; + break; + case takedamage: + fRetValue = pEntity->v.takedamage; + break; + case max_health: + fRetValue = pEntity->v.max_health; + break; + case teleport_time: + fRetValue = pEntity->v.teleport_time; + break; + case armortype: + fRetValue = pEntity->v.armortype; + break; + case armorvalue: + fRetValue = pEntity->v.armorvalue; + break; + case dmg_take: + fRetValue = pEntity->v.dmg_take; + break; + case dmg_save: + fRetValue = pEntity->v.dmg_save; + break; + case dmg: + fRetValue = pEntity->v.dmg; + break; + case dmgtime: + fRetValue = pEntity->v.dmgtime; + break; + case speed: + fRetValue = pEntity->v.speed; + break; + case air_finished: + fRetValue = pEntity->v.air_finished; + break; + case pain_finished: + fRetValue = pEntity->v.pain_finished; + break; + case radsuit_finished: + fRetValue = pEntity->v.radsuit_finished; + break; + case scale: + fRetValue = pEntity->v.scale; + break; + case renderamt: + fRetValue = pEntity->v.renderamt; + break; + case maxspeed: + fRetValue = pEntity->v.maxspeed; + break; + case fov: + fRetValue = pEntity->v.fov; + break; + case flFallVelocity: + fRetValue = pEntity->v.flFallVelocity; + break; + case fuser1: + fRetValue = pEntity->v.fuser1; + break; + case fuser2: + fRetValue = pEntity->v.fuser2; + break; + case fuser3: + fRetValue = pEntity->v.fuser3; + break; + case fuser4: + fRetValue = pEntity->v.fuser4; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return *(cell*)((void *)&fRetValue); +} + +// Almost the same as Get_float, look there for comments. +static cell AMX_NATIVE_CALL Entvars_Set_Float(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + float fNewValue = *(float *)((void *)¶ms[3]); + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEntity = INDEXENT(iTargetEntity); + + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case impacttime: + pEntity->v.impacttime = fNewValue; + break; + case starttime: + pEntity->v.starttime = fNewValue; + break; + case idealpitch: + pEntity->v.idealpitch = fNewValue; + break; + case pitch_speed: + pEntity->v.pitch_speed = fNewValue; + break; + case ideal_yaw: + pEntity->v.ideal_yaw = fNewValue; + break; + case yaw_speed: + pEntity->v.yaw_speed = fNewValue; + break; + case ltime: + pEntity->v.ltime = fNewValue; + break; + case nextthink: + pEntity->v.nextthink = fNewValue; + break; + case gravity: + pEntity->v.gravity = fNewValue; + break; + case friction: + pEntity->v.friction = fNewValue; + break; + case frame: + pEntity->v.frame = fNewValue; + break; + case animtime: + pEntity->v.animtime = fNewValue; + break; + case framerate: + pEntity->v.framerate = fNewValue; + break; + case health: + pEntity->v.health = fNewValue; + break; + case frags: + pEntity->v.frags = fNewValue; + break; + case takedamage: + pEntity->v.takedamage = fNewValue; + break; + case max_health: + pEntity->v.max_health = fNewValue; + break; + case teleport_time: + pEntity->v.teleport_time = fNewValue; + break; + case armortype: + pEntity->v.armortype = fNewValue; + break; + case armorvalue: + pEntity->v.armorvalue = fNewValue; + break; + case dmg_take: + pEntity->v.dmg_take = fNewValue; + break; + case dmg_save: + pEntity->v.dmg_save = fNewValue; + break; + case dmg: + pEntity->v.dmg = fNewValue; + break; + case dmgtime: + pEntity->v.dmgtime = fNewValue; + break; + case speed: + pEntity->v.speed = fNewValue; + break; + case air_finished: + pEntity->v.air_finished = fNewValue; + break; + case pain_finished: + pEntity->v.pain_finished = fNewValue; + break; + case radsuit_finished: + pEntity->v.radsuit_finished = fNewValue; + break; + case scale: + pEntity->v.scale = fNewValue; + break; + case renderamt: + pEntity->v.renderamt = fNewValue; + break; + case maxspeed: + pEntity->v.maxspeed = fNewValue; + break; + case fov: + pEntity->v.fov = fNewValue; + break; + case flFallVelocity: + pEntity->v.flFallVelocity = fNewValue; + break; + case fuser1: + pEntity->v.fuser1 = fNewValue; + break; + case fuser2: + pEntity->v.fuser2 = fNewValue; + break; + case fuser3: + pEntity->v.fuser3 = fNewValue; + break; + case fuser4: + pEntity->v.fuser4 = fNewValue; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return 1; +} + +// Gets a vector from entvars. I use a float[3] to describe half life vectors, +// as this is how half-life handles vectors. also angle vectors and the such are +// less then 1, so you need floats. All functions that i have that work with vectors +// use the float[3], this makes it easier. +static cell AMX_NATIVE_CALL Entvars_Get_Vector(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + + cell *vReturnTo = GET_AMXADDR(amx,params[3]); + + Vector vRetValue = Vector(0, 0, 0); + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEntity = INDEXENT(iTargetEntity); + + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case origin: + vRetValue = pEntity->v.origin; + break; + case oldorigin: + vRetValue = pEntity->v.oldorigin; + break; + case velocity: + vRetValue = pEntity->v.velocity; + break; + case basevelocity: + vRetValue = pEntity->v.basevelocity; + break; + case clbasevelocity: + vRetValue = pEntity->v.clbasevelocity; + break; + case movedir: + vRetValue = pEntity->v.movedir; + break; + case angles: + vRetValue = pEntity->v.angles; + break; + case avelocity: + vRetValue = pEntity->v.avelocity; + break; + case punchangle: + vRetValue = pEntity->v.punchangle; + break; + case v_angle: + vRetValue = pEntity->v.v_angle; + break; + case endpos: + vRetValue = pEntity->v.endpos; + break; + case startpos: + vRetValue = pEntity->v.startpos; + break; + case absmin: + vRetValue = pEntity->v.absmin; + break; + case absmax: + vRetValue = pEntity->v.absmax; + break; + case mins: + vRetValue = pEntity->v.mins; + break; + case maxs: + vRetValue = pEntity->v.maxs; + break; + case size: + vRetValue = pEntity->v.size; + break; + case rendercolor: + vRetValue = pEntity->v.rendercolor; + break; + case view_ofs: + vRetValue = pEntity->v.view_ofs; + break; + case vuser1: + vRetValue = pEntity->v.vuser1; + break; + case vuser2: + vRetValue = pEntity->v.vuser2; + break; + case vuser3: + vRetValue = pEntity->v.vuser3; + break; + case vuser4: + vRetValue = pEntity->v.vuser4; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + + vReturnTo[0] = *(cell*)((void *)&vRetValue.x); + vReturnTo[1] = *(cell*)((void *)&vRetValue.y); + vReturnTo[2] = *(cell*)((void *)&vRetValue.z); + + return 1; +} + +// Set is close to get, these functions are pretty self-explanitory. +static cell AMX_NATIVE_CALL Entvars_Set_Vector(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + cell *vInput = GET_AMXADDR(amx,params[3]); + + float fNewX = *(float *)((void *)&vInput[0]); + float fNewY = *(float *)((void *)&vInput[1]); + float fNewZ = *(float *)((void *)&vInput[2]); + + Vector vNewValue = Vector(fNewX, fNewY, fNewZ); + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEntity = INDEXENT(iTargetEntity); + + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case origin: + pEntity->v.origin = vNewValue; + break; + case oldorigin: + pEntity->v.oldorigin = vNewValue; + break; + case velocity: + pEntity->v.velocity = vNewValue; + break; + case basevelocity: + pEntity->v.basevelocity = vNewValue; + break; + case clbasevelocity: + pEntity->v.clbasevelocity = vNewValue; + break; + case movedir: + pEntity->v.movedir = vNewValue; + break; + case angles: + pEntity->v.angles = vNewValue; + break; + case avelocity: + pEntity->v.avelocity = vNewValue; + break; + case punchangle: + pEntity->v.punchangle = vNewValue; + break; + case v_angle: + pEntity->v.v_angle = vNewValue; + break; + case endpos: + pEntity->v.endpos = vNewValue; + break; + case startpos: + pEntity->v.startpos = vNewValue; + break; + case absmin: + pEntity->v.absmin = vNewValue; + break; + case absmax: + pEntity->v.absmax = vNewValue; + break; + case mins: + pEntity->v.mins = vNewValue; + break; + case maxs: + pEntity->v.maxs = vNewValue; + break; + case size: + pEntity->v.size = vNewValue; + break; + case rendercolor: + pEntity->v.rendercolor = vNewValue; + break; + case view_ofs: + pEntity->v.view_ofs = vNewValue; + break; + case vuser1: + pEntity->v.vuser1 = vNewValue; + break; + case vuser2: + pEntity->v.vuser2 = vNewValue; + break; + case vuser3: + pEntity->v.vuser3 = vNewValue; + break; + case vuser4: + pEntity->v.vuser4 = vNewValue; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return 1; +} + +// Get an edict pointer (or index, amx does not have pointers) from entvars. +static cell AMX_NATIVE_CALL Entvars_Get_Edict(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + + // Return edict structure. + edict_t *pRetValue; + + // Valid entity? + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + // get edict pointer of target entity + edict_t* pEntity = INDEXENT(iTargetEntity); + + // is it valid? + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case chain: + pRetValue = pEntity->v.chain; + break; + case dmg_inflictor: + pRetValue = pEntity->v.dmg_inflictor; + break; + case enemy: + pRetValue = pEntity->v.enemy; + break; + case aiment: + pRetValue = pEntity->v.aiment; + break; + case owner: + pRetValue = pEntity->v.owner; + break; + case groundentity: + pRetValue = pEntity->v.groundentity; + break; + case pContainingEntity: + pRetValue = pEntity->v.pContainingEntity; + break; + case euser1: + pRetValue = pEntity->v.euser1; + break; + case euser2: + pRetValue = pEntity->v.euser2; + break; + case euser3: + pRetValue = pEntity->v.euser3; + break; + case euser4: + pRetValue = pEntity->v.euser4; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + if(!FNullEnt(pRetValue)) { + return ENTINDEX(pRetValue); + } else { + return 0; + } +} + +// Set edict is almost the same as get, look there for comments. +static cell AMX_NATIVE_CALL Entvars_Set_Edict(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + edict_t *pNewValue = INDEXENT(params[3]); + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEntity = INDEXENT(iTargetEntity); + + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + if(FNullEnt(pNewValue)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case chain: + pEntity->v.chain = pNewValue; + break; + case dmg_inflictor: + pEntity->v.dmg_inflictor = pNewValue; + break; + case enemy: + pEntity->v.enemy = pNewValue; + break; + case aiment: + pEntity->v.aiment = pNewValue; + break; + case owner: + pEntity->v.owner = pNewValue; + break; + case groundentity: + pEntity->v.groundentity = pNewValue; + break; + case pContainingEntity: + pEntity->v.pContainingEntity = pNewValue; + break; + case euser1: + pEntity->v.euser1 = pNewValue; + break; + case euser2: + pEntity->v.euser2 = pNewValue; + break; + case euser3: + pEntity->v.euser3 = pNewValue; + break; + case euser4: + pEntity->v.euser4 = pNewValue; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return 1; +} + +// Strings. I remember now that weaponmodel and viewmodel are strings as well, +// even though half-life declares them as integers. (a half-life string is just a +// typedefed integer.). +static cell AMX_NATIVE_CALL Entvars_Get_String(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + int iszRetValue = 0; + + // Valid entity? + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + // Get pointer of entity. + edict_t* pEntity = INDEXENT(iTargetEntity); + + // Is entity valid again? + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case classname: + iszRetValue = pEntity->v.classname; + break; + case globalname: + iszRetValue = pEntity->v.globalname; + break; + case model: + iszRetValue = pEntity->v.model; + break; + case target: + iszRetValue = pEntity->v.target; + break; + case targetname: + iszRetValue = pEntity->v.targetname; + break; + case netname: + iszRetValue = pEntity->v.netname; + break; + case message: + iszRetValue = pEntity->v.message; + break; + case noise: + iszRetValue = pEntity->v.noise; + break; + case noise1: + iszRetValue = pEntity->v.noise1; + break; + case noise2: + iszRetValue = pEntity->v.noise2; + break; + case noise3: + iszRetValue = pEntity->v.noise3; + break; + case viewmodel: + iszRetValue = pEntity->v.viewmodel; + break; + case weaponmodel: + iszRetValue = pEntity->v.weaponmodel; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return SET_AMXSTRING(amx, params[3], STRING(iszRetValue), params[4]); +} + +// Almost the same as Get_String, look there for comments. +static cell AMX_NATIVE_CALL Entvars_Set_String(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + int iLength; + int iszNewValue = AMX_MAKE_STRING(amx, params[3], iLength); + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEntity = INDEXENT(iTargetEntity); + + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case classname: + pEntity->v.classname = iszNewValue; + break; + case globalname: + pEntity->v.globalname = iszNewValue; + break; + case model: + pEntity->v.model = iszNewValue; + break; + case target: + pEntity->v.target = iszNewValue; + break; + case targetname: + pEntity->v.targetname = iszNewValue; + break; + case netname: + pEntity->v.netname = iszNewValue; + break; + case message: + pEntity->v.message = iszNewValue; + break; + case noise: + pEntity->v.noise = iszNewValue; + break; + case noise1: + pEntity->v.noise1 = iszNewValue; + break; + case noise2: + pEntity->v.noise2 = iszNewValue; + break; + case noise3: + pEntity->v.noise3 = iszNewValue; + break; + case viewmodel: + pEntity->v.viewmodel = iszNewValue; + break; + case weaponmodel: + pEntity->v.weaponmodel = iszNewValue; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return 1; +} + +// Bytes, these were used for some things, mostly useless, but might be useful. +// They are arrays, but we just use numbers in naming of the enum variables to +// let us pass get different positions in the array. +static cell AMX_NATIVE_CALL Entvars_Get_Byte(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + int iRetValue = 0; + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEntity = INDEXENT(iTargetEntity); + + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + switch(iValueSet) { + case controller1: + iRetValue = pEntity->v.controller[1]; + break; + case controller2: + iRetValue = pEntity->v.controller[2]; + break; + case controller3: + iRetValue = pEntity->v.controller[3]; + break; + case controller4: + iRetValue = pEntity->v.controller[4]; + break; + case blending1: + iRetValue = pEntity->v.blending[1]; + break; + case blending2: + iRetValue = pEntity->v.blending[2]; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return iRetValue; +} + +// Like Get_Byte, but sets. +static cell AMX_NATIVE_CALL Entvars_Set_Byte(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iValueSet = params[2]; + int iNewValue = params[3]; + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEntity = INDEXENT(iTargetEntity); + + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + if(iNewValue > 255) iNewValue = 255; + if(iNewValue < 0) iNewValue = 0; + + switch(iValueSet) { + case controller1: + pEntity->v.controller[1] = iNewValue; + break; + case controller2: + pEntity->v.controller[2] = iNewValue; + break; + case controller3: + pEntity->v.controller[3] = iNewValue; + break; + case controller4: + pEntity->v.controller[4] = iNewValue; + break; + case blending1: + pEntity->v.blending[1] = iNewValue; + break; + case blending2: + pEntity->v.blending[2] = iNewValue; + break; + default: + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + break; + } + + return 1; +} + +// VelocityByAim, this function will take the aimvectors of an entity, and create a velocity +// of iVelocity in the direction of the aimvec. +static cell AMX_NATIVE_CALL VelocityByAim(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + int iVelocity = params[2]; + cell *vReturnTo = GET_AMXADDR(amx,params[3]); + + Vector vRetValue = Vector(0, 0, 0); + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEntity = INDEXENT(iTargetEntity); + + if(FNullEnt(pEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + MAKE_VECTORS(pEntity->v.v_angle); + vRetValue = gpGlobals->v_forward * iVelocity; + + vReturnTo[0] = *(cell*)((void *)&vRetValue.x); + vReturnTo[1] = *(cell*)((void *)&vRetValue.y); + vReturnTo[2] = *(cell*)((void *)&vRetValue.z); + + return 1; +} + +// RadiusDamage. Damages players within a certain radius. ToDo: add the +// damage messaging so players know where the damage is coming from +// (the red arrow-like things on the screen). +static cell AMX_NATIVE_CALL RadiusDamage(AMX *amx, cell *params) { + cell *vInput = GET_AMXADDR(amx,params[1]); + + float fCurrentX = *(float *)((void *)&vInput[0]); + float fCurrentY = *(float *)((void *)&vInput[1]); + float fCurrentZ = *(float *)((void *)&vInput[2]); + int iDamageMultiplier = params[2]; + int iRadiusMultiplier = params[3]; + + Vector vOrigin = Vector(fCurrentX, fCurrentY, fCurrentZ); + + edict_t *pSearchEnt = NULL; + while((pSearchEnt = UTIL_FindEntityInSphere(pSearchEnt, vOrigin, 5 * iRadiusMultiplier)) != NULL) { + if(FStrEq(STRING(pSearchEnt->v.classname), "player")) { + if(pSearchEnt->v.takedamage != DAMAGE_NO) { + pSearchEnt->v.health -= 10 + RANDOM_FLOAT(0,1 * iDamageMultiplier); + if(pSearchEnt->v.health < 1) { + pSearchEnt->v.health = 1; + MDLL_ClientKill(pSearchEnt); + } + } + } + } + + pSearchEnt = NULL; + + while((pSearchEnt = UTIL_FindEntityInSphere(pSearchEnt, vOrigin, 4 * iRadiusMultiplier)) != NULL) { + if(FStrEq(STRING(pSearchEnt->v.classname), "player")) { + if(pSearchEnt->v.takedamage != DAMAGE_NO) { + pSearchEnt->v.health -= 25 + RANDOM_FLOAT(0,2 * iDamageMultiplier); + if(pSearchEnt->v.health < 1) { + pSearchEnt->v.health = 1; + MDLL_ClientKill(pSearchEnt); + } + } + } + } + + pSearchEnt = NULL; + + while((pSearchEnt = UTIL_FindEntityInSphere(pSearchEnt, vOrigin, 3 * iRadiusMultiplier)) != NULL) { + if(FStrEq(STRING(pSearchEnt->v.classname), "player")) { + if(pSearchEnt->v.takedamage != DAMAGE_NO) { + pSearchEnt->v.health -= 50 + RANDOM_FLOAT(0,3 * iDamageMultiplier); + if(pSearchEnt->v.health < 1) { + pSearchEnt->v.health = 1; + MDLL_ClientKill(pSearchEnt); + } + } + } + } + + pSearchEnt = NULL; + + while((pSearchEnt = UTIL_FindEntityInSphere(pSearchEnt, vOrigin, 2 * iRadiusMultiplier)) != NULL) { + if(FStrEq(STRING(pSearchEnt->v.classname), "player")) { + if(pSearchEnt->v.takedamage != DAMAGE_NO) MDLL_ClientKill(pSearchEnt); + } + } + + return 1; +} + +// Gets the contents of a point. Return values for this are probably in const.h. +static cell AMX_NATIVE_CALL PointContents(AMX *amx, cell *params) { + cell *vInput = GET_AMXADDR(amx,params[1]); + + float fCurrentX = *(float *)((void *)&vInput[0]); + float fCurrentY = *(float *)((void *)&vInput[1]); + float fCurrentZ = *(float *)((void *)&vInput[2]); + + Vector vTestValue = Vector(fCurrentX, fCurrentY, fCurrentZ); + + return POINT_CONTENTS(vTestValue); +} + +// CreateEntity. Makes an entity. +static cell AMX_NATIVE_CALL CreateEntity(AMX *amx, cell *params) { + int iLength; + int iszNewClassName = AMX_MAKE_STRING(amx, params[1], iLength); + + edict_t* pNewEntity = CREATE_NAMED_ENTITY(iszNewClassName); + + if(FNullEnt(pNewEntity)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + return ENTINDEX(pNewEntity); +} + +// DispatchKeyValue, sets a key-value pair for a newly created entity. +// Use DispatchSpawn after doing ALL DispatchKeyValues on an entity. +static cell AMX_NATIVE_CALL DispatchKeyValue(AMX *amx, cell *params) { + edict_t* pTarget = INDEXENT(params[1]); + int iKeyLength; + int iValueLength; + char *szKey = AMX_GET_STRING(amx, params[2], iKeyLength); + char *szValue = AMX_GET_STRING(amx, params[3], iValueLength); + + + if(FNullEnt(pTarget)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + KeyValueData pkvd; + pkvd.szClassName = (char *)STRING(pTarget->v.classname); + pkvd.szKeyName = szKey; + pkvd.szValue = szValue; + pkvd.fHandled = false; + + MDLL_KeyValue(pTarget, &pkvd); + return 1; +} + +// DispatchSpawn. Call this after doing any DispatchKeyValues you are +// doing on an entity your creating. +static cell AMX_NATIVE_CALL DispatchSpawn(AMX *amx, cell *params) { + edict_t* pTarget = INDEXENT(params[1]); + + if(FNullEnt(pTarget)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + MDLL_Spawn(pTarget); + + return 1; +} + +// Sets a model on an entity. Dont set models in entvars, it wont +// update the engine of the model change. +static cell AMX_NATIVE_CALL ENT_SetModel(AMX *amx, cell *params) { + edict_t* pTarget = INDEXENT(params[1]); + + int iLength; + char *szNewValue = AMX_GET_STRING(amx, params[2], iLength); + + if(FNullEnt(pTarget)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + SET_MODEL(pTarget, szNewValue); + + return 1; +} + +// Set origin for entities. Use this instead of entvars, as it updates the engine. +// It also does a SetSize, this way we can set the size at the same time as origin. +static cell AMX_NATIVE_CALL ENT_SetOrigin(AMX *amx, cell *params) { + int iTargetEntity = params[1]; + cell *vInput = GET_AMXADDR(amx,params[2]); + + float fNewX = *(float *)((void *)&vInput[0]); + float fNewY = *(float *)((void *)&vInput[1]); + float fNewZ = *(float *)((void *)&vInput[2]); + + Vector vNewValue = Vector(fNewX, fNewY, fNewZ); + + if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pTarget = INDEXENT(iTargetEntity); + + if(FNullEnt(pTarget)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + SET_SIZE(pTarget, pTarget->v.mins, pTarget->v.maxs); + SET_ORIGIN(pTarget, vNewValue); + + return 1; +} + +// FindEntity, use this in a while loop. will return -1 when theres no entities left. +// It searches by classname. +static cell AMX_NATIVE_CALL FindEntity(AMX *amx, cell *params) { + int iStartEnt = params[1]; + + int iLengthSearchStrn; + char *szValue = AMX_GET_STRING(amx, params[2], iLengthSearchStrn); + + edict_t *pStartEnt; + + if(iStartEnt == -1) { + pStartEnt = NULL; + } else { + pStartEnt = INDEXENT(iStartEnt); + + if(FNullEnt(pStartEnt)) { + return -1; + } + } + + int iReturnEnt = ENTINDEX(FIND_ENTITY_BY_STRING(pStartEnt, "classname", szValue)); + + if(!iReturnEnt || FNullEnt(iReturnEnt)) { + return -1; + } + + return iReturnEnt; +} + +//FindEntityByTarget (BAILOPAN) +// Works like FindEntity except finds by Target +static cell AMX_NATIVE_CALL FindEntityByTarget(AMX *amx, cell *params) +{ + int iStart = params[1]; + int iLength; + char *szValue = AMX_GET_STRING(amx, params[2], iLength); + + edict_t *pStart; + + if (iStart == -1) { + pStart = NULL; + } else { + pStart = INDEXENT(iStart); + if (FNullEnt(pStart)) { + return -1; + } + } + + int iReturnEnt = ENTINDEX(FIND_ENTITY_BY_TARGET(pStart, szValue)); + + if (!iReturnEnt || FNullEnt(iReturnEnt)) { + return -1; + } + + return iReturnEnt; +} + +//FindEntityByModel (BAILOPAN) +//Takes in a classname and model... +static cell AMX_NATIVE_CALL FindEntityByModel(AMX *amx, cell *params) { + int iStart = params[1]; + int iLength, iLength2; + char *szClass = AMX_GET_STRING(amx, params[2], iLength); + char *szModel = AMX_GET_STRING(amx, params[3], iLength2); + int iModel = MAKE_STRING(szModel); + + edict_t *pStart; + + if (iStart == -1) { + pStart = NULL; + } else { + pStart = INDEXENT(iStart); + if (FNullEnt(pStart)) { + return -1; + } + } + + int checkEnt = ENTINDEX(FIND_ENTITY_BY_STRING(pStart, "classname", szClass)); + int iCheckModel = 0; + + while ((checkEnt && FNullEnt(checkEnt))) { + iCheckModel = pStart->v.model; + if (iCheckModel == iModel) { + return checkEnt; + } else { + pStart = INDEXENT(checkEnt); + checkEnt = ENTINDEX(FIND_ENTITY_BY_STRING(pStart, "classname", szClass)); + } + } + + if(!checkEnt || FNullEnt(checkEnt)) { + return -1; + } + + return checkEnt; +} + +//FindEntityByTName (BAILOPAN) +// Works like FindEntity except finds by TargetName +static cell AMX_NATIVE_CALL FindEntityByTName(AMX *amx, cell *params) { + int iStart = params[1]; + int iLength; + char *szValue = AMX_GET_STRING(amx, params[2], iLength); + + edict_t *pStart; + + if (iStart == -1) { + pStart = NULL; + } else { + pStart = INDEXENT(iStart); + if (FNullEnt(pStart)) { + return -1; + } + } + + int iReturnEnt = ENTINDEX(FIND_ENTITY_BY_TARGETNAME(pStart, szValue)); + + if (!iReturnEnt || FNullEnt(iReturnEnt)) { + return -1; + } + + return iReturnEnt; +} + +// FindEntityByOwner (BAILOPAN) +// Works like FindEntity except only returns by owner. +// Searches by classname. +static cell AMX_NATIVE_CALL FindEntityByOwner(AMX *amx, cell *params) { + int iStartEnt = params[1]; + int iEntOwner = params[3]; + int iLengthSearchStrn; + char *szValue = AMX_GET_STRING(amx, params[2], iLengthSearchStrn); + + edict_t *pStartEnt; + + if(iStartEnt == -1) { + pStartEnt = NULL; + } else { + pStartEnt = INDEXENT(iStartEnt); + + if(FNullEnt(pStartEnt)) { + return -1; + } + } + + int checkEnt = ENTINDEX(FIND_ENTITY_BY_STRING(pStartEnt, "classname", szValue)); + int iOwner = -1; + + while ((checkEnt && FNullEnt(checkEnt)) && (iOwner!=-1)) { + iOwner = ENTINDEX(pStartEnt->v.owner); + if (iOwner == iEntOwner) { + return checkEnt; + } else { + pStartEnt = INDEXENT(checkEnt); + checkEnt = ENTINDEX(FIND_ENTITY_BY_STRING(pStartEnt, "classname", szValue)); + } + } + + if(!checkEnt || FNullEnt(checkEnt) || (iOwner == -1)) { + return -1; + } + + return checkEnt; +} + +//returns current number of entities in game (BAILOPAN) +static cell AMX_NATIVE_CALL EntityCount(AMX *amx, cell *params) +{ + return NUMBER_OF_ENTITIES(); +} + +// BAILOPAN +static cell AMX_NATIVE_CALL set_user_footsteps(AMX *amx, cell *params) +{ + int index = params[1]; + int steps = params[2]; + + if (index<1||index>gpGlobals->maxClients) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEdict = INDEXENT(index); + + if (steps>0) { + pEdict->v.flTimeStepSound = steps; + } else if (steps == 0) { + pEdict->v.flTimeStepSound = 400; + } else if (steps < 0) { + pEdict->v.flTimeStepSound = 999; + } + + return 1; +} + +// BAILOPAN +static cell AMX_NATIVE_CALL get_user_footsteps(AMX *amx, cell *params) +{ + int index = params[1]; + + if (index<1||index>gpGlobals->maxClients) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEdict = INDEXENT(index); + + return pEdict->v.flTimeStepSound; +} + +// SpaceDude +static cell AMX_NATIVE_CALL get_grenade_id(AMX *amx, cell *params) /* 4 param */ +{ + int index = params[1]; + char* szModel; + + if (index<1||index>gpGlobals->maxClients) + { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pentFind = INDEXENT(params[4]); + edict_t* pentOwner = INDEXENT(index); + + pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "grenade" ); + while ( !FNullEnt( pentFind ) ) + { + if (pentFind->v.owner == pentOwner) + { + szModel = new char[params[3]]; + szModel = (char*)STRING(pentFind->v.model); + SET_AMXSTRING(amx,params[2],szModel,params[3]); + delete [] szModel; + return ENTINDEX(pentFind); + } + pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "grenade" ); + } + return 0; +} + +// SpaceDude +static cell AMX_NATIVE_CALL get_user_velocity(AMX *amx, cell *params) /* 2 param */ +{ + int index = params[1]; + cell *Velocity = GET_AMXADDR(amx,params[2]); + + if (index<1||index>gpGlobals->maxClients) + { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEdict = INDEXENT(index); + + Velocity[0] = (cell)pEdict->v.velocity.x; + Velocity[1] = (cell)pEdict->v.velocity.y; + Velocity[2] = (cell)pEdict->v.velocity.z; + + return 1; +} + +// SpaceDude +static cell AMX_NATIVE_CALL set_user_velocity(AMX *amx, cell *params) /* 2 param */ +{ + int index = params[1]; + cell *Velocity = GET_AMXADDR(amx,params[2]); + + if (index<1||index>gpGlobals->maxClients) + { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t* pEdict = INDEXENT(index); + + pEdict->v.velocity.x = Velocity[0]; + pEdict->v.velocity.y = Velocity[1]; + pEdict->v.velocity.z = Velocity[2]; + + return 1; +} + +// TraceLn, Traces a Line in space. This is useful for making beams, or checking if +// An entity is at the end of a line. +// The return value is either the end of the line (where it crashed into an object, +// or the end you supplied.) +static cell AMX_NATIVE_CALL TraceLn(AMX *amx, cell *params) { + int iIgnoreEnt = params[1]; + + cell *fpStart = GET_AMXADDR(amx,params[2]); + float fStartX = *(float *)((void *)&fpStart[0]); + float fStartY = *(float *)((void *)&fpStart[1]); + float fStartZ = *(float *)((void *)&fpStart[2]); + + cell *fpEnd = GET_AMXADDR(amx,params[3]); + float fEndX = *(float *)((void *)&fpEnd[0]); + float fEndY = *(float *)((void *)&fpEnd[1]); + float fEndZ = *(float *)((void *)&fpEnd[2]); + + + cell *vReturnTo = GET_AMXADDR(amx,params[4]); + + Vector vStart = Vector(fStartX, fStartY, fStartZ); + Vector vEnd = Vector(fEndX, fEndY, fEndZ); + + TraceResult tr; + + if(iIgnoreEnt == -1) { + TRACE_LINE(vStart, vEnd, ignore_monsters, NULL, &tr); + } else { + TRACE_LINE(vStart, vEnd, dont_ignore_monsters, INDEXENT(iIgnoreEnt), &tr); + } + + edict_t *pHit = tr.pHit; + + vReturnTo[0] = *(cell*)((void *)&tr.vecEndPos.x); + vReturnTo[1] = *(cell*)((void *)&tr.vecEndPos.y); + vReturnTo[2] = *(cell*)((void *)&tr.vecEndPos.z); + + if(FNullEnt(pHit)) { + return -1; + } + + return ENTINDEX(pHit); +} + +// TraceNormal. This is just like TraceLine, but it gives back the +// Normal of whatever plane it hit. Use with TraceLine and you can have +// A point on a plane, with its normal, good for creating things that attach +// to walls (like tripmines). +static cell AMX_NATIVE_CALL TraceNormal(AMX *amx, cell *params) { + int iIgnoreEnt = params[1]; + + cell *fpStart = GET_AMXADDR(amx,params[2]); + float fStartX = *(float *)((void *)&fpStart[0]); + float fStartY = *(float *)((void *)&fpStart[1]); + float fStartZ = *(float *)((void *)&fpStart[2]); + + cell *fpEnd = GET_AMXADDR(amx,params[3]); + float fEndX = *(float *)((void *)&fpEnd[0]); + float fEndY = *(float *)((void *)&fpEnd[1]); + float fEndZ = *(float *)((void *)&fpEnd[2]); + + + cell *vReturnTo = GET_AMXADDR(amx,params[4]); + + Vector vStart = Vector(fStartX, fStartY, fStartZ); + Vector vEnd = Vector(fEndX, fEndY, fEndZ); + + TraceResult tr; + TRACE_LINE(vStart, vEnd, dont_ignore_monsters, INDEXENT(iIgnoreEnt), &tr); + + vReturnTo[0] = *(cell*)((void *)&tr.vecPlaneNormal.x); + vReturnTo[1] = *(cell*)((void *)&tr.vecPlaneNormal.y); + vReturnTo[2] = *(cell*)((void *)&tr.vecPlaneNormal.z); + + if (tr.flFraction >= 1.0) return 0; + + return 1; +} + +// VecToAngles, this is a half-life function for making a vector out of +// angles. +static cell AMX_NATIVE_CALL VecToAngles(AMX *amx, cell *params) { + cell *vInput = GET_AMXADDR(amx,params[1]); + float fInX = *(float *)((void *)&vInput[0]); + float fInY = *(float *)((void *)&vInput[1]); + float fInZ = *(float *)((void *)&vInput[2]); + + Vector vVector = Vector(fInX, fInY, fInZ); + Vector vAngle = Vector(0, 0, 0); + VEC_TO_ANGLES(vVector, vAngle); + + cell *vReturnTo = GET_AMXADDR(amx,params[2]); + vReturnTo[0] = *(cell*)((void *)&vAngle.x); + vReturnTo[1] = *(cell*)((void *)&vAngle.y); + vReturnTo[2] = *(cell*)((void *)&vAngle.z); + + return 1; +} + +// VecLength, this gives you the length of a vector (float[3] type). +static cell AMX_NATIVE_CALL VecLength(AMX *amx, cell *params) { + cell *vInput = GET_AMXADDR(amx,params[1]); + float fInX = *(float *)((void *)&vInput[0]); + float fInY = *(float *)((void *)&vInput[1]); + float fInZ = *(float *)((void *)&vInput[2]); + + Vector vVector = Vector(fInX, fInY, fInZ); + + float flLength = vVector.Length(); + + return *(cell*)((void *)&flLength); +} + +// VecDist, this gives you the distance between 2 vectors (float[3] type). +static cell AMX_NATIVE_CALL VecDist(AMX *amx, cell *params) { + cell *vInput = GET_AMXADDR(amx,params[1]); + float fInX = *(float *)((void *)&vInput[0]); + float fInY = *(float *)((void *)&vInput[1]); + float fInZ = *(float *)((void *)&vInput[2]); + + cell *vInput2 = GET_AMXADDR(amx,params[2]); + float fInX2 = *(float *)((void *)&vInput2[0]); + float fInY2 = *(float *)((void *)&vInput2[1]); + float fInZ2 = *(float *)((void *)&vInput2[2]); + + Vector vVector = Vector(fInX, fInY, fInZ); + Vector vVector2 = Vector(fInX2, fInY2, fInZ2); + + float flLength = (vVector - vVector2).Length(); + + return *(cell*)((void *)&flLength); +} + +// RemoveEntity, this removes an entity from the world. +// Could also be done setting the flag FL_KILLME in entvars. +static cell AMX_NATIVE_CALL RemoveEntity(AMX *amx, cell *params) { + int iTarget = params[1]; + + edict_t* pTarget = INDEXENT(iTarget); + + if(FNullEnt(pTarget)) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + REMOVE_ENTITY(pTarget); + + return 1; +} + +// SetView, this sets the view of a player. This is done by +// Creating a camera entity, which follows the player. +static cell AMX_NATIVE_CALL SetView(AMX *amx, cell *params) { + int iIndex = params[1]; + int iCameraType = params[2]; + + if (iIndex < 1 || iIndex > gpGlobals->maxClients) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + edict_t *pPlayer = INDEXENT(iIndex); + edict_t *pNewCamera; + + switch(iCameraType) { + case CAMERA_NONE: + SET_VIEW(pPlayer, pPlayer); + if(PlInfo[ENTINDEX(pPlayer)].pViewEnt) { + REMOVE_ENTITY(PlInfo[ENTINDEX(pPlayer)].pViewEnt); + } + PlInfo[ENTINDEX(pPlayer)].iViewType = CAMERA_NONE; + PlInfo[ENTINDEX(pPlayer)].pViewEnt = NULL; + + pPlayer->v.rendermode = PlInfo[ENTINDEX(pPlayer)].iRenderMode; + pPlayer->v.renderamt = PlInfo[ENTINDEX(pPlayer)].fRenderAmt; + + PlInfo[ENTINDEX(pPlayer)].iRenderMode = 0; + PlInfo[ENTINDEX(pPlayer)].fRenderAmt = 0; + + return 1; + break; + case CAMERA_3RDPERSON: + if(PlInfo[ENTINDEX(pPlayer)].iViewType != CAMERA_NONE) { + PlInfo[ENTINDEX(pPlayer)].iViewType = CAMERA_3RDPERSON; + return 1; + } + + PlInfo[ENTINDEX(pPlayer)].iRenderMode = pPlayer->v.rendermode; + PlInfo[ENTINDEX(pPlayer)].fRenderAmt = pPlayer->v.renderamt; + + PlInfo[ENTINDEX(pPlayer)].iViewType = CAMERA_3RDPERSON; + pNewCamera = CREATE_NAMED_ENTITY(MAKE_STRING("info_target")); + pNewCamera->v.classname = MAKE_STRING("VexdCam"); + + SET_MODEL(pNewCamera, "models/rpgrocket.mdl"); + SET_SIZE(pNewCamera, Vector(0, 0, 0), Vector(0, 0, 0)); + + pNewCamera->v.movetype = MOVETYPE_FLY; + pNewCamera->v.solid = SOLID_BBOX; + pNewCamera->v.takedamage = DAMAGE_NO; + pNewCamera->v.gravity = 0; + pNewCamera->v.owner = pPlayer; + pNewCamera->v.rendermode = kRenderTransColor; + pNewCamera->v.renderamt = 0; + pNewCamera->v.renderfx = kRenderFxNone; + + SET_VIEW(pPlayer, pNewCamera); + + PlInfo[ENTINDEX(pPlayer)].pViewEnt = pNewCamera; + break; + case CAMERA_UPLEFT: + if(PlInfo[ENTINDEX(pPlayer)].iViewType != CAMERA_NONE) { + PlInfo[ENTINDEX(pPlayer)].iViewType = CAMERA_UPLEFT; + return 1; + } + + PlInfo[ENTINDEX(pPlayer)].iRenderMode = pPlayer->v.rendermode; + PlInfo[ENTINDEX(pPlayer)].fRenderAmt = pPlayer->v.renderamt; + + PlInfo[ENTINDEX(pPlayer)].iViewType = CAMERA_3RDPERSON; + pNewCamera = CREATE_NAMED_ENTITY(MAKE_STRING("info_target")); + pNewCamera->v.classname = MAKE_STRING("VexdCam"); + + SET_MODEL(pNewCamera, "models/rpgrocket.mdl"); + SET_SIZE(pNewCamera, Vector(0, 0, 0), Vector(0, 0, 0)); + + pNewCamera->v.movetype = MOVETYPE_FLY; + pNewCamera->v.solid = SOLID_BBOX; + pNewCamera->v.takedamage = DAMAGE_NO; + pNewCamera->v.gravity = 0; + pNewCamera->v.owner = pPlayer; + pNewCamera->v.rendermode = kRenderTransColor; + pNewCamera->v.renderamt = 0; + pNewCamera->v.renderfx = kRenderFxNone; + + SET_VIEW(pPlayer, pNewCamera); + + PlInfo[ENTINDEX(pPlayer)].pViewEnt = pNewCamera; + break; + case CAMERA_TOPDOWN: + if(PlInfo[ENTINDEX(pPlayer)].iViewType != CAMERA_NONE) { + PlInfo[ENTINDEX(pPlayer)].iViewType = CAMERA_TOPDOWN; + return 1; + } + + PlInfo[ENTINDEX(pPlayer)].iRenderMode = pPlayer->v.rendermode; + PlInfo[ENTINDEX(pPlayer)].fRenderAmt = pPlayer->v.renderamt; + + PlInfo[ENTINDEX(pPlayer)].iViewType = CAMERA_TOPDOWN; + pNewCamera = CREATE_NAMED_ENTITY(MAKE_STRING("info_target")); + pNewCamera->v.classname = MAKE_STRING("VexdCam"); + + SET_MODEL(pNewCamera, "models/rpgrocket.mdl"); + SET_SIZE(pNewCamera, Vector(0, 0, 0), Vector(0, 0, 0)); + + pNewCamera->v.movetype = MOVETYPE_FLY; + pNewCamera->v.solid = SOLID_BBOX; + pNewCamera->v.takedamage = DAMAGE_NO; + pNewCamera->v.gravity = 0; + pNewCamera->v.owner = pPlayer; + pNewCamera->v.rendermode = kRenderTransColor; + pNewCamera->v.renderamt = 0; + pNewCamera->v.renderfx = kRenderFxNone; + + SET_VIEW(pPlayer, pNewCamera); + + PlInfo[ENTINDEX(pPlayer)].pViewEnt = pNewCamera; + break; + default: + break; + } + + return 1; +} + +// Attachview, this allows you to attach a player's view to an entity. +// use AttachView(player, player) to reset view. +static cell AMX_NATIVE_CALL AttachView(AMX *amx, cell *params) { + int iIndex = params[1]; + int iTargetIndex = params[2]; + + if (iIndex < 1 || iIndex > gpGlobals->maxClients) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + if(iTargetIndex < 1 || iTargetIndex > gpGlobals->maxEntities) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + SET_VIEW(INDEXENT(iIndex), INDEXENT(iTargetIndex)); + + return 1; +} + +// SetSpeak, this sets who a player can speak to/who he can listen to. +static cell AMX_NATIVE_CALL SetSpeak(AMX *amx, cell *params) { + int iIndex = params[1]; + int iNewSpeakFlags = params[2]; + + if (iIndex < 1 || iIndex > gpGlobals->maxClients) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + PlInfo[iIndex].iSpeakFlags = iNewSpeakFlags; + + return 1; +} + +//GetSpeak, this gets whether a player can speak to +// (BAILOPAN) +static cell AMX_NATIVE_CALL GetSpeak(AMX *amx, cell *params) { + int iIndex = params[1]; + + if (iIndex < 1 || iIndex > gpGlobals->maxClients) + { + AMX_RAISEERROR(amx, AMX_ERR_NATIVE); + return 0; + } + + return PlInfo[iIndex].iSpeakFlags; +} + +// SetLights, this sets the lights for the map. +static cell AMX_NATIVE_CALL SetLights(AMX *amx, cell *params) { + int iLength; + + char *szLights = AMX_GET_STRING(amx, params[1], iLength); + + if(FStrEq(szLights, "#OFF")) { + GlInfo.bLights = false; + memset(GlInfo.szLastLights, 0x0, 128); + (g_engfuncs.pfnLightStyle)(0, (char *)GlInfo.szRealLights); + return 1; + } + + GlInfo.bLights = true; + + //Reset LastLights + memset(GlInfo.szLastLights, 0x0, 128); + //Store the previous lighting. + memcpy(GlInfo.szLastLights, szLights, strlen(szLights)); + + (g_engfuncs.pfnLightStyle)(0, szLights); + + // These make it so that players/weaponmodels look like whatever the lighting is + // at. otherwise it would color players under the skybox to these values. + SERVER_COMMAND("sv_skycolor_r 0\n"); + SERVER_COMMAND("sv_skycolor_g 0\n"); + SERVER_COMMAND("sv_skycolor_b 0\n"); + + return 1; +} + +// Sets a message block. +static cell AMX_NATIVE_CALL MessageBlock(AMX *amx, cell *params) { + int iMessage = params[1]; + int iMessageFlags = params[2]; + + if (iMessage < 1 || iMessage > MAX_MESSAGES) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + GlInfo.iMessageBlock[iMessage] = iMessageFlags; + + return 1; +} + +// Gets a message block. +static cell AMX_NATIVE_CALL GetMessageBlock(AMX *amx, cell *params) { + int iMessage = params[1]; + + if (iMessage < 1 || iMessage > MAX_MESSAGES) { + AMX_RAISEERROR(amx,AMX_ERR_NATIVE); + return 0; + } + + return GlInfo.iMessageBlock[iMessage]; +} + +// Get gpGlobals->time, this is useful for timing things. +static cell AMX_NATIVE_CALL HLTime(AMX *amx, cell *params) { + float fRetValue = gpGlobals->time; + return *(cell*)((void *)&fRetValue); +} + +static cell AMX_NATIVE_CALL FakeTouch(AMX *amx, cell *params) { + int iToucher = params[1]; + int iTouched = params[2]; + + if(iToucher < 1 || iTouched < 1) return 0; + if(iToucher > gpGlobals->maxEntities || iTouched > gpGlobals->maxEntities) return 0; + + edict_t *pToucher = INDEXENT(iToucher); + edict_t *pTouched = INDEXENT(iTouched); + + if(FNullEnt(pToucher) || FNullEnt(pTouched)) return 0; + + MDLL_Touch(pToucher, pTouched); + + return 1; +} + +/*********************** End Exported Functions *****************************/ + +/*********************** Begin Hooked Functions *****************************/ + +// This is where we register any Console-variables we have. +void GameInit(void) { + CVAR_REGISTER(&vx_version); +} + +// Check if they are using a model, if so, don't let CS know. +// HACKHACK: this might mess up some stuff with other infobuffers, +// ie you may not see when a modeled player changes thier name, etc. +void ClientUserInfoChanged(edict_t *pEntity, char *infobuffer) { + if(PlInfo[ENTINDEX(pEntity)].bModeled && pEntity->v.deadflag == DEAD_NO) { + RETURN_META(MRES_SUPERCEDE); + } else { + RETURN_META(MRES_IGNORED); + } +} + +// This code is to set the model at a specified time. the second part of the code updates the +// SetView camera. +void PlayerPostThink(edict_t *pEntity) { + if((PlInfo[ENTINDEX(pEntity)].bModeled) && (PlInfo[ENTINDEX(pEntity)].fModelSet != 0) && (PlInfo[ENTINDEX(pEntity)].fModelSet < gpGlobals->time)) { + (g_engfuncs.pfnSetClientKeyValue)(ENTINDEX(pEntity), (g_engfuncs.pfnGetInfoKeyBuffer)(pEntity), "model", PlInfo[ENTINDEX(pEntity)].szModel); + } + + if(PlInfo[ENTINDEX(pEntity)].pViewEnt) { + edict_t *pCamEnt = PlInfo[ENTINDEX(pEntity)].pViewEnt; + + MAKE_VECTORS(pEntity->v.v_angle + pEntity->v.punchangle); + Vector vecSrc = pEntity->v.origin + pEntity->v.view_ofs; + Vector vecAiming = gpGlobals->v_forward; + TraceResult tr; + + switch(PlInfo[ENTINDEX(pEntity)].iViewType) { + case CAMERA_3RDPERSON: + TRACE_LINE(vecSrc, vecSrc - (vecAiming * 128), ignore_monsters, ENT(pEntity), &tr); + SET_VIEW(pEntity, pCamEnt); + pCamEnt->v.origin = tr.vecEndPos; + pCamEnt->v.angles = pEntity->v.v_angle; + break; + case CAMERA_UPLEFT: + TRACE_LINE(vecSrc, vecSrc - ((vecAiming * 32) - ((gpGlobals->v_right * 15) + (gpGlobals->v_up * 15))), ignore_monsters, ENT(pEntity), &tr); + SET_VIEW(pEntity, pCamEnt); + pCamEnt->v.origin = tr.vecEndPos; + pCamEnt->v.angles = pEntity->v.v_angle; + break; + case CAMERA_TOPDOWN: + TRACE_LINE(vecSrc, vecSrc + Vector(0,0,2048), dont_ignore_monsters, ENT(pEntity), &tr); + SET_VIEW(pEntity, pCamEnt); + pCamEnt->v.origin = tr.vecEndPos; + pCamEnt->v.origin.z -= 40; + pCamEnt->v.angles = Vector(90,pEntity->v.v_angle.y,0); + break; + default: + SET_VIEW(pEntity, pEntity); + REMOVE_ENTITY(PlInfo[ENTINDEX(pEntity)].pViewEnt); + PlInfo[ENTINDEX(pEntity)].iViewType = CAMERA_NONE; + PlInfo[ENTINDEX(pEntity)].pViewEnt = NULL; + break; + } + } + + RETURN_META(MRES_IGNORED); +} + +// This is called once every server frame. This code resets the lights once every second. +// this is so joining players will see ther correct lighting. +// Also forward, may cause lag, but it is good for checking things. +void StartFrame() { + if(!FStrEq((const char *)GlInfo.szLastLights, "")) { + if(GlInfo.fNextLights < gpGlobals->time) { + (g_engfuncs.pfnLightStyle)(0, (char *)GlInfo.szLastLights); + GlInfo.fNextLights = gpGlobals->time + 1; + } + } + + if(!vServerFrameCallList.empty()) { + for(std::vector::iterator i = vServerFrameCallList.begin(); i != vServerFrameCallList.end(); i++) { + cell iRetVal = 0; + AMX_EXEC(&i->pPlugin->amx, &iRetVal, i->iFunctionIdx, 0); + } + } + + RETURN_META(MRES_IGNORED); +} + +// pfnTouch, this is a forward that is called whenever 2 entities collide. +void Touch(edict_t *pToucher, edict_t *pTouched) { + for(std::vector::iterator i = vTouchCallList.begin(); i != vTouchCallList.end(); i++) { + cell iRetVal = 0; + AMX_EXEC(&i->pPlugin->amx, &iRetVal, i->iFunctionIdx, 2, ENTINDEX(pToucher), ENTINDEX(pTouched)); + } + + RETURN_META(MRES_IGNORED); +} + +// ClientDisconnect. Reinitialize the PlayerInfo struct for that player. +void ClientDisconnect(edict_t *pEntity) { + memset(PlInfo[ENTINDEX(pEntity)].szModel, 0x0, sizeof(PlInfo[ENTINDEX(pEntity)].szModel)); + PlInfo[ENTINDEX(pEntity)].bModeled = false; + PlInfo[ENTINDEX(pEntity)].fModelSet = 0; + PlInfo[ENTINDEX(pEntity)].iSpeakFlags = SPEAK_NORMAL; + PlInfo[ENTINDEX(pEntity)].iViewType = CAMERA_NONE; + PlInfo[ENTINDEX(pEntity)].iRenderMode = 0; + PlInfo[ENTINDEX(pEntity)].fRenderAmt = 0; + + RETURN_META(MRES_IGNORED); +} + +// ClientConnect, reinitialize player info here as well. +// Also gives small message that its using the model. +BOOL ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]) { + memset(PlInfo[ENTINDEX(pEntity)].szModel, 0x0, sizeof(PlInfo[ENTINDEX(pEntity)].szModel)); + PlInfo[ENTINDEX(pEntity)].bModeled = false; + PlInfo[ENTINDEX(pEntity)].fModelSet = 0; + PlInfo[ENTINDEX(pEntity)].iSpeakFlags = SPEAK_NORMAL; + PlInfo[ENTINDEX(pEntity)].iViewType = CAMERA_NONE; + PlInfo[ENTINDEX(pEntity)].pViewEnt = NULL; + PlInfo[ENTINDEX(pEntity)].iRenderMode = 0; + PlInfo[ENTINDEX(pEntity)].fRenderAmt = 0; + + CLIENT_PRINTF(pEntity, print_console, "*** This server is using Vexd's Utility Module.\n"); + + RETURN_META_VALUE(MRES_IGNORED, 0); +} + +// This allows us to make the player transparent when in third person (but visable to others). +int AddToFullPack(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet) { + if(ent == host) { + if(FStrEq(STRING(ent->v.classname), "player")) { + if(PlInfo[ENTINDEX(ent)].iViewType != CAMERA_NONE) { + ent->v.rendermode = kRenderTransTexture; + ent->v.renderamt = 100; + RETURN_META_VALUE(MRES_IGNORED, 0); + } + } + } + + if(FStrEq(STRING(ent->v.classname), "player")) { + if(PlInfo[ENTINDEX(ent)].iViewType != CAMERA_NONE) { + ent->v.rendermode = PlInfo[ENTINDEX(ent)].iRenderMode; + ent->v.renderamt = PlInfo[ENTINDEX(ent)].fRenderAmt; + } + } + + RETURN_META_VALUE(MRES_IGNORED, 0); +} + +// ServerActivate. This is called when the server starts a new map. +void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) { + plugin_t *pCurrent = FIND_PLUGIN_BY_INDEX(0, 0); + int iFunctionIndex = 0; + + // Search for plugins that have my forward functions. + while(pCurrent){ //Iterate Plugin List + if(AMX_FINDPUBLIC(&pCurrent->amx, "vexd_pfntouch", &iFunctionIndex) == AMX_ERR_NONE) { + AmxCall sNewCall; + sNewCall.pPlugin = pCurrent; + sNewCall.iFunctionIdx = iFunctionIndex; + vTouchCallList.push_back(sNewCall); + } + + iFunctionIndex = 0; + + if(AMX_FINDPUBLIC(&pCurrent->amx, "ServerFrame", &iFunctionIndex) == AMX_ERR_NONE) { + AmxCall sNewCall; + sNewCall.pPlugin = pCurrent; + sNewCall.iFunctionIdx = iFunctionIndex; + vServerFrameCallList.push_back(sNewCall); + } + + iFunctionIndex = 0; + pCurrent = pCurrent->next; + } + + RETURN_META(MRES_IGNORED); +} + +// Every call to ServerActivate is matched by ServerDeactivate. This is called when the server +// Is unloading the old map. +void ServerDeactivate(void) { + + // Clear the call list for forwards. this is important as the address of plugins can change + // from map-to-map. + vTouchCallList.clear(); + vServerFrameCallList.clear(); + + // Reset Lights. + memset(GlInfo.szLastLights, 0x0, 128); + memset(GlInfo.szRealLights, 0x0, 128); + GlInfo.bLights = false; + GlInfo.fNextLights = 0; + + // Reset message blocks. + for(int i = 0; i < MAX_MESSAGES; i++) { + GlInfo.iMessageBlock[i] = BLOCK_NOT; + } + + RETURN_META(MRES_IGNORED); +} + +// make sure that if we currently have an edited light value, to use it. +void LightStyle(int style, char *val) { + if(style == 0) { + memset(GlInfo.szRealLights, 0x0, 128); + memcpy(GlInfo.szRealLights, val, strlen(val)); + } + + RETURN_META(MRES_IGNORED); +} + +// This checks who can hear who through voice comm. this reads flags set, +// and lets us choose who hears who based on the previously set flags. +qboolean Voice_SetClientListening(int iReceiver, int iSender, qboolean bListen) { + if((PlInfo[iSender].iSpeakFlags & SPEAK_MUTED) != 0) { + (g_engfuncs.pfnVoice_SetClientListening)(iReceiver, iSender, false); + RETURN_META_VALUE(MRES_SUPERCEDE, false); + } + + if((PlInfo[iSender].iSpeakFlags & SPEAK_ALL) != 0) { + (g_engfuncs.pfnVoice_SetClientListening)(iReceiver, iSender, true); + RETURN_META_VALUE(MRES_SUPERCEDE, true); + } + + if((PlInfo[iReceiver].iSpeakFlags & SPEAK_LISTENALL) != 0) { + (g_engfuncs.pfnVoice_SetClientListening)(iReceiver, iSender, true); + RETURN_META_VALUE(MRES_SUPERCEDE, true); + } + + RETURN_META_VALUE(MRES_IGNORED, bListen); +} + +// Engine message functions. +void MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) { + + // Reset player model a couple milliseconds after this if they are using an edited model. + if(msg_type == REG_USER_MSG("ResetHUD", 1)) { + if(PlInfo[ENTINDEX(ed)].bModeled) { + PlInfo[ENTINDEX(ed)].fModelSet = gpGlobals->time + AMS_OFFSET; + } + } + + // If the message is a blocked one, block it. + if(GlInfo.iMessageBlock[msg_type]) { + GlInfo.bBlocking = true; + + if(GlInfo.iMessageBlock[msg_type] == BLOCK_ONCE) { + GlInfo.iMessageBlock[msg_type] = BLOCK_NOT; + } + + RETURN_META(MRES_SUPERCEDE); + } + + RETURN_META(MRES_IGNORED); +} + +void MessageEnd(void) { + if(GlInfo.bBlocking) { + GlInfo.bBlocking = false; + RETURN_META(MRES_SUPERCEDE); + } + RETURN_META(MRES_IGNORED); +} + +void WriteByte(int iValue) { + if(GlInfo.bBlocking) { + RETURN_META(MRES_SUPERCEDE); + } + RETURN_META(MRES_IGNORED); +} + +void WriteChar(int iValue) { + if(GlInfo.bBlocking) { + RETURN_META(MRES_SUPERCEDE); + } + RETURN_META(MRES_IGNORED); +} + +void WriteShort(int iValue) { + if(GlInfo.bBlocking) { + RETURN_META(MRES_SUPERCEDE); + } + RETURN_META(MRES_IGNORED); +} + +void WriteLong(int iValue) { + if(GlInfo.bBlocking) { + RETURN_META(MRES_SUPERCEDE); + } + RETURN_META(MRES_IGNORED); +} + +void WriteAngle(float flValue) { + if(GlInfo.bBlocking) { + RETURN_META(MRES_SUPERCEDE); + } + RETURN_META(MRES_IGNORED); +} + +void WriteCoord(float flValue) { + if(GlInfo.bBlocking) { + RETURN_META(MRES_SUPERCEDE); + } + RETURN_META(MRES_IGNORED); +} + +void WriteString(const char *sz) { + if(GlInfo.bBlocking) { + RETURN_META(MRES_SUPERCEDE); + } + RETURN_META(MRES_IGNORED); +} + +void WriteEntity(int iValue) { + if(GlInfo.bBlocking) { + RETURN_META(MRES_SUPERCEDE); + } + RETURN_META(MRES_IGNORED); +} + +/*********************** End Hooked Functions *****************************/ + +// Native list. +AMX_NATIVE_INFO Engine_Exports[] = { + {"AttachView", AttachView}, + {"SetView", SetView}, + {"SetSpeak", SetSpeak}, + {"GetSpeak", GetSpeak}, + {"SetLights", SetLights}, + {"Entvars_Get_Int", Entvars_Get_Int}, + {"Entvars_Set_Int", Entvars_Set_Int}, + {"Entvars_Get_Float", Entvars_Get_Float}, + {"Entvars_Set_Float", Entvars_Set_Float}, + {"Entvars_Get_Vector", Entvars_Get_Vector}, + {"Entvars_Set_Vector", Entvars_Set_Vector}, + {"Entvars_Get_Edict", Entvars_Get_Edict}, + {"Entvars_Set_Edict", Entvars_Set_Edict}, + {"Entvars_Get_String", Entvars_Get_String}, + {"Entvars_Set_String", Entvars_Set_String}, + {"Entvars_Get_Byte", Entvars_Get_Byte}, + {"Entvars_Set_Byte", Entvars_Set_Byte}, + + {"VelocityByAim", VelocityByAim}, + {"PointContents", PointContents}, + {"RadiusDamage", RadiusDamage}, + + {"CreateEntity", CreateEntity}, + {"DispatchKeyValue", DispatchKeyValue}, + {"DispatchSpawn", DispatchSpawn}, + {"ENT_SetModel", ENT_SetModel}, + {"ENT_SetOrigin", ENT_SetOrigin}, + {"FindEntity", FindEntity}, + {"FindEntityByOwner", FindEntityByOwner}, + {"FindEntityByModel", FindEntityByModel}, + {"FindEntityByTarget", FindEntityByTarget}, + {"FindEntityByTName", FindEntityByTName}, + {"RemoveEntity", RemoveEntity}, + {"EntityCount", EntityCount}, + + { "get_user_velocity", get_user_velocity }, + { "set_user_velocity", set_user_velocity }, + { "get_grenade_id", get_grenade_id }, + { "set_user_footsteps", set_user_footsteps }, + { "get_user_footsteps", set_user_footsteps }, + + {"TraceLn", TraceLn}, + {"TraceNormal", TraceNormal}, + {"VecToAngles", VecToAngles}, + {"VecLength", VecLength}, + {"VecDist", VecDist}, + + {"MessageBlock", MessageBlock}, + {"GetMessageBlock", GetMessageBlock}, + + {"HLTime", HLTime}, + {"FakeTouch", FakeTouch}, + + {NULL, NULL} +}; + +C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion) { + if(!pengfuncsFromEngine) return(FALSE); + else if(*interfaceVersion != ENGINE_INTERFACE_VERSION) { + *interfaceVersion = ENGINE_INTERFACE_VERSION; + return(FALSE); + } + + meta_engfuncs.pfnMessageBegin = MessageBegin; + meta_engfuncs.pfnMessageEnd = MessageEnd; + meta_engfuncs.pfnWriteByte = WriteByte; + meta_engfuncs.pfnWriteChar = WriteChar; + meta_engfuncs.pfnWriteShort = WriteShort; + meta_engfuncs.pfnWriteLong = WriteLong; + meta_engfuncs.pfnWriteAngle = WriteAngle; + meta_engfuncs.pfnWriteCoord = WriteCoord; + meta_engfuncs.pfnWriteString = WriteString; + meta_engfuncs.pfnWriteEntity = WriteEntity; + meta_engfuncs.pfnLightStyle = LightStyle; + meta_engfuncs.pfnVoice_SetClientListening = Voice_SetClientListening; + + memcpy(pengfuncsFromEngine, &meta_engfuncs, sizeof(enginefuncs_t)); + + return TRUE; +} + +C_DLLEXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) { + gFunctionTable.pfnGameInit = GameInit; + gFunctionTable.pfnTouch = Touch; + gFunctionTable.pfnStartFrame = StartFrame; + gFunctionTable.pfnClientConnect = ClientConnect; + gFunctionTable.pfnClientDisconnect = ClientDisconnect; + gFunctionTable.pfnPlayerPostThink = PlayerPostThink; + gFunctionTable.pfnClientUserInfoChanged = ClientUserInfoChanged; + gFunctionTable.pfnAddToFullPack = AddToFullPack; + gFunctionTable.pfnServerActivate = ServerActivate; + gFunctionTable.pfnServerDeactivate = ServerDeactivate; + + memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); + + return(TRUE); +} + +C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) { + *pPlugInfo=&Plugin_info; + gpMetaUtilFuncs=pMetaUtilFuncs; + + return(TRUE); +} + +C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) { + if(!pMGlobals) { + LOG_ERROR(PLID, "Meta_Attach called with null pMGlobals"); + return(FALSE); + } + gpMetaGlobals=pMGlobals; + if(!pFunctionTable) { + LOG_ERROR(PLID, "Meta_Attach called with null pFunctionTable"); + return(FALSE); + } + + gMetaFunctionTable.pfnGetEntityAPI2 = GetEntityAPI2; + gMetaFunctionTable.pfnGetEngineFunctions = GetEngineFunctions; + + memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS)); + gpGamedllFuncs=pGamedllFuncs; + + return(TRUE); +} + +C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { + if(now && reason) { + return(TRUE); + } else { + return(FALSE); + } +} + +void WINAPI GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) { + memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); + gpGlobals = pGlobals; +} + +C_DLLEXPORT int AMX_Attach(module_info_s** info,pfnamx_engine_g* amxeng,pfnms_engine_g* mseng) { + *info = &AMXInfo; + g_engAmxFunc = amxeng; + g_engModuleFunc = mseng; + + ADD_NATIVES(Engine_Exports); + + return(1); +} + +C_DLLEXPORT int AMX_Detach() { + return(1); +}