/**************************************************************************** * Project: AMX Mod X * By: BAILOPAN, JohnnyGotHisGun, Manip, PM, SniperBeamer * * Purpose:Engine and entity related natives for AMXX scripting. * * Notes: Many core functions of this module were originally made by VexD. * VexD gets the credit for setting up the framework for this, as it was * Originally VexD Utilities * * 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; std::vector vCliKillList; //This was originally by VexD //Thank you for an excellent piece of work, VexD! #define NAME "Engine Module" #define AUTHOR "BAILOPAN" #define VERSION "0.2" #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 amxxe_version = {"amxxe_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 ******************************/ //(BAILOPAN) //Sets a pvPrivateData offset for a player (player, offset, val, float=0) static cell AMX_NATIVE_CALL set_offset(AMX *amx, cell *params) { int index = params[1]; int off = params[2]; if (index < 1 || index > gpGlobals->maxClients) { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } edict_t *Player = INDEXENT(index); #ifndef __linux__ off -= 5; #endif *((int *)Player->pvPrivateData + off) = params[3]; return 1; } //(BAILOPAN) //Sets a pvPrivateData offset for a player (player, offset, Float:val) static cell AMX_NATIVE_CALL set_offset_float(AMX *amx, cell *params) { int index = params[1]; int off = params[2]; if (index < 1 || index > gpGlobals->maxClients) { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } edict_t *Player = INDEXENT(index); #ifndef __linux__ off -= 5; #endif *((float *)Player->pvPrivateData + off) = params[3]; return 1; } //(BAILOPAN) //Gets a pvPrivateData offset for a player (player, offset, float=0) static cell AMX_NATIVE_CALL get_offset(AMX *amx, cell *params) { int index = params[1]; int off = params[2]; if (index < 1 || index > gpGlobals->maxClients) { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } edict_t *Player = INDEXENT(index); #ifndef __linux__ off -= 5; #endif return (int)*((int *)Player->pvPrivateData + off); return 1; } //(BAILOPAN) //Gets a pvPrivateData offset for a player (player, offset, float=0) static cell AMX_NATIVE_CALL get_offset_float(AMX *amx, cell *params) { int index = params[1]; int off = params[2]; float retVal; if (index < 1 || index > gpGlobals->maxClients) { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } edict_t *Player = INDEXENT(index); #ifndef __linux__ off -= 5; #endif retVal = ((float)*((float *)Player->pvPrivateData + off)); return *(cell*)((void *)&retVal); return 1; } // 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(&amxxe_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); } //Added by BAILOPAN. ClientKill() forward. void ClientKill(edict_t *pEntity) { for(std::vector::iterator i = vCliKillList.begin(); i != vCliKillList.end(); i++) { cell iRetVal = 0; AMX_EXEC(&i->pPlugin->amx, &iRetVal, i->iFunctionIdx, 1, ENTINDEX(pEntity)); } 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 the forward functions. while(pCurrent){ //Iterate Plugin List //THIS IS FOR BACKWARD COMPATIBILITY 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, "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; if (AMX_FINDPUBLIC(&pCurrent->amx, "client_kill", &iFunctionIndex) == AMX_ERR_NONE) { AmxCall sNewCall; sNewCall.pPlugin = pCurrent; sNewCall.iFunctionIdx = iFunctionIndex; vCliKillList.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(); vCliKillList.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 }, {"get_offset", get_offset}, {"get_offset_float", get_offset_float}, {"set_offset", set_offset}, {"set_offset_float", set_offset_float}, {"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); }