/* AMX Mod X * Engine Module * * by the AMX Mod X Development Team * thanks to Vexd * * This file is part of AMX Mod X. * * * 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 * * In addition, as a special exception, the author gives permission to * link the code of this program with the Half-Life Game Engine ("HL * Engine") and Modified Game Libraries ("MODs") developed by Valve, * L.L.C ("Valve"). You must obey the GNU General Public License in all * respects for all of the code used other than the HL Engine and MODs * from Valve. If you modify this file, you may extend this exception * to your version of the file, but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. */ #include #include #include #include "sdk_util.h" #include #include #include #include #include "engine.h" extern "C" void destroy(MessageInfo* p) { delete p; } GlobalInfo GlInfo; MessageInfo *msgd; bool isMsgHooked[MAX_MESSAGES]; int inHookProcess; cvar_t amxxe_version = {"amxxe_version", VERSION, FCVAR_SERVER, 0}; //from OLO char* get_amxstring(AMX *amx,cell amx_addr,int id, int& len) { static char buffor[4][3072]; register cell* source = (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); register char* dest = buffor[id]; char* start = dest; while (*dest++=(char)*source++) ; len = --dest - start; return start; } cell* get_amxaddr(AMX *amx,cell amx_addr) { return (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); } /******************************************************** vexd's utility funcs ******************************************************/ // 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; } /******************************************************** exported functions ******************************************************/ //(BAILOPAN) //Calls think static cell AMX_NATIVE_CALL call_think(AMX *amx, cell *params) { int iEnt = params[1]; edict_t *pEnt = INDEXENT(iEnt); if (FNullEnt(pEnt)) { return 0; } MDLL_Think(pEnt); return 1; } //(BAILOPAN) //Hooks a register_message() static cell AMX_NATIVE_CALL register_message(AMX *amx, cell *params) { int iLen; int iFunctionIndex; int iMessage = params[1]; char *szFunction = AMX_GET_STRING(amx, params[2], iLen); if (iMessage > 0 && iMessage < MAX_MESSAGES) { if (AMX_FINDPUBLIC(amx, szFunction, &iFunctionIndex) == AMX_ERR_NONE) { isMsgHooked[iMessage] = true; Msgs.put(amx, iFunctionIndex); } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } return 1; } //(BAILOPAN) //Gets the argument type of a message argument static cell AMX_NATIVE_CALL get_msg_argtype(AMX *amx, cell *params) { int argn = params[1]; if ((inHookProcess) && (msgd != NULL)) { return msgd->ArgType(argn); } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } return 1; } //(BAILOPAN) //Gets the argument count for a message. static cell AMX_NATIVE_CALL get_msg_args(AMX *amx, cell *params) { if ((inHookProcess) && (msgd != NULL)) { return msgd->args(); } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } } //(BAILOPAN) //gets a message argument as an integer static cell AMX_NATIVE_CALL get_msg_arg_int(AMX *amx, cell *params) { int argn = params[1]; if (inHookProcess && msgd!=NULL) { if (argn < msgd->args() && argn > 0) { return msgd->RetArg_Int(argn); } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } return 1; } //(BAILOPAN) //gets a message argument as a float static cell AMX_NATIVE_CALL get_msg_arg_float(AMX *amx, cell *params) { int argn = params[1]; float retVal; if (inHookProcess && msgd!=NULL) { if (argn < msgd->args() && argn > 0) { retVal = msgd->RetArg_Float(argn); return *(cell*)((void *)&retVal); } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } return 1; } //(BAILOPAN) //gets a message argument as a string static cell AMX_NATIVE_CALL get_msg_arg_string(AMX *amx, cell *params) { int argn = params[1]; int iLen = 0; char *szValue = '\0'; if (inHookProcess && msgd!=NULL) { if (argn < msgd->args() && argn > 0) { iLen = msgd->RetArg_Strlen(argn); szValue = new char[iLen+1]; strcpy(szValue, msgd->RetArg_String(argn)); if (strlen(szValue)) { return SET_AMXSTRING(amx, params[2], szValue, params[3]); } else { return SET_AMXSTRING(amx, params[2], "", params[3]); } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } return 1; } //(BAILOPAN) static cell AMX_NATIVE_CALL set_msg_arg_string(AMX *amx, cell *params) { int argn = params[1]; int iLen; char *szData = AMX_GET_STRING(amx, params[2], iLen); if (inHookProcess && msgd!=NULL) { if (argn < msgd->args() && argn > 0) { if (msgd->Set(argn, arg_string, szData)) { return 1; } else { return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } return 1; } //(BAILOPAN) static cell AMX_NATIVE_CALL set_msg_arg_float(AMX *amx, cell *params) { int argn = params[1]; int argtype = params[2]; if (inHookProcess && msgd!=NULL) { if (argn < msgd->args() && argn > 0) { if (msgd->Set(argn, argtype, params[3])) { return 1; } else { return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } return 1; } //(BAILOPAN) static cell AMX_NATIVE_CALL set_msg_arg_int(AMX *amx, cell *params) { int argn = params[1]; int argtype = params[2]; int iData = params[3]; if (inHookProcess && msgd!=NULL) { if (argn < msgd->args() && argn > 0) { if (msgd->Set(argn, argtype, iData)) { return 1; } else { return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } } else { AMX_RAISEERROR(amx, AMX_ERR_NATIVE); return 0; } return 1; } //(BAILOPAN) //Sets a pvPrivateData offset for a player (player, offset, val, float=0) static cell AMX_NATIVE_CALL set_offset_short(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 *((short *)Player->pvPrivateData + off) = params[3]; return 1; } //(BAILOPAN) //Sets a pvPrivateData offset for a player (player, offset, val) 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) static cell AMX_NATIVE_CALL get_offset_short(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)*((short *)Player->pvPrivateData + off); } //////////////////////////////////////////// //THESE ARE FROM amxmod.cpp!!! //////////////////////////////////////////// static cell AMX_NATIVE_CALL message_begin(AMX *amx, cell *params) /* 4 param */ { int numparam = *params/sizeof(cell); Vector vecOrigin; cell *cpOrigin; switch (params[1]){ case MSG_BROADCAST: case MSG_ALL: case MSG_SPEC: MESSAGE_BEGIN( params[1], params[2],NULL ); break; case MSG_PVS: case MSG_PAS: if (numparam < 3) { AMX_RAISEERROR(amx,AMX_ERR_NATIVE); return 0; } cpOrigin = get_amxaddr(amx,params[3]); vecOrigin.x = *cpOrigin; vecOrigin.y = *(cpOrigin+1); vecOrigin.z = *(cpOrigin+2); MESSAGE_BEGIN( params[1], params[2] , vecOrigin ); break; case MSG_ONE: if (numparam < 4) { AMX_RAISEERROR(amx,AMX_ERR_NATIVE); return 0; } MESSAGE_BEGIN( MSG_ONE, params[2], NULL, INDEXENT(params[4]) ); break; } return 1; } static cell AMX_NATIVE_CALL message_end(AMX *amx, cell *params) { MESSAGE_END(); return 1; } static cell AMX_NATIVE_CALL write_byte(AMX *amx, cell *params) /* 1 param */ { WRITE_BYTE( params[1] ); return 1; } static cell AMX_NATIVE_CALL write_char(AMX *amx, cell *params) /* 1 param */ { WRITE_CHAR( params[1] ); return 1; } static cell AMX_NATIVE_CALL write_short(AMX *amx, cell *params) /* 1 param */ { WRITE_SHORT( params[1] ); return 1; } static cell AMX_NATIVE_CALL write_long(AMX *amx, cell *params) /* 1 param */ { WRITE_LONG( params[1] ); return 1; } static cell AMX_NATIVE_CALL write_entity(AMX *amx, cell *params) /* 1 param */ { WRITE_ENTITY( params[1] ); return 1; } static cell AMX_NATIVE_CALL write_angle(AMX *amx, cell *params) /* 1 param */ { WRITE_ANGLE( params[1] ); return 1; } static cell AMX_NATIVE_CALL write_coord(AMX *amx, cell *params) /* 1 param */ { WRITE_COORD( params[1] ); return 1; } static cell AMX_NATIVE_CALL write_string(AMX *amx, cell *params) /* 1 param */ { int a; WRITE_STRING( get_amxstring(amx,params[1],3,a) ); 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); } //(BAILOPAN) //Gets a pvPrivateData offset for a player (player, offset) 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; } //is an entity valid? //(BAILOPAN) static cell AMX_NATIVE_CALL is_valid_ent(AMX *amx, cell *params) { int iEnt = params[1]; if (iEnt < 1 || iEnt > gpGlobals->maxEntities) { return 0; } edict_t *pEntity = INDEXENT(iEnt); if (FNullEnt(pEntity)) { return 0; } return 1; } // Get an integer from an entities entvars. // (vexd) static cell AMX_NATIVE_CALL entity_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) { return -1; } // get its edict pointer. edict_t* pEntity = INDEXENT(iTargetEntity); // Is it a real entity? if(FNullEnt(pEntity)) { return -1; } 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: return 0; break; } return iRetValue; } //vexd static cell AMX_NATIVE_CALL entity_set_int(AMX *amx, cell *params) { int iTargetEntity = params[1]; int iValueSet = params[2]; int iNewValue = params[3]; if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { return 0; } edict_t* pEntity = INDEXENT(iTargetEntity); if(FNullEnt(pEntity)) { 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: return 0; break; } return 1; } // Gets a float out of entvars. //(vexd) static cell AMX_NATIVE_CALL entity_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) { return -1; } // Get pointer. edict_t* pEntity = INDEXENT(iTargetEntity); // is it a valid entity? if(FNullEnt(pEntity)) { return -1; } 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: return 0; break; } return *(cell*)((void *)&fRetValue); } // Almost the same as Get_float, look there for comments. static cell AMX_NATIVE_CALL entity_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) { return 0; } edict_t* pEntity = INDEXENT(iTargetEntity); if(FNullEnt(pEntity)) { 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: 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. //(vexd) static cell AMX_NATIVE_CALL entity_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) { return 0; } edict_t* pEntity = INDEXENT(iTargetEntity); if(FNullEnt(pEntity)) { 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: 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 entity_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) { return 0; } edict_t* pEntity = INDEXENT(iTargetEntity); if(FNullEnt(pEntity)) { 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: return 0; break; } return 1; } // Get an edict pointer (or index, amx does not have pointers) from entvars. //(vexd) static cell AMX_NATIVE_CALL entity_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) { return 0; } // get edict pointer of target entity edict_t* pEntity = INDEXENT(iTargetEntity); // is it valid? if(FNullEnt(pEntity)) { 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: return 0; break; } if(!FNullEnt(pRetValue)) { return ENTINDEX(pRetValue); } else { return 0; } } // Set edict is almost the same as get, look there for comments. //(vexd) static cell AMX_NATIVE_CALL entity_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) { return 0; } edict_t* pEntity = INDEXENT(iTargetEntity); if(FNullEnt(pEntity)) { return 0; } if(FNullEnt(pNewValue)) { 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: 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.). //(vexd) static cell AMX_NATIVE_CALL entity_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) { return 0; } // Get pointer of entity. edict_t* pEntity = INDEXENT(iTargetEntity); // Is entity valid again? if(FNullEnt(pEntity)) { 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: return 0; break; } return SET_AMXSTRING(amx, params[3], STRING(iszRetValue), params[4]); } // Almost the same as Get_String, look there for comments. //(vexd) static cell AMX_NATIVE_CALL entity_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) { return 0; } edict_t* pEntity = INDEXENT(iTargetEntity); if(FNullEnt(pEntity)) { 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: 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. //(vexd) static cell AMX_NATIVE_CALL entity_get_byte(AMX *amx, cell *params) { int iTargetEntity = params[1]; int iValueSet = params[2]; int iRetValue = 0; if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { return 0; } edict_t* pEntity = INDEXENT(iTargetEntity); if(FNullEnt(pEntity)) { 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: return 0; break; } return iRetValue; } // Like Get_Byte, but sets. //(vexd) static cell AMX_NATIVE_CALL entity_set_byte(AMX *amx, cell *params) { int iTargetEntity = params[1]; int iValueSet = params[2]; int iNewValue = params[3]; if (iTargetEntity < 1 || iTargetEntity > gpGlobals->maxEntities) { return 0; } edict_t* pEntity = INDEXENT(iTargetEntity); if(FNullEnt(pEntity)) { 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: 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. //(vexd) 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) { return 0; } edict_t* pEntity = INDEXENT(iTargetEntity); if(FNullEnt(pEntity)) { 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). //(vexd) 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. //(vexd) 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. //(vexd) static cell AMX_NATIVE_CALL create_entity(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)) { return 0; } return ENTINDEX(pNewEntity); } //ej ref'd by jghg static cell AMX_NATIVE_CALL find_ent_by_class(AMX *amx, cell *params) /* 3 param */ { edict_t *pEnt = INDEXENT(params[1]); int len; char* sValue = GET_AMXSTRING(amx, params[2], 1, len); pEnt = FIND_ENTITY_BY_STRING(pEnt, "classname", sValue); if(pEnt) // This even needed? return ENTINDEX(pEnt); else return 0; } // DispatchKeyValue, sets a key-value pair for a newly created entity. // Use DispatchSpawn after doing ALL DispatchKeyValues on an entity. //(vexd) 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)) { 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. //(vexd) static cell AMX_NATIVE_CALL DispatchSpawn(AMX *amx, cell *params) { edict_t* pTarget = INDEXENT(params[1]); if(FNullEnt(pTarget)) { return 0; } MDLL_Spawn(pTarget); 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. //(vexd) static cell AMX_NATIVE_CALL entity_set_origin(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) { return 0; } edict_t* pTarget = INDEXENT(iTargetEntity); if(FNullEnt(pTarget)) { return 0; } SET_SIZE(pTarget, pTarget->v.mins, pTarget->v.maxs); SET_ORIGIN(pTarget, vNewValue); return 1; } // Sets a model on an entity. Dont set models in entvars, it wont // update the engine of the model change. //(vexd) static cell AMX_NATIVE_CALL entity_set_model(AMX *amx, cell *params) { edict_t* pTarget = INDEXENT(params[1]); int iLength; char *szNewValue = AMX_GET_STRING(amx, params[2], iLength); if(FNullEnt(pTarget)) { return 0; } SET_MODEL(pTarget, szNewValue); return 1; } //FindEntityByTarget (BAILOPAN) // Works like FindEntity except finds by Target static cell AMX_NATIVE_CALL find_ent_by_target(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 0; } } int iReturnEnt = ENTINDEX(FIND_ENTITY_BY_TARGET(pStart, szValue)); if (!iReturnEnt || FNullEnt(iReturnEnt)) { return 0; } return iReturnEnt; } //FindEntityByModel (BAILOPAN) //Takes in a classname and model... static cell AMX_NATIVE_CALL find_ent_by_model(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 0; } } 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 0; } return checkEnt; } //FindEntityByTName (BAILOPAN) // Works like FindEntity except finds by TargetName static cell AMX_NATIVE_CALL find_ent_by_tname(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 0; } } int iReturnEnt = ENTINDEX(FIND_ENTITY_BY_TARGETNAME(pStart, szValue)); if (!iReturnEnt || FNullEnt(iReturnEnt)) { return 0; } return iReturnEnt; } // FindEntityByOwner (BAILOPAN) // Works like FindEntity except only returns by owner. // Searches by classname. static cell AMX_NATIVE_CALL find_ent_by_owner(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 0; } } 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 0; } return checkEnt; } //returns current number of entities in game (BAILOPAN) static cell AMX_NATIVE_CALL entity_count(AMX *amx, cell *params) { return NUMBER_OF_ENTITIES(); } // RemoveEntity, this removes an entity from the world. // Could also be done setting the flag FL_KILLME in entvars. //(vexd) static cell AMX_NATIVE_CALL remove_entity(AMX *amx, cell *params) { int iTarget = params[1]; edict_t* pTarget = INDEXENT(iTarget); if(FNullEnt(pTarget)) { return 0; } REMOVE_ENTITY(pTarget); return 1; } // VecToAngles, this is a half-life function for making a vector out of // angles. //(vexd) static cell AMX_NATIVE_CALL vector_to_angle(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). //(vexd) static cell AMX_NATIVE_CALL vector_length(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). //(vexd) static cell AMX_NATIVE_CALL vector_distance(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); } // 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). //(vexd) static cell AMX_NATIVE_CALL trace_normal(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; } // 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.) //(vexd) static cell AMX_NATIVE_CALL trace_line(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 0; } return ENTINDEX(pHit); } // Get gpGlobals->time, this is useful for timing things. //(vexd) static cell AMX_NATIVE_CALL halflife_time(AMX *amx, cell *params) { float fRetValue = gpGlobals->time; return *(cell*)((void *)&fRetValue); } //simulate two objects coliding //(vexd) static cell AMX_NATIVE_CALL fake_touch(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; } //(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) { 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; } // Sets a message block. static cell AMX_NATIVE_CALL set_msg_block(AMX *amx, cell *params) { int iMessage = params[1]; int iMessageFlags = params[2]; if (iMessage < 1 || iMessage > MAX_MESSAGES) { return 0; } GlInfo.iMessageBlock[iMessage] = iMessageFlags; return 1; } // Gets a message block. static cell AMX_NATIVE_CALL get_msg_block(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]; } // SetLights, this sets the lights for the map. //(vexd) static cell AMX_NATIVE_CALL set_lights(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; } // SetView, this sets the view of a player. This is done by // Creating a camera entity, which follows the player. //(vexd) static cell AMX_NATIVE_CALL set_view(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. //(vexd) static cell AMX_NATIVE_CALL attach_view(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; } static cell AMX_NATIVE_CALL precache_generic(AMX *amx, cell *params) { int len; char* szPreCache = GET_AMXSTRING(amx,params[1],0,len); PRECACHE_GENERIC((char*)STRING(ALLOC_STRING(szPreCache))); return 1; } /******************************************** METAMOD HOOKED FUNCTIONS *****************************************/ //Added by BAILOPAN. ClientKill() forward. void ClientKill(edict_t *pEntity) { cell iRetVal = 0; META_RES result = MRES_IGNORED; for (AmxCallList::AmxCall* i = clientKill.head; i; i = i->next) { AMX_EXEC(i->amx, &iRetVal, i->iFunctionIdx, 1, ENTINDEX(pEntity)); if (iRetVal & 2) { RETURN_META(MRES_SUPERCEDE); } else if (iRetVal & 1) { result = MRES_SUPERCEDE; } } RETURN_META(result); } // This allows us to make the player transparent when in third person (but visable to others). //(vexd) 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); } // 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. //(vexd) 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. (vexd) 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; } } for (AmxCallList::AmxCall* i = postThink.head; i; i = i->next) { AMX_EXEC(i->amx, NULL, i->iFunctionIdx, 1, ENTINDEX(pEntity)); } 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. //(vexd) 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; } } for (AmxCallList::AmxCall* i = serverFrame.head; i; i = i->next) { AMX_EXEC(i->amx, NULL, i->iFunctionIdx, 0); } RETURN_META(MRES_IGNORED); } //(BAILOPAN) - forward this void PlayerPreThink(edict_t *pEntity) { for (AmxCallList::AmxCall* i = preThink.head; i; i = i->next) { AMX_EXEC(i->amx, NULL, i->iFunctionIdx, 1, ENTINDEX(pEntity)); } RETURN_META(MRES_IGNORED); } // ClientDisconnect. Reinitialize the PlayerInfo struct for that player. //(vexd) 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); } // pfnTouch, this is a forward that is called whenever 2 entities collide. void Touch(edict_t *pToucher, edict_t *pTouched) { cell iResult; META_RES result = MRES_IGNORED; for (AmxCallList::AmxCall* i = pfnTouch.head; i; i = i->next) { AMX_EXEC(i->amx, &iResult, i->iFunctionIdx, 2, ENTINDEX(pToucher), ENTINDEX(pTouched)); if (iResult & 2) { RETURN_META(MRES_SUPERCEDE); } else if (iResult & 1) { result = MRES_SUPERCEDE; } } RETURN_META(result); } // ClientConnect, reinitialize player info here as well. //(vexd) 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; RETURN_META_VALUE(MRES_IGNORED, 0); } //(vexd) void GameInit(void) { CVAR_REGISTER(&amxxe_version); } // make sure that if we currently have an edited light value, to use it. //(vexd) void LightStyle(int style, char *val) { if(style == 0) { memset(GlInfo.szRealLights, 0x0, 128); memcpy(GlInfo.szRealLights, val, strlen(val)); } RETURN_META(MRES_IGNORED); } // Engine message functions. (vexd) 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); } else { if (isMsgHooked[msg_type] && !inHookProcess) { inHookProcess = msg_type; msgd = new MessageInfo(msg_dest, msg_type, pOrigin, ed); RETURN_META(MRES_SUPERCEDE); } } RETURN_META(MRES_IGNORED); } void MessageEnd(void) { cell iResult; META_RES result = MRES_IGNORED; if(GlInfo.bBlocking) { GlInfo.bBlocking = false; RETURN_META(MRES_SUPERCEDE); } int msg_type = inHookProcess; if (inHookProcess) { for (AmxCallList::AmxCall* i = Msgs.head; i; i = i->next) { AMX_EXEC(i->amx, &iResult, i->iFunctionIdx, 1, msg_type); if (iResult & 2) { RETURN_META(MRES_SUPERCEDE); } else if (iResult & 1) { result = MRES_SUPERCEDE; } } //clear the message inHookProcess = 0; if (result != MRES_SUPERCEDE) { //supercede the message ANYWAY msgd->SendMsg(); RETURN_META(MRES_SUPERCEDE); } destroy(msgd); msgd = NULL; } RETURN_META(result); } void WriteByte(int iValue) { if(GlInfo.bBlocking) { RETURN_META(MRES_SUPERCEDE); } int msg_type = inHookProcess; if (msg_type && msgd!=NULL) { msgd->AddArg(arg_byte, iValue); RETURN_META(MRES_SUPERCEDE); } RETURN_META(MRES_IGNORED); } void WriteChar(int iValue) { if(GlInfo.bBlocking) { RETURN_META(MRES_SUPERCEDE); } int msg_type = inHookProcess; if (msg_type && msgd!=NULL) { msgd->AddArg(arg_char, iValue); RETURN_META(MRES_SUPERCEDE); } RETURN_META(MRES_IGNORED); } void WriteShort(int iValue) { if(GlInfo.bBlocking) { RETURN_META(MRES_SUPERCEDE); } int msg_type = inHookProcess; if (msg_type && msgd!=NULL) { msgd->AddArg(arg_short, iValue); RETURN_META(MRES_SUPERCEDE); } RETURN_META(MRES_IGNORED); } void WriteLong(int iValue) { if(GlInfo.bBlocking) { RETURN_META(MRES_SUPERCEDE); } int msg_type = inHookProcess; if (msg_type && msgd!=NULL) { msgd->AddArg(arg_long, iValue); RETURN_META(MRES_SUPERCEDE); } RETURN_META(MRES_IGNORED); } void WriteAngle(float flValue) { if(GlInfo.bBlocking) { RETURN_META(MRES_SUPERCEDE); } int msg_type = inHookProcess; if (msg_type && msgd!=NULL) { msgd->AddArg(arg_angle, flValue); RETURN_META(MRES_SUPERCEDE); } RETURN_META(MRES_IGNORED); } void WriteCoord(float flValue) { if(GlInfo.bBlocking) { RETURN_META(MRES_SUPERCEDE); } int msg_type = inHookProcess; if (msg_type && msgd!=NULL) { msgd->AddArg(arg_coord, flValue); RETURN_META(MRES_SUPERCEDE); } RETURN_META(MRES_IGNORED); } void WriteString(const char *sz) { if(GlInfo.bBlocking) { RETURN_META(MRES_SUPERCEDE); } int msg_type = inHookProcess; if (msg_type && msgd!=NULL) { msgd->AddArgString(arg_string, sz); RETURN_META(MRES_SUPERCEDE); } RETURN_META(MRES_IGNORED); } void WriteEntity(int iValue) { if(GlInfo.bBlocking) { RETURN_META(MRES_SUPERCEDE); } int msg_type = inHookProcess; if (msg_type && msgd!=NULL) { msgd->AddArg(arg_entity, iValue); RETURN_META(MRES_SUPERCEDE); } RETURN_META(MRES_IGNORED); } void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ){ AMX* amx; void* code; const char* filename; int iFunctionIndex; int i=0; while ((amx = GET_AMXSCRIPT(i++, &code, &filename)) != 0) { if (AMX_FINDPUBLIC(amx, "vexd_pfntouch", &iFunctionIndex) == AMX_ERR_NONE) { pfnTouch.put(amx, iFunctionIndex); } if (AMX_FINDPUBLIC(amx, "pfn_touch", &iFunctionIndex) == AMX_ERR_NONE) { pfnTouch.put(amx, iFunctionIndex); } if (AMX_FINDPUBLIC(amx, "server_frame", &iFunctionIndex) == AMX_ERR_NONE) { serverFrame.put(amx, iFunctionIndex); } if (AMX_FINDPUBLIC(amx, "ServerFrame", &iFunctionIndex) == AMX_ERR_NONE) { serverFrame.put(amx, iFunctionIndex); } if (AMX_FINDPUBLIC(amx, "client_PreThink", &iFunctionIndex) == AMX_ERR_NONE) { preThink.put(amx, iFunctionIndex); } if (AMX_FINDPUBLIC(amx, "client_PostThink", &iFunctionIndex) == AMX_ERR_NONE) { postThink.put(amx, iFunctionIndex); } if (AMX_FINDPUBLIC(amx, "client_kill", &iFunctionIndex) == AMX_ERR_NONE) { clientKill.put(amx, iFunctionIndex); } } inHookProcess = 0; for (i=0; i mmajor || (pmajor==mmajor && pminor > mminor)) { LOG_ERROR(PLID, "metamod version is too old for this plugin; update metamod"); return(FALSE); } else if(pmajor < mmajor) { LOG_ERROR(PLID, "metamod version is incompatible with this plugin; please find a newer version of this plugin"); return(FALSE); } else if(pmajor==mmajor && pminor < mminor) LOG_MESSAGE(PLID, "WARNING: metamod version is newer than expected; consider finding a newer version of this plugin"); else LOG_ERROR(PLID, "unexpected version comparison; metavers=%s, mmajor=%d, mminor=%d; plugvers=%s, pmajor=%d, pminor=%d", ifvers, mmajor, mminor, META_INTERFACE_VERSION, pmajor, pminor); } return(TRUE); } static META_FUNCTIONS gMetaFunctionTable; C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) { if(now > Plugin_info.loadable) { LOG_ERROR(PLID, "Can't load plugin right now"); return(FALSE); } gpMetaGlobals=pMGlobals; 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 > Plugin_info.unloadable && reason != PNL_CMD_FORCED) { LOG_ERROR(PLID, "Can't unload plugin right now"); return(FALSE); } return(TRUE); } #ifdef __linux__ C_DLLEXPORT void GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) { #else void WINAPI GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) { #endif memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); gpGlobals = pGlobals; } DLL_FUNCTIONS gFunctionTable; C_DLLEXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ){ gFunctionTable.pfnGameInit = GameInit; gFunctionTable.pfnStartFrame = StartFrame; gFunctionTable.pfnTouch = Touch; gFunctionTable.pfnServerDeactivate = ServerDeactivate; gFunctionTable.pfnClientDisconnect = ClientDisconnect; gFunctionTable.pfnServerActivate = ServerActivate; gFunctionTable.pfnClientConnect = ClientConnect; gFunctionTable.pfnClientDisconnect = ClientDisconnect; gFunctionTable.pfnPlayerPostThink = PlayerPostThink; gFunctionTable.pfnPlayerPreThink = PlayerPreThink; gFunctionTable.pfnClientUserInfoChanged = ClientUserInfoChanged; gFunctionTable.pfnAddToFullPack = AddToFullPack; gFunctionTable.pfnClientKill = ClientKill; if(*interfaceVersion!=INTERFACE_VERSION) { LOG_ERROR(PLID, "GetEntityAPI2 version mismatch; requested=%d ours=%d", *interfaceVersion, INTERFACE_VERSION); *interfaceVersion = INTERFACE_VERSION; return(FALSE); } memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); return(TRUE); } enginefuncs_t meta_engfuncs; C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion ) { 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; if(*interfaceVersion!=ENGINE_INTERFACE_VERSION) { LOG_ERROR(PLID, "GetEngineFunctions version mismatch; requested=%d ours=%d", *interfaceVersion, ENGINE_INTERFACE_VERSION); *interfaceVersion = ENGINE_INTERFACE_VERSION; return(FALSE); } memcpy(pengfuncsFromEngine, &meta_engfuncs, sizeof(enginefuncs_t)); return(TRUE); } enginefuncs_t meta_engfuncs_post; C_DLLEXPORT int GetEngineFunctions_Post(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion ) { if(*interfaceVersion!=ENGINE_INTERFACE_VERSION) { LOG_ERROR(PLID, "GetEngineFunctions_Post version mismatch; requested=%d ours=%d", *interfaceVersion, ENGINE_INTERFACE_VERSION); *interfaceVersion = ENGINE_INTERFACE_VERSION; return(FALSE); } memcpy(pengfuncsFromEngine, &meta_engfuncs_post, sizeof(enginefuncs_t)); return(TRUE); } C_DLLEXPORT int AMX_Query(module_info_s** info) { *info = &module_info; return 1; } C_DLLEXPORT int AMX_Attach(pfnamx_engine_g* amxeng,pfnmodule_engine_g* meng) { g_engAmxFunc = amxeng; g_engModuleFunc = meng; if (!gpMetaGlobals) REPORT_ERROR( 1 , "[CS STATS] Module is not attached to MetaMod\n"); ADD_AMXNATIVES( &module_info , Engine_Natives); return 1; } C_DLLEXPORT int AMX_Detach() { return 1; } AMX_NATIVE_INFO Engine_Natives[] = { {"set_offset_float", set_offset_float}, {"set_offset_short", set_offset_short}, {"set_offset", set_offset}, {"get_offset_float", get_offset_float}, {"get_offset_short", get_offset_short}, {"get_offset", get_offset}, {"entity_get_float", entity_get_float}, {"entity_set_float", entity_set_float}, {"entity_set_int", entity_set_int}, {"entity_get_int", entity_get_int}, {"entity_get_vector", entity_get_vector}, {"entity_get_string", entity_get_string}, {"entity_get_edict", entity_get_edict}, {"entity_get_byte", entity_get_byte}, {"entity_set_vector", entity_set_vector}, {"entity_set_string", entity_set_string}, {"entity_set_edict", entity_set_edict}, {"entity_set_byte", entity_set_byte}, {"entity_set_origin", entity_set_origin}, {"entity_set_model", entity_set_model}, {"PointContents", PointContents}, {"RadiusDamage", RadiusDamage}, {"VelocityByAim", VelocityByAim}, {"vector_length", vector_length}, {"vector_distance", vector_distance}, {"vector_to_angle", vector_to_angle}, {"trace_line", trace_line}, {"trace_normal", trace_normal}, {"halflife_time", halflife_time}, {"fake_touch", fake_touch}, {"get_grenade_id", get_grenade_id}, {"create_entity", create_entity}, {"remove_entity", remove_entity}, {"find_ent_by_class", find_ent_by_class}, {"find_ent_by_classname", find_ent_by_class}, // just in case anyone likes typing the whole thing {"find_ent_by_owner", find_ent_by_owner}, {"find_ent_by_target", find_ent_by_target}, {"find_ent_by_tname", find_ent_by_tname}, {"find_ent_by_model", find_ent_by_model}, {"entity_count", entity_count}, {"DispatchKeyValue", DispatchKeyValue}, {"DispatchSpawn", DispatchSpawn}, {"set_msg_block", set_msg_block}, {"get_msg_block", get_msg_block}, {"set_lights", set_lights}, {"set_view", set_view}, {"attach_view", attach_view}, {"precache_generic", precache_generic}, {"register_message", register_message}, {"set_msg_arg_float", set_msg_arg_float}, {"set_msg_arg_int", set_msg_arg_int}, {"set_msg_arg_string", set_msg_arg_string}, {"get_msg_arg_float", get_msg_arg_float}, {"get_msg_arg_int", get_msg_arg_int}, {"get_msg_arg_string", get_msg_arg_string}, {"get_msg_args", get_msg_args}, {"get_msg_argtype", get_msg_argtype}, {"message_begin", message_begin}, {"message_end", message_end}, {"write_angle", write_angle}, {"write_byte", write_byte}, {"write_char", write_char}, {"write_coord", write_coord}, {"write_entity", write_entity}, {"write_long", write_long}, {"write_short", write_short}, {"write_string", write_string}, {"is_valid_ent", is_valid_ent}, { NULL, NULL } };