diff --git a/amxmodx/CCmd.cpp b/amxmodx/CCmd.cpp new file mode 100755 index 00000000..9214420f --- /dev/null +++ b/amxmodx/CCmd.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" +#include "CCmd.h" + +// ***************************************************** +// class CmdMngr +// ***************************************************** +CmdMngr::CmdMngr() { + memset(sortedlists,0,sizeof(sortedlists)); + srvcmdlist = 0; + clcmdlist = 0; + prefixHead = 0; + buf_type = -1; + buf_access = 0; + buf_id = -1; + buf_cmdid = -1; + buf_cmdtype = -1; + buf_cmdaccess = 0; + +} + +CmdMngr::Command::Command( CPluginMngr::CPlugin* pplugin,const char* pcmd, + const char* pinfo , int pflags , int pfunc, + bool pviewable, CmdMngr* pparent ) : commandline(pcmd) , info(pinfo) { + + char szCmd[64], szArg[64]; + *szCmd = 0; *szArg=0; + sscanf(pcmd,"%s %s",szCmd,szArg); + command.set(szCmd); + argument.set(szArg); + plugin = pplugin; + flags = pflags; + cmdtype = 0; + prefix = 0; + function = pfunc; + listable = pviewable; + parent = pparent; + id = --uniqueid; +} + +CmdMngr::Command::~Command() +{ + ++uniqueid; +} + +CmdMngr::Command* CmdMngr::registerCommand( CPluginMngr::CPlugin* plugin , int func , char* cmd , char* info , int level , bool listable ) +{ + Command* b = new Command( plugin , cmd , info , level , func , listable, this ); + if ( b == 0 ) return 0; + setCmdLink( &sortedlists[0] , b ); + return b; +} + +CmdMngr::Command* CmdMngr::getCmd( long int id ,int type, int access ) +{ + //if ( id >= 1024 || id < 0 ) return (Command*)id; + if ( id < 0 ){ + for (CmdMngr::iterator a = begin( type ); a ; ++a){ + if ( (*a).id == id ) + return &(*a); + } + return 0; + } + + if ( (id < buf_cmdid) || (access != buf_cmdaccess) || (type != buf_cmdtype) ) + { + buf_cmdptr = begin( type ); + buf_cmdaccess = access; + buf_cmdtype = type; + buf_cmdid = id; + } + else + { + int a = id; + id -= buf_cmdid; + buf_cmdid = a; + } + + while ( buf_cmdptr ) + { + + if ( (*buf_cmdptr).gotAccess( access ) && + (*buf_cmdptr).getPlugin()->isExecutable( (*buf_cmdptr).getFunction() ) + && (*buf_cmdptr).isViewable() ) + { + + if ( id-- == 0 ) + return &(*buf_cmdptr); + + } + + ++buf_cmdptr; + } + + return 0; +} + +int CmdMngr::getCmdNum( int type, int access ) +{ + if ( (access == buf_access) && (type == buf_type) ) + return buf_num; // once calculated don't have to be done again + + buf_access = access; + buf_type = type; + buf_num = 0; + + CmdMngr::iterator a = begin( type ); + + while ( a ) + { + + if ( (*a).gotAccess( access ) && + (*a).getPlugin()->isExecutable( (*a).getFunction() ) + && (*a).isViewable() ) + ++buf_num; + ++a; + } + + return buf_num; +} + +void CmdMngr::setCmdLink( CmdLink** a , Command* c, bool sorted ) +{ + CmdLink* np = new CmdLink( c ); + + if ( np == 0 ) return; + + if ( sorted ) + { + while( *a ) + { + int i = strcmp(c->getCommand(),(*a)->cmd->getCommand() ); + + if ( (i<0) || (i==0) && ( strcmp( c->getArgument() , (*a)->cmd->getArgument() ) < 0 ) ) + break; + + a = &(*a)->next; + } + + np->next = *a; + *a = np; + } + else + { + while ( *a ) a = &(*a)->next; + *a = np; + } + + +} + +void CmdMngr::clearCmdLink( CmdLink** phead, bool pclear ) +{ + while( *phead ){ + CmdLink* pp = (*phead)->next; + if ( pclear ) delete (*phead)->cmd; + delete *phead; + *phead = pp; + } +} + +void CmdMngr::Command::setCmdType( int a ) +{ + switch(a){ + case CMD_ConsoleCommand: cmdtype |= 3; break; + case CMD_ClientCommand: cmdtype |= 1; break; + case CMD_ServerCommand: cmdtype |= 2; break; + } + if ( cmdtype & 1 ) { // ClientCommand + parent->setCmdLink( &parent->sortedlists[1] , this ); + if ( !parent->registerCmdPrefix( this ) ) + parent->setCmdLink( &parent->clcmdlist , this , false ); + } + if ( cmdtype & 2 ) { // ServerCommand + parent->setCmdLink( &parent->sortedlists[2] , this ); + parent->setCmdLink( &parent->srvcmdlist , this , false ); + } +} + +const char* CmdMngr::Command::getCmdType() const { + switch( cmdtype ){ + case 1: return"client"; + case 2: return "server"; + case 3: return "console"; + } + return "unknown"; +} + +bool CmdMngr::registerCmdPrefix( Command* cc ) +{ + CmdPrefix** b = findPrefix( cc->getCommand() ); + if (*b){ + setCmdLink( &(*b)->list , cc , false ); + cc->prefix = (*b)->name.size(); + return true; + } + return false; +} + +void CmdMngr::registerPrefix( const char* nn ) +{ + if ( *nn == 0 ) return; + CmdPrefix** b = findPrefix( nn ); + if (*b) return; + *b = new CmdPrefix( nn , this ); +} + +CmdMngr::CmdPrefix** CmdMngr::findPrefix( const char* nn ){ + CmdPrefix** aa = &prefixHead; + while(*aa){ + if ( !strncmp( (*aa)->name.str(), nn, (*aa)->name.size() ) ) + break; + aa=&(*aa)->next; + } + return aa; +} + +void CmdMngr::clearPrefix(){ + while(prefixHead){ + CmdPrefix* a = prefixHead->next; + delete prefixHead; + prefixHead = a; + } +} + +void CmdMngr::clear() +{ + clearCmdLink(&sortedlists[0], true); + clearCmdLink(&sortedlists[1]); + clearCmdLink(&sortedlists[2]); + clearCmdLink(&srvcmdlist); + clearCmdLink(&clcmdlist); + clearPrefix(); + clearBufforedInfo(); +} + +void CmdMngr::clearBufforedInfo() { + buf_type = -1; + buf_access = 0; + buf_id = -1; + buf_cmdid = -1; + buf_cmdtype = -1; + buf_cmdaccess = 0; +} + +int CmdMngr::Command::uniqueid = 0; \ No newline at end of file diff --git a/amxmodx/CCmd.h b/amxmodx/CCmd.h new file mode 100755 index 00000000..41806bd4 --- /dev/null +++ b/amxmodx/CCmd.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef COMMANDS_H +#define COMMANDS_H + +// ***************************************************** +// class CmdMngr +// ***************************************************** + +enum { + CMD_ConsoleCommand, + CMD_ClientCommand, + CMD_ServerCommand +}; + +class CmdMngr +{ +public: + class Command; + friend class Command; + + class Command { + friend class CmdMngr; + CPluginMngr::CPlugin* plugin; + CmdMngr* parent; + String command; + String argument; + String commandline; + String info; + bool listable; + int function; + int flags; + int id; + int cmdtype; + int prefix; + static int uniqueid; + Command( CPluginMngr::CPlugin* pplugin,const char* pcmd, const char* pinfo , int pflags , int pfunc, bool pviewable, CmdMngr* pparent ); + ~Command(); + public: + + inline const char* getCommand() const{ return command.str(); } + inline const char* getArgument() const{ return argument.str(); } + inline const char* getCmdInfo() const{ return info.str(); } + inline const char* getCmdLine() const{ return commandline.str(); } + inline bool matchCommandLine(const char* cmd, const char* arg) { return (!stricmp(command.str()+prefix, cmd+prefix ) && (argument.empty() || !stricmp(argument.str() , arg ))); } + inline bool matchCommand(const char* cmd) { return (!strcmp(command.str(), cmd )); } + inline int getFunction() const { return function; } + inline bool gotAccess(int f) const { return (!flags||((flags & f)==flags)); } + inline CPluginMngr::CPlugin* getPlugin() { return plugin; } + inline bool isViewable() const { return listable; } + inline int getFlags() const { return flags; } + inline long int getId() const { return (long int)id; } + const char* getCmdType() const; + void setCmdType( int a ); + + }; + +private: + + struct CmdPrefix; + friend struct CmdPrefix; + + struct CmdLink { + Command* cmd; + CmdLink* next; + CmdLink(Command* c): cmd(c), next(0) {} + }; + + CmdLink* sortedlists[3]; + CmdLink* srvcmdlist; + CmdLink* clcmdlist; + + struct CmdPrefix { + CmdMngr* parent; + String name; + CmdLink* list; + CmdPrefix* next; + CmdPrefix( const char* nn , CmdMngr* pp) : name(nn),parent(pp),list(0),next(0){} + ~CmdPrefix(){ parent->clearCmdLink(&list); } + } *prefixHead; + + bool registerCmdPrefix( Command* cc ); + CmdPrefix** findPrefix( const char* nn ); + void clearPrefix(); + + void setCmdLink( CmdLink** a , Command* c, bool sorted = true ); + void clearCmdLink( CmdLink** phead, bool pclear = false ); + +public: + CmdMngr(); + ~CmdMngr() {clear();} + + // Interface + + void registerPrefix( const char* nn ); + Command* registerCommand( CPluginMngr::CPlugin* plugin , int func , char* cmd , char* info , int level , bool listable ); + Command* getCmd( long int id ,int type, int access); + int getCmdNum( int type, int access ); + void clearBufforedInfo(); + void clear(); + + class iterator { + CmdLink *a; + public: + iterator(CmdLink*aa = 0) : a(aa) {} + iterator& operator++() { a = a->next; return *this; } + bool operator==(const iterator& b) const { return a == b.a; } + bool operator!=(const iterator& b) const { return !operator==(b); } + operator bool () const { return a ? true : false; } + Command& operator*() { return *a->cmd; } + }; + inline iterator clcmdprefixbegin(const char* nn){ + CmdPrefix* a = *findPrefix(nn); + return iterator( a ? a->list : 0 ); + } + inline iterator clcmdbegin() const {return iterator(clcmdlist);} + inline iterator srvcmdbegin() const {return iterator(srvcmdlist);} + inline iterator begin( int type ) const { return iterator(sortedlists[type]); } + inline iterator end() const { return iterator(0); } + +private: + + int buf_cmdid; + int buf_cmdtype; + int buf_cmdaccess; + iterator buf_cmdptr; + + int buf_id; + int buf_type; + int buf_access; + int buf_num; + +}; + +#endif + diff --git a/amxmodx/CEvent.cpp b/amxmodx/CEvent.cpp new file mode 100755 index 00000000..c5891cef --- /dev/null +++ b/amxmodx/CEvent.cpp @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" +#include "CEvent.h" + +// ***************************************************** +// class EventsMngr +// ***************************************************** +EventsMngr::EventsMngr() +{ + memset( modMsgsFunCall, 0 , sizeof(modMsgsFunCall) ); +} +EventsMngr::~EventsMngr() +{ + clearEvents(); +} + +EventsMngr::ClEvent::ClEvent( CPluginMngr::CPlugin* amxplugin, int function, int flags ) +{ + plugin = amxplugin; + func = function; + stamp = 0.0; + next = 0; + done = false; + alive=true; + dead=true; + if ( flags & 24 ){ + alive=(flags&16)?true:false; //e + dead=(flags&8)?true:false; //d + } + world=(flags&1)?true:false; //a + player=(flags&2)?true:false; //b + once=(flags&4)?true:false; //c + memset(cond,0,sizeof(cond)); +} + +void EventsMngr::ClEvent::registerFilter( char* filter ) +{ + if ( filter == 0 ) return; + + char* value = filter; + + while ( isdigit(*value) ) + ++value; + + if ( *value == 0 ) return; + + cond_t* b = new cond_t; + + if ( b == 0 ) return; + + b->type = *value; + + *value++ = 0; + + b->sValue.set(value); + b->fValue = atof(value); + b->iValue = atoi(value); + + int i = atoi(filter); + if (i >= 0 && i < MAX_PARSE_VALUES) { + b->next = cond[i]; + cond[i] = b; + } + else delete b; +} + +EventsMngr::ClEvent* EventsMngr::registerEvent( CPluginMngr::CPlugin* p, int f, int flags, int pos ) +{ + ClEvent* a = new ClEvent( p , f , flags ); + if ( a == 0 ) return 0; + ClEvent** end = &modMsgsFunCall[pos]; + while( *end ) end = &(*end)->next; + return *end = a; +} + +void EventsMngr::parserInit(int msg_type, float* tim, CPlayer *pPlayer, int index) { + parseNotDone = false; + timer = tim; + if ( (parseFun = modMsgsFunCall[msg_type]) == 0 ) return; + + for(EventsMngr::ClEvent*p=parseFun;p;p=p->next){ + if ( p->done ) continue; + if ( !p->plugin->isExecutable(p->func) ){ + p->done = true; + continue; + } + if ( pPlayer ) { + if ( !p->player || ( pPlayer->IsAlive() ? !p->alive : !p->dead ) ) { + p->done = true; + continue; + } + } + else if ( !p->world ){ + p->done = true; + continue; + } + if ( p->once && p->stamp == (float)(*timer) ){ + p->done = true; + continue; + } + parseNotDone = true; + } + if ( parseNotDone ) { + parseVault[parsePos = 0].type = MSG_INTEGER; + parseVault[parsePos].iValue = index; + } +} + + +const char* EventsMngr::getArgString(int a) +{ + if ( a < 0 || a > parsePos ) return ""; + static char var[32]; + switch(parseVault[a].type){ + case MSG_INTEGER: + sprintf( var, "%d", parseVault[a].iValue ); + return var; + case MSG_STRING: + return parseVault[a].sValue; + default: + sprintf( var, "%g", parseVault[a].fValue ); + return var; + } +} + +int EventsMngr::getArgInteger(int a) +{ + if ( a < 0 || a > parsePos ) return 0; + switch(parseVault[a].type){ + case MSG_INTEGER: return parseVault[a].iValue; + case MSG_STRING: return atoi(parseVault[a].sValue); + default: return (int)parseVault[a].fValue; + } +} + +float EventsMngr::getArgFloat(int a) +{ + if ( a < 0 || a > parsePos ) return 0.0f; + switch(parseVault[a].type){ + case MSG_INTEGER: return parseVault[a].iValue; + case MSG_STRING: return atof(parseVault[a].sValue); + default: return parseVault[a].fValue; + } +} + + + +void EventsMngr::executeEvents() { + int err; + +#ifdef ENABLEEXEPTIONS + try + { +#endif + + for ( ClEvent*p = parseFun ; p ; p = p->next ) + { + + if ( p->done ) + { + p->done = false; + continue; + } + + p->stamp = *timer; + + if ((err = amx_Exec(p->plugin->getAMX(), NULL , p->func , 1,parseVault[0].iValue)) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n",err,p->plugin->getAMX()->curline,p->plugin->getName()); + + } + +#ifdef ENABLEEXEPTIONS + } + catch( ... ) + { + print_srvconsole( "[AMX] fatal error at event execution\n"); + } +#endif + +} + +void EventsMngr::parseValue(int iValue) { + if ( !parseNotDone ) return; + parseVault[++parsePos].type = MSG_INTEGER; + parseVault[parsePos].iValue = iValue; + bool skip; + for (ClEvent*p=parseFun;p;p=p->next){ + if ( p->done || !p->cond[parsePos] ) continue; + skip = false; + ClEvent::cond_t* a = p->cond[parsePos]; + do { + switch(a->type){ + case '=': if (a->iValue == iValue) skip=true; break; + case '!': if (a->iValue != iValue) skip=true; break; + case '&': if (iValue & a->iValue) skip=true; break; + case '<': if (iValue < a->iValue) skip=true; break; + case '>': if (iValue > a->iValue) skip=true; break; + } + if (skip) break; + } while ( a = a->next ); + if (skip) continue; + p->done = true; + } +} + +void EventsMngr::parseValue(float flValue) { + if ( !parseNotDone ) return; + parseVault[++parsePos].type = MSG_FLOAT; + parseVault[parsePos].fValue = flValue; + bool skip; + for (ClEvent*p=parseFun;p;p=p->next){ + if ( p->done || !p->cond[parsePos] ) continue; + skip = false; + ClEvent::cond_t* a = p->cond[parsePos]; + do { + switch(a->type){ + case '=': if (a->fValue == flValue) skip=true; break; + case '!': if (a->fValue != flValue) skip=true; break; + case '<': if (flValue < a->fValue) skip=true; break; + case '>': if (flValue > a->fValue) skip=true; break; + } + if (skip) break; + } while ( a = a->next ); + if (skip) continue; + p->done = true; + } +} + +void EventsMngr::parseValue(const char *sz) { + if ( !parseNotDone ) return; + parseVault[++parsePos].type = MSG_STRING; + parseVault[parsePos].sValue = sz; + bool skip; + for (ClEvent*p=parseFun;p;p=p->next){ + if ( p->done || !p->cond[parsePos] ) continue; + skip = false; + ClEvent::cond_t* a = p->cond[parsePos]; + do { + switch(a->type){ + case '=': if (!strcmp(sz,a->sValue.str())) skip=true; break; + case '!': if (strcmp(sz,a->sValue.str())) skip=true; break; + case '&': if (strstr(sz,a->sValue.str())) skip=true; break; + } + if (skip) break; + } while ( a = a->next ); + if (skip) continue; + p->done = true; + } +} + +void EventsMngr::clearEvents() +{ + for(int i=0;inext; + delete *b; + *b = aa; + } + } +} + +EventsMngr::ClEvent::~ClEvent(){ + for(int a = 0; a < MAX_PARSE_VALUES; ++a){ + cond_t** b = &cond[a]; + while(*b){ + cond_t* nn = (*b)->next; + delete *b; + *b = nn; + } + } +} + +EventsMngr::ClEvent* EventsMngr::getValidEvent(ClEvent* a ) { + while(a){ + if ( a->done ) { + a->done = false; + a = a->next; + continue; + } + a->stamp = *timer; + return a; + } + return 0; +} + +int EventsMngr::getEventId( const char* msg ){ + struct CS_Events { + const char* name; + CS_EventsIds id; + } table[] = { + { "CS_DeathMsg" , CS_DeathMsg }, +// { "CS_RoundEnd" , CS_RoundEnd }, +// { "CS_RoundStart" , CS_RoundStart }, +// { "CS_Restart" , CS_Restart }, + { "" , CS_Null } + }; + int pos; + if ( (pos = atoi( msg )) != 0 ) + return pos; + for (pos = 0; table[ pos ].id != CS_Null; ++pos ) + if ( !strcmp( table[ pos ].name , msg ) ) + return table[ pos ].id; + return pos = GET_USER_MSG_ID(PLID, msg , 0 ); +} diff --git a/amxmodx/CEvent.h b/amxmodx/CEvent.h new file mode 100755 index 00000000..06e26725 --- /dev/null +++ b/amxmodx/CEvent.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef EVENTS_H +#define EVENTS_H + +#define MAX_PARSE_VALUES 32 +#define MAX_AMX_REG_MSG MAX_REG_MSGS+16 + +enum { + CS_DEATHMSG = MAX_REG_MSGS, +// CS_ROUNDEND, +// CS_ROUNDSTART, +// CS_RESTART, +}; + +// ***************************************************** +// class EventsMngr +// ***************************************************** + + +class EventsMngr { + + enum MsgValueType{ + MSG_INTEGER, + MSG_FLOAT, + MSG_STRING, + }; + +public: + + enum CS_EventsIds { + CS_Null = 0, + CS_DeathMsg = MAX_REG_MSGS, // start from last element +// CS_RoundEnd, +// CS_RoundStart, +// CS_Restart, + }; + + class iterator; + friend class iterator; + + class ClEvent { + friend class EventsMngr; + friend class iterator; + CPluginMngr::CPlugin* plugin; + int func; + bool player; + bool world; + bool once; + bool done; + bool dead; + bool alive; + float stamp; + struct cond_t { + String sValue; + float fValue; + int iValue; + int type; + cond_t* next; + } *cond[MAX_PARSE_VALUES]; + ClEvent* next; + ClEvent( CPluginMngr::CPlugin* p, int f, int flags ); + ~ClEvent(); + public: + inline CPluginMngr::CPlugin* getPlugin() { return plugin; } + inline int getFunction() { return func; } + void registerFilter( char* filter ); + }; + +private: + struct MsgDataVault { + float fValue; + int iValue; + const char* sValue; + MsgValueType type; + } parseVault[MAX_PARSE_VALUES]; + + + ClEvent* modMsgsFunCall[MAX_AMX_REG_MSG]; + ClEvent* parseFun; + bool parseNotDone; + int parsePos; // is -1 less then args. num. + float* timer; + ClEvent* getValidEvent(ClEvent* a ); + +public: + EventsMngr(); + ~EventsMngr(); + + // Interface + + ClEvent* registerEvent( CPluginMngr::CPlugin* p, int f, int flags, int pos ); + void parserInit(int msg_type, float* timer , CPlayer* target = 0, int index = 0); + void parseValue(int iValue); + void parseValue(float fValue); + void parseValue(const char *sz); + void executeEvents(); + inline int getArgNum() { return (parsePos+1); } + const char* getArgString(int a); + int getArgInteger(int a); + float getArgFloat(int a); + void clearEvents(void); + static int getEventId( const char* msg ); + + + class iterator { + EventsMngr* b; + ClEvent* a; + public: + inline iterator(ClEvent*aa,EventsMngr* bb) : a(aa), b(bb) {} + inline iterator& operator++() { + a = b->getValidEvent( a->next ); + return *this; + } + inline bool operator==(const iterator& c) const { return a == c.a; } + inline bool operator!=(const iterator& c) const { return !operator==(c); } + ClEvent& operator*() { return *a; } + operator bool ( ) const { return a ? true : false; } + }; + inline iterator begin() { return iterator(getValidEvent(parseFun),this); } + inline iterator end() { return iterator(0,this); } +}; + +#endif + diff --git a/amxmodx/CFile.cpp b/amxmodx/CFile.cpp new file mode 100755 index 00000000..a881c074 --- /dev/null +++ b/amxmodx/CFile.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "CFile.h" +#include + +// ***************************************************** +// class File +// ***************************************************** +File::File( const char* n, const char* m ) +{ + fp = fopen( n , m ); +} + +File::~File( ) +{ + if ( fp ) + fclose( fp ); +} + +File::operator bool ( ) const +{ + return fp && !feof(fp); +} + +File& operator<<( File& f, const String& n ) +{ + if ( f ) fputs( n.str() , f.fp ) ; + return f; +} + +File& operator<<( File& f, const char* n ) +{ + if ( f ) fputs( n , f.fp ) ; + return f; +} + +File& operator<<( File& f, int n ) +{ + if ( f ) fprintf( f.fp , "%d" , n ) ; + return f; +} + + +File& operator<<( File& f, const char& c ) +{ + if ( f ) fputc( c , f.fp ) ; + return f; +} + +File& operator>>( File& f, String& n ) +{ + if ( !f ) return f; + char temp[1024]; + fscanf( f.fp , "%s", temp ); + n.set(temp); + return f; +} + +File& operator>>( File& f, char* n ) +{ + if ( f ) fscanf( f.fp , "%s", n ); + return f; +} + +int File::getline( char* buf, int sz ) +{ + int a = sz; + if ( *this ) + { + int c; + while ( sz-- && (c = getc( (*this).fp)) && c != EOF && c != '\n' ) + *buf++ = c; + *buf = 0; + } + return a - sz; +} + +File& File::skipWs( ) +{ + if ( !*this ) return *this; + int c; + while( isspace( c = getc( fp ) ) ){}; + ungetc( c , fp ); + return *this; +} + diff --git a/amxmodx/CFile.h b/amxmodx/CFile.h new file mode 100755 index 00000000..c85793a2 --- /dev/null +++ b/amxmodx/CFile.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "CString.h" +#include + +// ***************************************************** +// class File +// ***************************************************** + +class File +{ + FILE* fp; + +public: + File( const char* n, const char* m ); + ~File( ); + operator bool ( ) const; + friend File& operator<<( File& f, const String& n ); + friend File& operator<<( File& f, const char* n ); + friend File& operator<<( File& f, const char& c ); + friend File& operator<<( File& f, int n ); + friend File& operator>>( File& f, String& n ); + friend File& operator>>( File& f, char* n ); + int getline( char* buf, int sz ); + File& skipWs( ); +}; + + + diff --git a/amxmodx/CForward.cpp b/amxmodx/CForward.cpp new file mode 100755 index 00000000..68a5ea91 --- /dev/null +++ b/amxmodx/CForward.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" +#include "CForward.h" + +void CForwardMngr::registerForward( CPluginMngr::CPlugin* p, int func , int type ){ + + CForward** a = &head[ type ]; + while(*a) a = &(*a)->next; + *a = new CForward( p , func ); + +} + +void CForwardMngr::clearForwards( CForward** a ){ + while( *a ) { + CForward* b = (*a)->next; + delete *a; + *a = b; + } +} + +void CForwardMngr::clear() +{ + for ( int a = 0; a < FORWARD_NUM; ++a ) + clearForwards( &head[ a ] ); +} + +void CForwardMngr::executeForwards( int type , int num , int player ) { + + cell ret = 0; + int err; + CForward* a = head[ type ]; + + while ( a ) + { + if ( a->getPlugin()->isExecutable( a->getFunction() ) ) + { + + if ((err = amx_Exec(a->getPlugin()->getAMX(), &ret, a->getFunction() , num, player)) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n", err,a->getPlugin()->getAMX()->curline,a->getPlugin()->getName()); + + if ( ret ) + break; + + } + + a = a->next; + } +} \ No newline at end of file diff --git a/amxmodx/CForward.h b/amxmodx/CForward.h new file mode 100755 index 00000000..c22f14b8 --- /dev/null +++ b/amxmodx/CForward.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef FORWARD_H +#define FORWARD_H + +// ***************************************************** +// class CmdMngr +// ***************************************************** + +#define FORWARD_NUM 12 + +enum { + FF_ClientCommand, + FF_ClientConnect, + FF_ClientDisconnect, + FF_ClientInfoChanged, + FF_ClientPutInServer, + FF_PluginInit, + FF_PluginCfg, + FF_PluginPrecache, + FF_PluginLog, + FF_PluginEnd, + FF_InconsistentFile, + FF_ClientAuthorized, +}; + +class CForwardMngr +{ +public: + + class iterator; + + class CForward + { + + friend class iterator; + friend class CForwardMngr; + + CPluginMngr::CPlugin* plugin; + int function; + CForward* next; + CForward( CPluginMngr::CPlugin* p, int func ) : plugin(p) , function(func) {next=0;} + + public: + inline CPluginMngr::CPlugin* getPlugin() { return plugin; } + inline int getFunction() { return function; } + + + + }; + + + +private: + CForward *head[ FORWARD_NUM ]; + void clearForwards( CForward** a ); + +public: + CForwardMngr() {memset( head, 0, sizeof(head));} + ~CForwardMngr() { clear(); } + + // Interface + + void registerForward( CPluginMngr::CPlugin* p, int func , int type ); + void executeForwards( int type , int num = 0, int player = 0 ); + void clear(); + + + class iterator { + CForward *a; + public: + iterator(CForward*aa) : a(aa) {} + iterator& operator++() { a = a->next; return *this; } + bool operator==(const iterator& b) const { return a == b.a; } + bool operator!=(const iterator& b) const { return !operator==(b); } + operator bool () const { return a ? true : false; } + CForward& operator*() { return *a; } + }; + inline iterator begin( int type ) const { return iterator(head[(int)type]); } + inline iterator end() const { return iterator(0); } + inline bool forwardsExist( int type ) {return head[(int)type]?true:false;} +}; + + +#endif + diff --git a/amxmodx/CList.h b/amxmodx/CList.h new file mode 100755 index 00000000..a58a3c60 --- /dev/null +++ b/amxmodx/CList.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef CLIST_H +#define CLIST_H + +// ***************************************************** +// class CList +// ***************************************************** + +template +class CList { +public: + class iterator; + class CListEle { + friend class CList; + friend class iterator; + T* obj; + CListEle* next; + CListEle( T* a , CListEle* nn ) : obj(a) , next(nn) {} + public: + T& operator* () { return *obj; } + }; +private: + CListEle *head; +public: + CList() { head = 0; } + ~CList() { clear(); } + void clear() { + iterator a = begin(); + while( a ) a.remove(); + } + void put( T* a ) { + head = new CListEle( a , head ); + } + class iterator { + CListEle** a; + public: + iterator(CListEle** i=0) : a(i){} + T& operator*() const { return *(*a)->obj;} + inline operator bool () const { return (a && *a); } + inline iterator& operator++() { + a = &(*a)->next; + return *this; + } + inline iterator operator++(int) { + iterator tmp(a); + a = &(*a)->next; + return tmp; + } + iterator& remove(){ + CListEle* aa = (*a)->next; + delete (*a)->obj; + delete *a; + *a = aa; + return *this; + } + iterator& put( T* aa ){ + *a = new CListEle( aa , *a ); + return *this; + } + }; + inline iterator begin() { return iterator(&head); } + iterator find( F a ){ + iterator cc = begin(); + while(cc){ + if ( *cc == a ) + break; + ++cc; + } + return cc; + } +}; + +#endif + diff --git a/amxmodx/CLogEvent.cpp b/amxmodx/CLogEvent.cpp new file mode 100755 index 00000000..e51a09b3 --- /dev/null +++ b/amxmodx/CLogEvent.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" +#include "CLogEvent.h" + +// ***************************************************** +// class LogEventsMngr +// ***************************************************** +LogEventsMngr::LogEventsMngr() { + logCurrent = logCounter = 0; + logcmplist = 0; + arelogevents = false; + memset( logevents, 0, sizeof(logevents) ); +} + +LogEventsMngr::~LogEventsMngr() { + clearLogEvents(); +} + +int LogEventsMngr::CLogCmp::compareCondition(const char* string){ + if ( logid == parent->logCounter ) + return result; + logid = parent->logCounter; + if ( in ) return result = strstr( string , text.str() ) ? 0 : 1; + return result = strcmp(string,text.str()); +} + +LogEventsMngr::CLogCmp* LogEventsMngr::registerCondition(char* filter){ + char* temp = filter; + // expand "1=message" + while ( isdigit(*filter) ) + ++filter; + bool in = (*filter=='&'); + *filter++ = 0; + int pos = atoi(temp); + if ( pos < 0 || pos >= MAX_LOGARGS) pos = 0; + CLogCmp* c = logcmplist; + while( c ) { + if ( (c->pos==pos) && (c->in==in) && !strcmp(c->text.str(), filter)) + return c; + c = c->next; + } + return logcmplist = new CLogCmp( filter , in , pos , logcmplist,this ); +} + +void LogEventsMngr::CLogEvent::registerFilter( char* filter ){ + CLogCmp *cmp = parent->registerCondition( filter ); + if ( cmp == 0 ) return; + for(LogCond* c = filters; c ; c = c->next){ + if ( c->argnum == cmp->pos ){ + c->list = new LogCondEle( cmp , c->list ); + return; + } + } + LogCondEle* aa = new LogCondEle( cmp , 0 ); + if ( aa == 0 ) return; + filters = new LogCond( cmp->pos , aa , filters ); +} + +void LogEventsMngr::setLogString( char* frmt, va_list& vaptr ) { + ++logCounter; + int len = vsnprintf (logString, 255 , frmt, vaptr ); + if ( len == - 1) { + len = 255; + logString[len] = 0; + } + if ( len ) logString[--len] = 0; + logArgc = 0; +} + +void LogEventsMngr::setLogString( char* frmt, ... ) { + ++logCounter; + va_list logArgPtr; + va_start ( logArgPtr , frmt ); + int len = vsnprintf(logString, 255 , frmt, logArgPtr ); + if ( len == - 1) { + len = 255; + logString[len] = 0; + } + va_end ( logArgPtr ); + if ( len ) logString[--len] = 0; + logArgc = 0; +} + +void LogEventsMngr::parseLogString( ) { + register const char* b = logString; + register int a; + while( *b && logArgc < MAX_LOGARGS ){ + a = 0; + if ( *b == '"' ) { + ++b; + while ( *b && *b != '"' && a < 127 ) + logArgs[logArgc][a++] = *b++; + logArgs[logArgc++][a] = 0; + if ( *b) b+=2; // thanks to double terminator + } + else if ( *b == '(' ) { + ++b; + while ( *b && *b != ')' && a < 127 ) + logArgs[logArgc][a++] = *b++; + logArgs[logArgc++][a] = 0; + if ( *b) b+=2; + } + else { + while ( *b && *b != '(' && *b != '"' && a < 127 ) + logArgs[logArgc][a++] = *b++; + if ( *b ) --a; + logArgs[logArgc++][a] = 0; + } + } +} + +LogEventsMngr::CLogEvent* LogEventsMngr::registerLogEvent( CPluginMngr::CPlugin* plugin, int func, int pos ) +{ + if ( pos < 1 || pos > MAX_LOGARGS) + return 0; + arelogevents = true; + CLogEvent** d = &logevents[pos]; + while(*d) d = &(*d)->next; + return *d = new CLogEvent( plugin , func, this ); +} + +void LogEventsMngr::executeLogEvents() +{ + int err; + bool valid; + for(CLogEvent* a = logevents[ logArgc ]; a ; a = a->next){ + valid = true; + for( CLogEvent::LogCond* b = a->filters; b ; b = b->next){ + valid = false; + for( CLogEvent::LogCondEle* c = b->list; c ; c = c->next) { + if ( c->cmp->compareCondition( logArgs[b->argnum] ) == 0 ){ + valid = true; + break; + } + } + if (!valid) break; + } + +#ifdef ENABLEEXEPTIONS + try + { +#endif + + if (valid){ + if ((err = amx_Exec(a->plugin->getAMX(), NULL , a->func , 0)) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n", + err,a->plugin->getAMX()->curline,a->plugin->getName()); + } + +#ifdef ENABLEEXEPTIONS + } + catch( ... ) + { + print_srvconsole( "[AMX] fatal error at log forward function execution\n"); + } +#endif + + } +} + +void LogEventsMngr::clearLogEvents(){ + logCurrent = logCounter = 0; + arelogevents = false; + for(int i = 0; i < MAX_LOGARGS + 1; ++i){ + CLogEvent **a = &logevents[i]; + while(*a){ + CLogEvent* bb = (*a)->next; + delete *a; + *a = bb; + } + } + clearConditions(); +} + +void LogEventsMngr::clearConditions() { + while (logcmplist){ + CLogCmp* a = logcmplist->next; + delete logcmplist; + logcmplist = a; + } +} + +LogEventsMngr::CLogEvent::LogCond::~LogCond() { + while( list ) { + LogCondEle* cc = list->next; + delete list; + list = cc; + } +} + +LogEventsMngr::CLogEvent::~CLogEvent() { + while( filters ) { + LogCond* cc = filters->next; + delete filters; + filters = cc; + } +} + +LogEventsMngr::CLogEvent *LogEventsMngr::getValidLogEvent( CLogEvent * a ) +{ + bool valid; + while(a){ + valid = true; + for( CLogEvent::LogCond* b = a->filters; b ; b = b->next){ + valid = false; + for( CLogEvent::LogCondEle* c = b->list; c ; c = c->next) { + if ( c->cmp->compareCondition( logArgs[b->argnum] ) == 0 ){ + valid = true; + break; + } + } + if (!valid) break; + } + if (!valid){ + a = a->next; + continue; + } + return a; + } + return 0; +} \ No newline at end of file diff --git a/amxmodx/CLogEvent.h b/amxmodx/CLogEvent.h new file mode 100755 index 00000000..1d9fd5c7 --- /dev/null +++ b/amxmodx/CLogEvent.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef LOGEVENTS_H +#define LOGEVENTS_H + +#define MAX_LOGARGS 12 + +#include + +// ***************************************************** +// class LogEventsMngr +// ***************************************************** + +class LogEventsMngr { + + char logString[256]; + char logArgs[MAX_LOGARGS][128]; + int logArgc; + int logCounter; + int logCurrent; + bool arelogevents; + +public: + class CLogCmp; + class iterator; + class CLogEvent; + + friend class CLogEvent; + friend class CLogCmp; + friend class iterator; + + class CLogCmp + { + friend class LogEventsMngr; + friend class CLogEvent; + LogEventsMngr* parent; + String text; + int logid; + int pos; + int result; + bool in; + CLogCmp *next; + CLogCmp( const char* s, bool r, int p, CLogCmp *n, LogEventsMngr* mg ) : text(s) { + logid = result = 0; + pos = p; + parent = mg; + in = r; + next = n; + } + public: + + int compareCondition(const char* string); + }; + +private: + + CLogCmp *logcmplist; + +public: + + class CLogEvent { + friend class LogEventsMngr; + friend class iterator; + struct LogCondEle { + CLogCmp *cmp; + LogCondEle *next; + LogCondEle(CLogCmp *c, LogCondEle *n): cmp(c) , next(n) { } + }; + struct LogCond { + LogCondEle *list; + int argnum; + LogCond *next; + LogCond( int a , LogCondEle* ee , LogCond* n ) : argnum(a) , list(ee), next(n) {} + ~LogCond(); + }; + CPluginMngr::CPlugin *plugin; + int func; + LogEventsMngr* parent; + LogCond *filters; + CLogEvent *next; + CLogEvent(CPluginMngr::CPlugin *p,int f, LogEventsMngr* ppp) : plugin(p),func(f), filters(0),parent(ppp) ,next(0) { } + ~CLogEvent(); + public: + + void registerFilter( char* filter ); + inline CPluginMngr::CPlugin *getPlugin() { return plugin; } + inline int getFunction() { return func; } + }; + +private: + + CLogEvent *logevents[MAX_LOGARGS+1]; + CLogEvent *getValidLogEvent( CLogEvent * a ); + CLogCmp* registerCondition(char* filter); + void clearConditions(); + +public: + + LogEventsMngr(); + ~LogEventsMngr(); + + // Interface + + + CLogEvent* registerLogEvent( CPluginMngr::CPlugin* plugin, int func, int pos ); + inline bool logEventsExist() { return arelogevents; } + void setLogString( char* frmt, va_list& vaptr ); + void setLogString( char* frmt , ... ); + void parseLogString( ); + void executeLogEvents(); + inline const char* getLogString() { return logString; } + inline int getLogArgNum() { return logArgc; } + inline const char* getLogArg( int i ) { return ( i < 0 || i >= logArgc ) ? "" : logArgs[ i ]; } + void clearLogEvents(); + + + class iterator { + LogEventsMngr* b; + CLogEvent* a; + public: + inline iterator(CLogEvent*aa,LogEventsMngr* bb) : a(aa), b(bb) {} + inline iterator& operator++() { + a = b->getValidLogEvent( a->next ); + return *this; + } + inline bool operator==(const iterator& c) const { return a == c.a; } + inline bool operator!=(const iterator& c) const { return !operator==(c); } + CLogEvent& operator*() { return *a; } + operator bool ( ) const { return a ? true : false; } + }; + inline iterator begin() { return iterator(getValidLogEvent(logevents[ logArgc ]),this); } + inline iterator end() { return iterator(0,this); } +}; + +#endif + + diff --git a/amxmodx/CMenu.cpp b/amxmodx/CMenu.cpp new file mode 100755 index 00000000..5079906e --- /dev/null +++ b/amxmodx/CMenu.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" +#include "CMenu.h" + +// ***************************************************** +// class MenuMngr +// ***************************************************** +MenuMngr::MenuCommand::MenuCommand( CPluginMngr::CPlugin *a, int mi, int k, int f ) { + plugin = a; + keys = k; + menuid = mi; + function = f; + next = 0; +} + +MenuMngr::~MenuMngr() +{ + clear(); +} + +int MenuMngr::findMenuId(const char* name, AMX* amx) +{ + for( MenuIdEle* b = headid; b ; b = b->next) { + if ( (!b->amx || amx == b->amx) && strstr(name,b->name.str()) ) + return b->id; + } + return 0; +} + +int MenuMngr::registerMenuId(const char* n, AMX* a ) +{ + int id = findMenuId( n, a ); + if (id) return id; + headid = new MenuIdEle( n, a , headid ); + return headid->id; +} + +void MenuMngr::registerMenuCmd( CPluginMngr::CPlugin *a,int mi, int k , int f ) +{ + MenuCommand** temp = &headcmd; + while(*temp) temp = &(*temp)->next; + *temp = new MenuCommand(a,mi, k,f); +} + +void MenuMngr::clear() +{ + while (headid) + { + MenuIdEle* a = headid->next; + delete headid; + headid = a; + } + + while (headcmd) + { + MenuCommand* a = headcmd->next; + delete headcmd; + headcmd = a; + } +} + +int MenuMngr::MenuIdEle::uniqueid = 0; \ No newline at end of file diff --git a/amxmodx/CMenu.h b/amxmodx/CMenu.h new file mode 100755 index 00000000..a4574a9e --- /dev/null +++ b/amxmodx/CMenu.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef MENUS_H +#define MENUS_H + +// ***************************************************** +// class MenuMngr +// ***************************************************** + +class MenuMngr +{ + struct MenuIdEle + { + String name; + AMX* amx; + MenuIdEle* next; + int id; + static int uniqueid; + MenuIdEle( const char* n, AMX* a, MenuIdEle* m ) : name( n ) , amx(a) , next( m ) { + id = ++uniqueid; + } + ~MenuIdEle() { --uniqueid; } + } *headid; + +public: + class iterator; + +private: + + class MenuCommand + { + friend class iterator; + friend class MenuMngr; + + CPluginMngr::CPlugin *plugin; + int menuid; + int keys; + int function; + MenuCommand* next; + MenuCommand( CPluginMngr::CPlugin *a, int mi, int k, int f ); + public: + inline int getFunction() { return function; } + inline CPluginMngr::CPlugin* getPlugin() { return plugin; } + inline bool matchCommand( int m, int k ) { return ((m == menuid) && (keys & k)); } + } *headcmd; + +public: + + MenuMngr() { headid = 0; headcmd = 0; } + ~MenuMngr(); + + // Interface + + + int findMenuId(const char* name, AMX* a = 0); + int registerMenuId(const char* n, AMX* a ); + void registerMenuCmd( CPluginMngr::CPlugin *a,int mi, int k , int f ); + void clear(); + + class iterator { + MenuCommand* a; + public: + iterator(MenuCommand*aa) : a(aa) {} + iterator& operator++() { a = a->next; return *this; } + bool operator==(const iterator& b) const { return a == b.a; } + bool operator!=(const iterator& b) const { return !operator==(b); } + operator bool () const { return a ? true : false; } + MenuCommand& operator*() { return *a; } + }; + inline iterator begin() const { return iterator(headcmd); } + inline iterator end() const { return iterator(0); } + + +}; + +#endif + + diff --git a/amxmodx/CMisc.cpp b/amxmodx/CMisc.cpp new file mode 100755 index 00000000..17a87161 --- /dev/null +++ b/amxmodx/CMisc.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" + +// ***************************************************** +// class CPlayer +// ***************************************************** +void CPlayer::Init( edict_t* e , int i ) +{ + index = i; + pEdict = e; + initialized = false; + ingame = false; + bot = false; + authorized = false; + + current = 0; + teamId = -1; + deaths = 0; + aiming = 0; + menu = 0; + keys = 0; + + death_weapon.clear(); + name.clear(); + ip.clear(); + team.clear(); +} + +void CPlayer::Disconnect() { + ingame = false; + initialized = false; + authorized = false; +} +void CPlayer::PutInServer() { + playtime = gpGlobals->time; + ingame = true; +} +bool CPlayer::Connect(const char* connectname,const char* ipaddress) { + name.set(connectname); + ip.set(ipaddress); + time = gpGlobals->time; + bot = IsBot(); + death_killer = 0; + memset(flags,0,sizeof(flags)); + memset(weapons,0,sizeof(weapons)); + initialized = true; + authorized = false; + + const char* authid = GETPLAYERAUTHID( pEdict ); + + if ( (authid == 0) || (*authid == 0) + || (strcmp( authid , "STEAM_ID_PENDING") == 0) ) + return true; + + return false; +} + + + +// ***************************************************** +// class Grenades +// ***************************************************** +void Grenades::put( edict_t* grenade, float time, int type, CPlayer* player ) +{ + Obj* a = new Obj; + if ( a == 0 ) return; + a->player = player; + a->grenade = grenade; + a->time = gpGlobals->time + time; + a->type = type; + a->next = head; + head = a; +} + +bool Grenades::find( edict_t* enemy, CPlayer** p, int& type ) +{ + bool found = false; + Obj** a = &head; + while ( *a ){ + if ( (*a)->time > gpGlobals->time ) { + if ( (*a)->grenade == enemy ) { + found = true; + (*p) = (*a)->player; + type = (*a)->type; + } + } + else { + Obj* b = (*a)->next; + delete *a; + *a = b; + continue; + + } + a = &(*a)->next; + } + return found; +} + +void Grenades::clear() +{ + while(head){ + Obj* a = head->next; + delete head; + head = a; + } +} + +// ***************************************************** +// class XVars +// ***************************************************** +void XVars::clear() { + delete[] head; + head = 0; + num = 0; + size = 0; +} + +int XVars::put( AMX* p, cell* v ) +{ + for(int a = 0; a < num; ++a) { + if ( (head[a].amx == p) && (head[a].value == v) ) + return a; + } + + if ( (num >= size) && realloc_array( size ? (size * 2) : 8 ) ) + return -1; + + head[num].value = v; + head[num].amx = p; + return num++; +} + +int XVars::realloc_array( int nsize ) +{ + XVarEle* me = new XVarEle[nsize]; + if ( me ){ + for(int a = 0 ; a < num; ++a) + me[a] = head[a]; + delete[] head; + head = me; + size = nsize; + return 0; + } + return 1; +} + +// ***************************************************** +// class TeamIds +// ***************************************************** +TeamIds::TeamIds() { head = 0; newTeam = 0; } +TeamIds::~TeamIds() { + while( head ) { + TeamEle* a = head->next; + delete head; + head = a; + } +} + +void TeamIds::registerTeam( const char* n ,int s ) +{ + TeamEle** a = &head; + while( *a ){ + if ( strcmp((*a)->name.str(),n) == 0 ){ + if (s != -1){ + (*a)->id = s; + newTeam &= ~(1<<(*a)->tid); + } + return; + } + a = &(*a)->next; + } + *a = new TeamEle( n , s ); + if ( *a == 0 ) return; + newTeam |= (1<<(*a)->tid); +} + +int TeamIds::findTeamId( const char* n ) +{ + TeamEle* a = head; + while( a ){ + if ( !strcmpi(a->name.str(),n) ) + return a->id; + a = a->next; + } + return -1; +} + +int TeamIds::findTeamIdCase( const char* n) +{ + TeamEle* a = head; + while( a ){ + if ( !strcmp(a->name.str(), n) ) + return a->id; + a = a->next; + } + return -1; +} + +char TeamIds::TeamEle::uid = 0; + diff --git a/amxmodx/CMisc.h b/amxmodx/CMisc.h new file mode 100755 index 00000000..23a1390e --- /dev/null +++ b/amxmodx/CMisc.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef CMISC_H +#define CMISC_H + +#include "CList.h" +#include "string.h" + +// ***************************************************** +// class CCVar +// ***************************************************** +class CCVar +{ + cvar_t cvar; + String name; + String plugin; +public: + CCVar( const char* pname, const char* pplugin, + int pflags, float pvalue ) : name(pname) , plugin(pplugin ) { + cvar.name = (char*)name.str(); + cvar.flags = pflags; + cvar.string = ""; + cvar.value = pvalue; + } + inline cvar_t* getCvar() { return &cvar; } + inline const char* getPluginName() { return plugin.str(); } + inline const char* getName() { return name.str(); } + inline bool operator == ( const char* string ) const { return (strcmp(name.str(),string)==0); } +}; + + + +// ***************************************************** +// class CPlayer +// ***************************************************** + +class CPlayer +{ + +public: + edict_t* pEdict; + + String name; + String ip; + String team; + + bool initialized; + bool ingame; + bool bot; + bool authorized; + + float time; + float playtime; + + struct { + int ammo; + int clip; + } weapons[MAX_WEAPONS]; + + int current; + int teamId; + int deaths; + int aiming; + int menu; + int keys; + int index; + int flags[32]; + + int death_headshot; + int death_killer; + int death_victim; + bool death_tk; + String death_weapon; + + Vector lastTrace; + Vector thisTrace; + Vector lastHit; + + void Init( edict_t* e , int i ); + void Disconnect(); + void PutInServer(); + bool Connect(const char* connectname,const char* ipaddress); + + inline bool IsBot(){ + const char* auth= (*g_engfuncs.pfnGetPlayerAuthId)(pEdict); + return ( auth && !strcmp( auth , "BOT" ) ); + } + + inline bool IsAlive(){ + return ((pEdict->v.deadflag==DEAD_NO)&&(pEdict->v.health>0)); + } + + inline void Authorize() { authorized = true; } + +}; + +// ***************************************************** +// class Grenades +// ***************************************************** + +class Grenades +{ + struct Obj + { + CPlayer* player; + edict_t* grenade; + float time; + int type; + Obj* next; + } *head; + + +public: + Grenades() { head = 0; } + ~Grenades() { clear(); } + void put( edict_t* grenade, float time, int type, CPlayer* player ); + bool find( edict_t* enemy, CPlayer** p, int& type ); + void clear(); +}; + +// ***************************************************** +// class ForceObject +// ***************************************************** +class ForceObject { + AMX* amx; + String filename; + FORCE_TYPE type; + Vector mins; + Vector maxs; +public: + ForceObject(const char* n, FORCE_TYPE c,Vector& mi, Vector& ma, AMX* a) : + filename(n) , type(c), mins(mi), maxs(ma), amx(a) {} + inline const char* getFilename() { return filename.str(); } + inline AMX* getAMX() { return amx; } + Vector& getMin() { return mins; } + Vector& getMax() { return maxs; } + inline FORCE_TYPE getForceType() { return type; } +}; + +// ***************************************************** +// class XVars +// ***************************************************** + +class XVars +{ + struct XVarEle { + AMX* amx; + cell* value; + }; + + XVarEle* head; + int size; + int num; + + int realloc_array( int nsize ); + +public: + XVars() { num = 0; size = 0; head = 0; } + ~XVars() { clear(); } + void clear(); + int put( AMX* a, cell* v ); + inline cell getValue( int a ) { + return ( a >= 0 && a < num ) ? *(head[a].value) : 0; + } + inline int setValue( int a, cell v ) { + if ( a >= 0 && a < num ){ + *(head[a].value) = v; + return 0; + } + return 1; + } +}; + +// ***************************************************** +// class CScript +// ***************************************************** +class CScript +{ + String filename; + AMX* amx; + void* code; +public: + CScript(AMX* aa, void* cc,const char* ff):filename(ff),amx(aa),code(cc){} + inline AMX* getAMX() { return amx; } + inline const char* getName() { return filename.str(); } + inline bool operator==( void* a ) { return (amx == (AMX*)a); } + inline void* getCode() { return code; } +}; + +// ***************************************************** +// class TeamIds +// ***************************************************** +class TeamIds +{ + struct TeamEle { + String name; + int id; + char tid; + static char uid; + TeamEle* next; + TeamEle(const char* n, int& i) : name(n) , id(i) , next(0) { + tid = uid++; + }; + ~TeamEle(){ --uid; } + } *head; + + int newTeam; + +public: + TeamIds(); + ~TeamIds(); + void registerTeam( const char* n ,int s ); + int findTeamId( const char* n); + int findTeamIdCase( const char* n); + inline bool isNewTeam() { return newTeam ? true : false; } +}; + + + +#endif + + + diff --git a/amxmodx/CModule.cpp b/amxmodx/CModule.cpp new file mode 100755 index 00000000..9dc8eb5c --- /dev/null +++ b/amxmodx/CModule.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" + +typedef int (FAR *QUERYMOD)(module_info_s**); +typedef int (FAR *ATTACHMOD)(pfnamx_engine_g*,pfnmodule_engine_g*); +typedef int (FAR *DETACHMOD)(void); + +QUERYMOD QueryModule; +ATTACHMOD AttachModule; +DETACHMOD DetachModule; + + + +pfnamx_engine_g engAmxFunc = { + amx_Align16, + amx_Align32, + amx_Allot, + amx_Callback, + amx_Clone, + amx_Debug, + amx_Exec, + amx_Execv, + amx_FindPublic, + amx_FindPubVar, + amx_FindTagId, + amx_Flags, + amx_GetAddr, + amx_GetPublic, + amx_GetPubVar, + amx_GetString, + amx_GetTag, + amx_GetUserData, + amx_Init, + amx_InitJIT, + amx_MemInfo, + amx_NameLength, + amx_NativeInfo, + amx_NumPublics, + amx_NumPubVars, + amx_NumTags, + amx_RaiseError, + amx_Register, + amx_Release, + amx_SetCallback, + amx_SetDebugHook, + amx_SetString, + amx_SetUserData, + amx_StrLen, +}; + +pfnmodule_engine_g engModuleFunc = { + add_amxnatives, + build_pathname, + copy_amxmemory, + format_amxstring, + get_amxaddr, + get_amxscript, + get_amxscriptname, + get_amxstring, + get_modname, + load_amxscript, + print_srvconsole, + report_error, + set_amxnatives, + set_amxstring, + amxstring_len, + unload_amxscript, + alloc_amxmemory, + free_amxmemory, +}; + +// ***************************************************** +// class CModule +// ***************************************************** + +CModule::CModule(const char* fname) : filename(fname) +{ + metamod = false; + info = 0; + module = 0; + status = MODULE_NONE; +} +CModule::~CModule() +{ + if ( module ) DLFREE(module); + natives.clear(); +} +bool CModule::attachModule() +{ + if ( status != MODULE_QUERY ) + return false; + AttachModule = (ATTACHMOD)DLPROC(module,"AMX_Attach"); + if ( AttachModule ) (*AttachModule)(&engAmxFunc,&engModuleFunc); + status = MODULE_LOADED; + return true; +} +bool CModule::queryModule() +{ + if ( status != MODULE_NONE ) // don't check if already quried + return false; + module = DLLOAD( filename.str() ); // link dll + if ( !module ){ + status = MODULE_BADLOAD; + return false; + } + int meta = (int)DLPROC(module,"Meta_Attach"); // check if also MM + if ( meta ) metamod = true; + + QueryModule = (QUERYMOD)DLPROC(module,"AMX_Query"); // check what version + if (QueryModule == 0) { + status = MODULE_NOQUERY; + return false; + } + (*QueryModule)( &info ); + if ( info == 0 ){ + status = MODULE_NOINFO; + return false; + } + if ( info->ivers != AMX_INTERFACE_VERSION ) { + status = MODULE_OLD; + return false; + } + AttachModule = (ATTACHMOD)DLPROC(module,"AMX_Attach"); // check for attach + if ( AttachModule == 0) { + status = MODULE_NOATTACH; + return false; + } + info->serial = (long int)this; + status = MODULE_QUERY; + return true; +} +bool CModule::detachModule() +{ + if ( status != MODULE_LOADED ) + return false; + DetachModule = (DETACHMOD)DLPROC(module,"AMX_Detach"); + if (DetachModule) (*DetachModule)(); + DLFREE(module); + module = 0; + natives.clear(); + status = MODULE_NONE; + return true; +} +const char* CModule::getStatus() const { + switch(status){ + case MODULE_NONE: return "error"; + case MODULE_QUERY: return "pending"; + case MODULE_BADLOAD:return "bad load"; + case MODULE_LOADED:return "running"; + case MODULE_NOINFO:return "no info"; + case MODULE_NOQUERY:return "no query"; + case MODULE_NOATTACH:return "no attach"; + case MODULE_OLD:return "old"; + } + return "unknown"; +} diff --git a/amxmodx/CModule.h b/amxmodx/CModule.h new file mode 100755 index 00000000..26aec4bb --- /dev/null +++ b/amxmodx/CModule.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +// ***************************************************** +// class CModule +// ***************************************************** + +#ifndef CMODULE_H +#define CMODULE_H + +enum MODULE_STATUS { + MODULE_NONE, + MODULE_QUERY, + MODULE_BADLOAD, + MODULE_LOADED, + MODULE_NOINFO, + MODULE_NOQUERY, + MODULE_NOATTACH, + MODULE_OLD +}; + +class CModule +{ + String filename; + bool metamod; + module_info_s* info; + DLHANDLE module; + MODULE_STATUS status; + +public: + + CModule(const char* fname); + ~CModule(); + + // Interface + bool attachModule(); + bool queryModule(); + bool detachModule(); + const char* getStatus() const; + inline const char* getType() const { return metamod ? "amx&mm" : "amx"; } + inline const char* getAuthor() const { return info ? info->author : "unknown"; } + inline const char* getVersion() const { return info ? info->version : "unknown"; } + inline const char* getName() const { return info ? info->name : "unknown"; } + inline module_info_s* getInfo() const { return info; } + inline int getStatusValue() { return status; } + inline bool operator==( void* fname ) { return !strcmp( filename.str() , (char*)fname ); } + inline bool isReloadable() { return ( (status==MODULE_LOADED) && (info->type==RELOAD_MODULE)); } + CList natives; +}; + + + +#endif + + + diff --git a/amxmodx/COPYING b/amxmodx/COPYING new file mode 100755 index 00000000..5b6e7c66 --- /dev/null +++ b/amxmodx/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/amxmodx/CPlugin.cpp b/amxmodx/CPlugin.cpp new file mode 100755 index 00000000..81d4366e --- /dev/null +++ b/amxmodx/CPlugin.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" +#include "CPlugin.h" +#include "CForward.h" +#include "CFile.h" + +CPluginMngr::CPlugin* CPluginMngr::loadPlugin(const char* path, const char* name, char* error) { + CPlugin** a = &head; + while( *a ) a = &(*a)->next; + *a = new CPlugin( pCounter++ ,path,name,error); + return *error ? 0 : *a; +} + +void CPluginMngr::unloadPlugin( CPlugin** a ) { + CPlugin* next = (*a)->next; + delete *a; + *a = next; + --pCounter; +} + +int CPluginMngr::loadPluginsFromFile( const char* filename ) +{ + File fp( build_pathname("%s",filename) , "r" ); + + if ( !fp ) + { + print_srvconsole( "[AMX] Plugins list not found (file \"%s\")\n",filename); + return 1; + } + + // Find now folder + char pluginName[256], line[256], error[256], pluginsDir[256]; + strcpy(pluginsDir,filename); + char* ptrEnd = pluginsDir; + for (int i = 0; pluginsDir[i];++i ) { + if (pluginsDir[i] == '/' || pluginsDir[i] == '\\') + ptrEnd = &pluginsDir[i]; + } + *ptrEnd = 0; + + + while ( fp.getline(line , 255 ) ) + { + *pluginName = 0; + sscanf(line,"%s",pluginName); + if (!isalnum(*pluginName)) continue; + + CPlugin* plugin = loadPlugin( pluginsDir , pluginName , error ); + + if ( plugin != 0 ) // load_amxscript fills it with info in case of error + { + AMX* amx = plugin->getAMX(); + int iFunc; + + if(amx_FindPublic(amx, "client_command" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_ClientCommand); + if(amx_FindPublic(amx, "client_connect" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_ClientConnect); + if(amx_FindPublic(amx, "client_disconnect" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_ClientDisconnect); + if(amx_FindPublic(amx, "client_infochanged" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_ClientInfoChanged); + if(amx_FindPublic(amx, "client_putinserver" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_ClientPutInServer); + if(amx_FindPublic(amx, "plugin_init" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_PluginInit); + if(amx_FindPublic(amx, "plugin_cfg" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_PluginCfg); + if(amx_FindPublic(amx, "plugin_precache" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_PluginPrecache); + if(amx_FindPublic(amx, "plugin_log" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_PluginLog); + if(amx_FindPublic(amx, "plugin_end" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_PluginEnd); + if(amx_FindPublic(amx, "inconsistent_file" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_InconsistentFile); + if(amx_FindPublic(amx, "client_authorized" , &iFunc) == AMX_ERR_NONE) + g_forwards.registerForward( plugin , iFunc , FF_ClientAuthorized); + } + else + { + print_srvconsole("[AMX] %s (plugin \"%s\")\n", error, pluginName ); + } + } + + return pCounter; +} + +void CPluginMngr::clear() { + CPlugin**a = &head; + while ( *a ) + unloadPlugin(a); +} + +CPluginMngr::CPlugin* CPluginMngr::findPluginFast(AMX *amx) +{ + return (CPlugin*)(amx->userdata[3]); + /*CPlugin*a = head; + while ( a && &a->amx != amx ) + a=a->next; + return a;*/ +} + +CPluginMngr::CPlugin* CPluginMngr::findPlugin(AMX *amx) { + CPlugin*a = head; + while ( a && &a->amx != amx ) + a=a->next; + return a; +} + +CPluginMngr::CPlugin* CPluginMngr::findPlugin(int index){ + CPlugin*a = head; + while ( a && index--) + a=a->next; + return a; +} + +CPluginMngr::CPlugin* CPluginMngr::findPlugin(const char* name) { + if (!name) return 0; + int len = strlen(name); + if (!len) return 0; + CPlugin*a = head; + while( a && strncmp(a->name.str(), name,len) ) + a=a->next; + return a; +} + +const char* CPluginMngr::CPlugin::getStatus() const { + switch(status){ + case ps_running: return "running"; + case ps_paused: return "paused"; + case ps_bad_load: return "bad load"; + case ps_stopped: return "stopped"; + case ps_locked: return "locked"; + } + return "error"; +} + +CPluginMngr::CPlugin::CPlugin(int i, const char* p,const char* n, char* e) : name(n), title(n) { + const char* unk = "unknown"; + title.set(unk); + author.set(unk); + version.set(unk); + char* path = build_pathname("%s/%s",p,n); + code = 0; + int err = load_amxscript(&amx,&code,path,e ); + if ( err == AMX_ERR_NONE ) status = ps_running; + else status = ps_bad_load; + amx.userdata[3] = this; + paused_fun = 0; + next = 0; + id = i; +} +CPluginMngr::CPlugin::~CPlugin( ){ + unload_amxscript( &amx, &code ); +} + +void CPluginMngr::CPlugin::pauseFunction( int id ) { + if (isValid()){ + paused_fun |= (1<next; return *this; } + bool operator==(const iterator& b) const { return a == b.a; } + bool operator!=(const iterator& b) const { return !operator==(b); } + operator bool () const { return a ? true : false; } + CPlugin& operator*() { return *a; } + }; + inline iterator begin() const { return iterator(head); } + inline iterator end() const { return iterator(0); } +}; + +#endif + + diff --git a/amxmodx/CString.cpp b/amxmodx/CString.cpp new file mode 100755 index 00000000..54119c7f --- /dev/null +++ b/amxmodx/CString.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "CString.h" +#include "string.h" +#include "CFile.h" + +String::String() +{ + len = 0; + napis = 0; +} + +String::String( const char* n ) +{ + napis = 0; + set(n); +} + +String::~String() +{ + clear(); +} + +void String::set( const char* n ) +{ + clear(); + if ( n != 0 ){ + len = strlen( n ); + napis = new char[ len + 1 ]; + if ( napis ) strcpy( napis , n ); + else len = 0; + } +} + +void String::clear() { + delete[] napis; + napis = 0; + len = 0; +} + diff --git a/amxmodx/CString.h b/amxmodx/CString.h new file mode 100755 index 00000000..0adba151 --- /dev/null +++ b/amxmodx/CString.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef STRING_CUSTOM_H +#define STRING_CUSTOM_H + +// ***************************************************** +// class String +// ***************************************************** + +class String +{ + char* napis; + short int len; + +public: + String(); + String( const char* n ); + ~String(); + void set( const char* n ); + inline bool empty() const { return (len == 0); } + inline const char* str() const { return napis ? napis : "(null)"; } + inline short int size() const { return len; } + void clear(); +}; + +#endif + + + diff --git a/amxmodx/CTask.cpp b/amxmodx/CTask.cpp new file mode 100755 index 00000000..61c45256 --- /dev/null +++ b/amxmodx/CTask.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" +#include "CTask.h" + + +CTaskMngr::CTask::CTask( CPluginMngr::CPlugin* p, int f, int flags, + int i, float base, float exec, int parlen , + const cell* par, int r){ + plugin = p; + func = f; + id = i; + next = 0; + prev = 0; + param_len = 0; + param = 0; + base_time = base; + exec_time = exec; + repeat = (flags & 1) ? r : 0; + loop = (flags & 2) ? true : false; + afterstart = (flags & 4) ? true : false; + beforeend = (flags & 8) ? true : false; + + if ( parlen ) + { + param = new cell[ parlen + 1 ]; + + if ( param ){ + param_len = parlen + 1; + memcpy( param , par , sizeof( cell ) * parlen ); + param[ parlen ] = 0; + } + } +} + +CTaskMngr::CTask* CTaskMngr::getFirstValidTask(CTask* h){ + CTask* a = h; + while( a ) { + if ( a->isRemoved() ) { + CTask* b = a->next; + unlink( a ); + delete a; + a = b; + continue; + } + else if ( a->afterstart ){ + if ( *m_timer - *m_timeleft + 1 < a->base_time ) { + a = a->next; + continue; + } + } + else if ( a->beforeend ){ + if ( *m_timelimit == 0 ){ + a = a->next; + continue; + } + if ( (*m_timeleft + *m_timelimit * 60.0) - *m_timer - 1 > + a->base_time ){ + a = a->next; + continue; + } + } + else if ( a->exec_time > *m_timer ) { + a = a->next; + continue; + } + return a; + } + return 0; +} + +CTaskMngr::CTask* CTaskMngr::getNextTask(CTask* a) { + if ( a->isRemoved() ) + return a->next; + if ( a->loop || a->isToReply() ){ + a->exec_time = *m_timer + a->base_time; + return a->next; + } + a->setToRemove(); + return a->next; +} + + +CTaskMngr::CTaskMngr() { + head = 0; + tail = 0; + m_timer = 0; + m_timelimit = 0; + m_timeleft = 0; +} + +CTaskMngr::~CTaskMngr() { + clear(); +} + +void CTaskMngr::clear() { + while ( head ) { + tail = head->next; + delete head; + head = tail; + } +} + +void CTaskMngr::registerTimers( float* timer , float* timelimit, float* timeleft ) { + m_timer = timer; + m_timelimit = timelimit; + m_timeleft = timeleft; +} + +void CTaskMngr::registerTask( CPluginMngr::CPlugin* plugin, int func, + int flags, int i, float base, float exec, + int parlen , const cell* par, int repeat ){ + + CTask* a = new CTask(plugin,func,flags,i,base,exec,parlen,par,repeat ); + + if ( a == 0 ) return; + + if ( tail ) + { + tail->next = a; + a->prev = tail; + tail = a; + } + else { + head = a; + tail = a; + } +} + +CTaskMngr::CTask* CTaskMngr::findTask( int id , AMX* amx ) +{ + for (CTask* a = head; a ; a = a->next) + { + if ( !a->isRemoved() && (a->getTaskId() == id) && (!amx || + (a->getPlugin()->getAMX() == amx)) ) + return a; + } + + return 0; +} + +void CTaskMngr::unlink(CTask* a){ + if ( a->prev ) a->prev->next = a->next; + else head = a->next; + if ( a->next ) a->next->prev = a->prev; + else tail = a->prev; +} + +int CTaskMngr::removeTasks( int id , AMX* amx ) +{ + CTask* a; + int i = 0; + + while ( (a = findTask(id, amx )) != 0 ) { + a->setToRemove(); + ++i; + } + + return i; +} + diff --git a/amxmodx/CTask.h b/amxmodx/CTask.h new file mode 100755 index 00000000..b8864cc3 --- /dev/null +++ b/amxmodx/CTask.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef CTASK_H +#define CTASK_H + +// ***************************************************** +// class CTaskMngr +// ***************************************************** + +class CTaskMngr +{ +public: + + class iterator; + + class CTask + { + + friend class iterator; + friend class CTaskMngr; + + CPluginMngr::CPlugin* plugin; + int id; + int func; + int repeat; + bool loop; + bool afterstart; + bool beforeend; + float base_time; + float exec_time; + int param_len; + cell* param; + CTask* next; + CTask* prev; + inline void setToRemove() { exec_time = -1.0f; } + inline bool isToReply() { return (repeat-- > 0); } + inline bool isRemoved() { return (exec_time == -1.0f); } + CTask( CPluginMngr::CPlugin* p, int f, int flags, int i, + float base, float exec, int parlen , const cell* par, int r ); + ~CTask() { if ( param_len ) delete[] param; } + + public: + + inline int getParamLen() { return param_len; } + inline int getTaskId() { return id; } + inline int getFunction() { return func; } + cell* getParam() { return param; } + CPluginMngr::CPlugin* getPlugin() { return plugin; } + }; + + + +private: + + friend class iterator; + CTask *head; + CTask *tail; + float* m_timer; + float* m_timelimit; + float* m_timeleft; + CTask* getFirstValidTask(CTask* a); + CTask* getNextTask(CTask* a); + CTask* findTask( int id , AMX* amx ); + void unlink(CTask* a); + +public: + + CTaskMngr(); + ~CTaskMngr(); + + // Interface + + + void registerTimers( float* timer , float* timelimit, float* timeleft ); + void registerTask( CPluginMngr::CPlugin* plugin, int func, int flags, int i, float base, float exec, int parlen , const cell* par, int repeat ); + inline int taskExists( int id ,AMX* amx) { return findTask(id,amx ) ? 1 : 0; } + int removeTasks( int id , AMX* amx ); + void clear(); + + class iterator { + CTaskMngr* b; + CTask* a; + public: + iterator(CTask*aa,CTaskMngr* bb) : a(aa), b(bb) {} + iterator& operator++() { + a = b->getNextTask( a ); + a = b->getFirstValidTask( a ); + return *this; + } + CTask& operator*() { return *a; } + operator bool ( ) const { return a ? true : false; } + }; + inline iterator begin() { return iterator(getFirstValidTask(head),this); } + +}; + +#endif + + diff --git a/amxmodx/CVault.cpp b/amxmodx/CVault.cpp new file mode 100755 index 00000000..fd4a9a3d --- /dev/null +++ b/amxmodx/CVault.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "CVault.h" +#include "CFile.h" +#include +#include +#include + +// ***************************************************** +// class Vault +// ***************************************************** +bool Vault::exists( const char* k ) +{ + if ( *k == 0 ) return false; + + return *find( k ) != 0; +} + +void Vault::put( const char* k, const char* v ) +{ + if ( *k == 0 ) return; + + if ( *v == 0 ) + { + remove( k ); + return; + } + + Obj** a = find( k ); + + if ( *a ) + { + (*a)->value.set(v); + (*a)->number = atoi( v ); + } + else + *a = new Obj( k , v ); + +} + +Vault::Obj::Obj( const char* k, const char* v): key(k) , value(v) , next(0) { + number = atoi(v); +} + +Vault::Obj** Vault::find( const char* n ) +{ + Obj** a = &head; + + while( *a ) + { + if ( strcmp((*a)->key.str(), n) == 0 ) + return a; + + a = &(*a)->next; + } + + return a; +} + + +int Vault::get_number( const char* n ) +{ + if ( *n == 0 ) return 0; + + Obj* b = *find( n ); + + if ( b == 0 ) return 0; + + return b->number; +} + +const char* Vault::get( const char* n ) +{ + if ( *n == 0 ) return ""; + + Obj* b = *find( n ); + + if ( b == 0 ) return ""; + + return b->value.str(); +} + +void Vault::clear() +{ + while ( head ) + { + Obj* a = head->next; + delete head; + head = a; + } +} + +void Vault::remove( const char* n ) +{ + Obj** b = find( n ); + + if ( *b == 0 ) return; + + Obj* a = (*b)->next; + delete *b; + *b = a; +} + +void Vault::setSource( const char* n ) +{ + path.set(n); +} + + +bool Vault::loadVault( ) +{ + if ( path.empty() ) return false; + + clear(); + + File a( path.str() , "r" ); + + if ( !a ) return false; + + const int sz = 512; + char value[sz+1]; + char key[sz+1]; + + while ( a >> key && a.skipWs() && a.getline( value , sz ) ) + { + if ( isalpha ( *key ) ) + put( key, value ); + } + + return true; + +} + +bool Vault::saveVault( ) +{ + if ( path.empty() ) return false; + + File a( path.str() , "w" ); + + if ( !a ) return false; + + a << "; Don't modify!" << '\n'; + + for (Obj* b = head; b ;b = b->next) + a << b->key << '\t' << b->value << '\n'; + + return true; +} diff --git a/amxmodx/CVault.h b/amxmodx/CVault.h new file mode 100755 index 00000000..7f744bc6 --- /dev/null +++ b/amxmodx/CVault.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef VAULT_CUSTOM_H +#define VAULT_CUSTOM_H + +#include "CString.h" +#include "CList.h" + +// ***************************************************** +// class Vault +// ***************************************************** + +class Vault +{ + struct Obj + { + String key; + String value; + int number; + Obj *next; + Obj( const char* k, const char* v); + } *head; + + String path; + + Obj** find( const char* n ); + +public: + + Vault() {head=0;} + ~Vault() { clear();} + + // Interface + + bool exists( const char* k ); + void put(const char* k, const char* v); + void remove( const char* k ); + const char* get( const char* n ); + int get_number( const char* n ); + void setSource( const char* n ); + bool loadVault( ); + bool saveVault( ); + void clear(); + + + class iterator { + Obj * a; + public: + iterator(Obj*aa) : a(aa) {} + iterator& operator++() { if ( a ) a = a->next; return *this; } + bool operator==(const iterator& b) const { return a == b.a; } + bool operator!=(const iterator& b) const { return !operator==(b); } + String& key() const { return a->key; } + String& value() const { return a->value; } + }; + + inline iterator begin() const { return iterator(head); } + inline iterator end() const { return iterator(0); } +}; + +#endif + + + diff --git a/amxmodx/Makefile b/amxmodx/Makefile new file mode 100755 index 00000000..e9f4561a --- /dev/null +++ b/amxmodx/Makefile @@ -0,0 +1,116 @@ +MODNAME = amx_mm +SRCFILES = meta_api.cpp CFile.cpp CString.cpp CVault.cpp vault.cpp\ +float.cpp file.cpp modules.cpp CMisc.cpp CTask.cpp string.cpp\ +amxmod.cpp CEvent.cpp CCmd.cpp CLogEvent.cpp srvcmd.cpp strptime.cpp\ +CForward.cpp CPlugin.cpp CModule.cpp CMenu.cpp emsg.cpp util.cpp +CSRCFILES = amx.c amxcore.c amxtime.c power.c + +EXTRA_LIBS_LINUX = +EXTRA_LIBS_WIN32 = +EXTRA_LIBDIRS_LINUX = -Lextra/lib_linux +EXTRA_LIBDIRS_WIN32 = -Lextra/lib_win32 + +EXTRA_INCLUDEDIRS = -Iextra/include + +EXTRA_FLAGS = -Dstrcmpi=strcasecmp + +SDKTOP=../hlsdk +METADIR=../metamod/metamod + + +SDKSRC=$(SDKTOP)/SourceCode +OBJDIR_LINUX=obj.linux +OBJDIR_WIN32=obj.win32 +SRCDIR=. + +ifdef windir + OS=WIN32 +else + OS=LINUX +endif + +CC_LINUX=gcc +ifeq "$(OS)" "WIN32" + CC_WIN32=gcc + LD_WINDLL=dllwrap + DEFAULT=win32 + CLEAN=clean_win32 +else + CC_WIN32=/usr/local/cross-tools/i386-mingw32msvc/bin/gcc + LD_WINDLL=/usr/local/cross-tools/bin/i386-mingw32msvc-dllwrap + DEFAULT=linux win32 + CLEAN=clean_both +endif + + + +LIBFILE_LINUX = $(MODNAME)_i386.so +LIBFILE_WIN32 = $(MODNAME).dll +TARGET_LINUX = $(OBJDIR_LINUX)/$(LIBFILE_LINUX) +TARGET_WIN32 = $(OBJDIR_WIN32)/$(LIBFILE_WIN32) + +FILES_ALL = *.cpp *.h [A-Z]* *.rc +ifeq "$(OS)" "LINUX" + ASRCFILES := $(shell ls -t $(SRCFILES)) +else + ASRCFILES := $(shell dir /b) +endif +OBJ_LINUX := $(SRCFILES:%.cpp=$(OBJDIR_LINUX)/%.o) +OBJC_LINUX := $(CSRCFILES:%.c=$(OBJDIR_LINUX)/%.o) +OBJ_WIN32 := $(SRCFILES:%.cpp=$(OBJDIR_WIN32)/%.o) +OBJC_WIN32 := $(CSRCFILES:%.c=$(OBJDIR_WIN32)/%.o) + + +CCOPT = -march=i586 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \ + -malign-jumps=2 -malign-functions=2 -s -DNDEBUG + +INCLUDEDIRS=-I../curl/include -I$(SRCDIR) -I$(METADIR) -I$(SDKSRC)/engine -I$(SDKSRC)/common -I$(SDKSRC)/pm_shared -I$(SDKSRC)/dlls -I$(SDKSRC) $(EXTRA_INCLUDEDIRS) +CFLAGS=-Wall -Wno-unknown-pragmas +ODEF = -DOPT_TYPE=\"optimized\" +CFLAGS:=$(CCOPT) $(CFLAGS) $(ODEF) $(EXTRA_FLAGS) + +DO_CC_LINUX=$(CC_LINUX) $(CFLAGS) -fPIC $(INCLUDEDIRS) -o $@ -c $< +DO_CC_WIN32=$(CC_WIN32) $(CFLAGS) $(INCLUDEDIRS) -o $@ -c $< +LINK_LINUX=$(CC_LINUX) $(CFLAGS) -shared -ldl -lm $(OBJ_LINUX) $(OBJC_LINUX) $(EXTRA_LIBDIRS_LINUX) $(EXTRA_LIBS_LINUX) -o $@ +LINK_WIN32=$(LD_WINDLL) -mwindows --def $(MODNAME).def --add-stdcall-alias $(OBJ_WIN32) $(OBJC_WIN32) $(EXTRA_LIBDIRS_WIN32) $(EXTRA_LIBS_WIN32) -o $@ + +$(OBJDIR_LINUX)/%.o: $(SRCDIR)/%.c + $(DO_CC_LINUX) + +$(OBJDIR_LINUX)/%.o: $(SRCDIR)/%.cpp + $(DO_CC_LINUX) + +$(OBJDIR_WIN32)/%.o: $(SRCDIR)/%.c + $(DO_CC_WIN32) + +$(OBJDIR_WIN32)/%.o: $(SRCDIR)/%.cpp + $(DO_CC_WIN32) + +default: $(DEFAULT) + +$(TARGET_LINUX): $(OBJDIR_LINUX) $(OBJ_LINUX) $(OBJC_LINUX) + $(LINK_LINUX) + +$(TARGET_WIN32): $(OBJDIR_WIN32) $(OBJ_WIN32) $(OBJC_WIN32) + $(LINK_WIN32) + +$(OBJDIR_LINUX): + mkdir $@ + +$(OBJDIR_WIN32): + mkdir $@ + +win32: $(TARGET_WIN32) + +linux: $(TARGET_LINUX) + +clean: $(CLEAN) + +clean_both: + -rm -f $(OBJDIR_LINUX)/* + -rm -f $(OBJDIR_WIN32)/* + +clean_win32: + del /q $(OBJDIR_WIN32) + diff --git a/amxmodx/amx.c b/amxmodx/amx.c new file mode 100755 index 00000000..eb6f4b19 --- /dev/null +++ b/amxmodx/amx.c @@ -0,0 +1,3208 @@ +/* Abstract Machine for the Small compiler + * + * Copyright (c) ITB CompuPhase, 1997-2002 + * This file may be freely used. No warranties of any kind. + * + * Version: $Id$ + */ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#if defined __linux__ + #include +#endif +#if defined JIT + #include +#endif +#include "osdefs.h" +#include "amx.h" + +//#if !defined __linux__ /* Linux GCC already has these types */ +typedef unsigned char u_char; +//#endif + +typedef enum { + OP_NONE, /* invalid opcode */ + OP_LOAD_PRI, + OP_LOAD_ALT, + OP_LOAD_S_PRI, + OP_LOAD_S_ALT, + OP_LREF_PRI, + OP_LREF_ALT, + OP_LREF_S_PRI, + OP_LREF_S_ALT, + OP_LOAD_I, + OP_LODB_I, + OP_CONST_PRI, + OP_CONST_ALT, + OP_ADDR_PRI, + OP_ADDR_ALT, + OP_STOR_PRI, + OP_STOR_ALT, + OP_STOR_S_PRI, + OP_STOR_S_ALT, + OP_SREF_PRI, + OP_SREF_ALT, + OP_SREF_S_PRI, + OP_SREF_S_ALT, + OP_STOR_I, + OP_STRB_I, + OP_LIDX, + OP_LIDX_B, + OP_IDXADDR, + OP_IDXADDR_B, + OP_ALIGN_PRI, + OP_ALIGN_ALT, + OP_LCTRL, + OP_SCTRL, + OP_MOVE_PRI, + OP_MOVE_ALT, + OP_XCHG, + OP_PUSH_PRI, + OP_PUSH_ALT, + OP_PUSH_R, + OP_PUSH_C, + OP_PUSH, + OP_PUSH_S, + OP_POP_PRI, + OP_POP_ALT, + OP_STACK, + OP_HEAP, + OP_PROC, + OP_RET, + OP_RETN, + OP_CALL, + OP_CALL_PRI, + OP_JUMP, + OP_JREL, + OP_JZER, + OP_JNZ, + OP_JEQ, + OP_JNEQ, + OP_JLESS, + OP_JLEQ, + OP_JGRTR, + OP_JGEQ, + OP_JSLESS, + OP_JSLEQ, + OP_JSGRTR, + OP_JSGEQ, + OP_SHL, + OP_SHR, + OP_SSHR, + OP_SHL_C_PRI, + OP_SHL_C_ALT, + OP_SHR_C_PRI, + OP_SHR_C_ALT, + OP_SMUL, + OP_SDIV, + OP_SDIV_ALT, + OP_UMUL, + OP_UDIV, + OP_UDIV_ALT, + OP_ADD, + OP_SUB, + OP_SUB_ALT, + OP_AND, + OP_OR, + OP_XOR, + OP_NOT, + OP_NEG, + OP_INVERT, + OP_ADD_C, + OP_SMUL_C, + OP_ZERO_PRI, + OP_ZERO_ALT, + OP_ZERO, + OP_ZERO_S, + OP_SIGN_PRI, + OP_SIGN_ALT, + OP_EQ, + OP_NEQ, + OP_LESS, + OP_LEQ, + OP_GRTR, + OP_GEQ, + OP_SLESS, + OP_SLEQ, + OP_SGRTR, + OP_SGEQ, + OP_EQ_C_PRI, + OP_EQ_C_ALT, + OP_INC_PRI, + OP_INC_ALT, + OP_INC, + OP_INC_S, + OP_INC_I, + OP_DEC_PRI, + OP_DEC_ALT, + OP_DEC, + OP_DEC_S, + OP_DEC_I, + OP_MOVS, + OP_CMPS, + OP_FILL, + OP_HALT, + OP_BOUNDS, + OP_SYSREQ_PRI, + OP_SYSREQ_C, + OP_FILE, + OP_LINE, + OP_SYMBOL, + OP_SRANGE, + OP_JUMP_PRI, + OP_SWITCH, + OP_CASETBL, + OP_SWAP_PRI, + OP_SWAP_ALT, + OP_PUSHADDR, +//OP_CALLN, + OP_NOP, + /* ----- */ + OP_NUM_OPCODES +} OPCODE; + +#define NUMENTRIES(hdr,field,nextfield) (int)(((hdr).nextfield - (hdr).field)/sizeof(AMX_FUNCSTUB)) + +static int amx_LittleEndian = -1; /* set to TRUE for Little Endian, and + * to FALSE for Big Endian */ + +static void init_little_endian(void) +{ + if (amx_LittleEndian < 0) { /* initialize this variable only once */ + uint16_t val=0x00ff; + u_char *ptr=(u_char *)&val; + + /* "ptr" points to the starting address of "val". If that address + * holds the byte "0xff", the computer stored the low byte of "val" + * at the lower address, and so the memory lay out is Little Endian. + */ + assert(*ptr==0xff || *ptr==0x00); + amx_LittleEndian= *ptr==0xff; + } /* if */ +} + +static void swap16(uint16_t *v) +{ + unsigned char *s = (unsigned char *)v; + unsigned char t; + + assert(sizeof(*v)==2); + /* swap two bytes */ + t=s[0]; + s[0]=s[1]; + s[1]=t; +} + +static void swap32(uint32_t *v) +{ + unsigned char *s = (unsigned char *)v; + unsigned char t; + + assert(sizeof(*v)==4); + /* swap outer two bytes */ + t=s[0]; + s[0]=s[3]; + s[3]=t; + /* swap inner two bytes */ + t=s[1]; + s[1]=s[2]; + s[2]=t; +} + +uint16_t *amx_Align16(uint16_t *v) +{ + assert(sizeof(*v)==2); + init_little_endian(); + if (!amx_LittleEndian) + swap16(v); + return v; +} + +uint32_t *amx_Align32(uint32_t *v) +{ + assert(sizeof(cell)==4); + init_little_endian(); + if (!amx_LittleEndian) + swap32(v); + return v; +} + +#if defined BIT16 + #define swapcell swap16 +#else + #define swapcell swap32 +#endif + +int AMXAPI amx_Flags(AMX *amx,uint16_t *flags) +{ + AMX_HEADER *hdr; + + *flags=0; + if (amx==NULL) + return AMX_ERR_FORMAT; + hdr=(AMX_HEADER *)amx->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionflags; + return AMX_ERR_NONE; +} + +int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + AMX_FUNCSTUB *func=(AMX_FUNCSTUB *)(amx->base+(int)hdr->natives+(int)index*sizeof(AMX_FUNCSTUB)); + AMX_NATIVE f=(AMX_NATIVE)func->address; + assert(f!=NULL); + assert(hdr->natives<=hdr->libraries); + assert(index<(cell)NUMENTRIES(*hdr,natives,libraries)); + + /* Note: + * params[0] == number of parameters passed to the native function + * params[1] == first argument + * etc. + */ + + amx->error=AMX_ERR_NONE; + *result = f(amx,params); + return amx->error; +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +int AMXAPI amx_Debug(AMX *amx) +{ + return AMX_ERR_DEBUG; +} + +#if defined JIT + extern int AMXAPI getMaxCodeSize(void); + extern int AMXAPI asm_runJIT(void *sourceAMXbase, void *jumparray, void *compiledAMXbase); +#endif + +#if defined BIT16 + #define JUMPABS(base,ip) ((cell *)(base+*ip)) + #define RELOC_ABS(base, off) + #define RELOC_VALUE(base, v) +#else + #define JUMPABS(base, ip) ((cell *)*ip) + #define RELOC_ABS(base, off) *(ucell *)(base+(int)off) += (ucell)base + #define RELOC_VALUE(base, v) ((v)+((ucell)(base))) +#endif + +#define DBGPARAM(v) ( (v)=*(cell *)(code+(int)cip), cip+=sizeof(cell) ) + +static int amx_BrowseRelocate(AMX *amx) +{ + AMX_HEADER *hdr; + u_char *code; + cell cip; + long codesize; + OPCODE op; + int debug; + int last_sym_global = 0; + #if defined __GNUC__ || defined ASM32 || defined JIT + ucell **opcode_list; + #endif + #if defined JIT + int opcode_count = 0; + int reloc_count = 0; + #endif + + + hdr=(AMX_HEADER *)amx->base; + code=amx->base+(int)hdr->cod; + codesize=hdr->dat - hdr->cod; + + /* sanity checks */ + assert(OP_PUSH_PRI==36); + assert(OP_PROC==46); + assert(OP_SHL==65); + assert(OP_SMUL==72); + assert(OP_EQ==95); + assert(OP_INC_PRI==107); + assert(OP_MOVS==117); + assert(OP_SYMBOL==126); + + /* check the debug hook */ + amx->dbgcode=DBG_INIT; + assert(amx->flags==0); + amx->flags=AMX_FLAG_BROWSE; + debug= amx->debug(amx)==AMX_ERR_NONE; + if (debug) + amx->flags=AMX_FLAG_DEBUG | AMX_FLAG_BROWSE; + + #if defined __GNUC__ || defined ASM32 || defined JIT + amx_Exec(NULL, (cell *)&opcode_list, 0, 0); + #endif + + /* start browsing code */ + for (cip=0; cip0 && op=256) + return AMX_ERR_INVINSTR; + #if defined __GNUC__ || defined ASM32 || defined JIT + /* relocate symbol */ + *(ucell **)(code+(int)cip) = opcode_list[op]; + #endif + #if defined JIT + opcode_count++; + #endif + cip+=sizeof(cell); + switch (op) { + case OP_LOAD_PRI: /* instructions with 1 parameter */ + case OP_LOAD_ALT: + case OP_LOAD_S_PRI: + case OP_LOAD_S_ALT: + case OP_LREF_PRI: + case OP_LREF_ALT: + case OP_LREF_S_PRI: + case OP_LREF_S_ALT: + case OP_LODB_I: + case OP_CONST_PRI: + case OP_CONST_ALT: + case OP_ADDR_PRI: + case OP_ADDR_ALT: + case OP_STOR_PRI: + case OP_STOR_ALT: + case OP_STOR_S_PRI: + case OP_STOR_S_ALT: + case OP_SREF_PRI: + case OP_SREF_ALT: + case OP_SREF_S_PRI: + case OP_SREF_S_ALT: + case OP_STRB_I: + case OP_LIDX_B: + case OP_IDXADDR_B: + case OP_ALIGN_PRI: + case OP_ALIGN_ALT: + case OP_LCTRL: + case OP_SCTRL: + case OP_PUSH_R: + case OP_PUSH_C: + case OP_PUSH: + case OP_PUSH_S: + case OP_STACK: + case OP_HEAP: + case OP_JREL: + case OP_SHL_C_PRI: + case OP_SHL_C_ALT: + case OP_SHR_C_PRI: + case OP_SHR_C_ALT: + case OP_ADD_C: + case OP_SMUL_C: + case OP_ZERO: + case OP_ZERO_S: + case OP_EQ_C_PRI: + case OP_EQ_C_ALT: + case OP_INC: + case OP_INC_S: + case OP_DEC: + case OP_DEC_S: + case OP_MOVS: + case OP_CMPS: + case OP_FILL: + case OP_HALT: + case OP_BOUNDS: + case OP_SYSREQ_C: + case OP_PUSHADDR: + cip+=sizeof(cell); + break; + + case OP_LOAD_I: /* instructions without parameters */ + case OP_STOR_I: + case OP_LIDX: + case OP_IDXADDR: + case OP_MOVE_PRI: + case OP_MOVE_ALT: + case OP_XCHG: + case OP_PUSH_PRI: + case OP_PUSH_ALT: + case OP_POP_PRI: + case OP_POP_ALT: + case OP_PROC: + case OP_RET: + case OP_RETN: + case OP_CALL_PRI: + case OP_SHL: + case OP_SHR: + case OP_SSHR: + case OP_SMUL: + case OP_SDIV: + case OP_SDIV_ALT: + case OP_UMUL: + case OP_UDIV: + case OP_UDIV_ALT: + case OP_ADD: + case OP_SUB: + case OP_SUB_ALT: + case OP_AND: + case OP_OR: + case OP_XOR: + case OP_NOT: + case OP_NEG: + case OP_INVERT: + case OP_ZERO_PRI: + case OP_ZERO_ALT: + case OP_SIGN_PRI: + case OP_SIGN_ALT: + case OP_EQ: + case OP_NEQ: + case OP_LESS: + case OP_LEQ: + case OP_GRTR: + case OP_GEQ: + case OP_SLESS: + case OP_SLEQ: + case OP_SGRTR: + case OP_SGEQ: + case OP_INC_PRI: + case OP_INC_ALT: + case OP_INC_I: + case OP_DEC_PRI: + case OP_DEC_ALT: + case OP_DEC_I: + case OP_SYSREQ_PRI: + case OP_JUMP_PRI: + case OP_SWAP_PRI: + case OP_SWAP_ALT: + case OP_NOP: + break; + + case OP_CALL: /* opcodes that need relocation */ + case OP_JUMP: + case OP_JZER: + case OP_JNZ: + case OP_JEQ: + case OP_JNEQ: + case OP_JLESS: + case OP_JLEQ: + case OP_JGRTR: + case OP_JGEQ: + case OP_JSLESS: + case OP_JSLEQ: + case OP_JSGRTR: + case OP_JSGEQ: + case OP_SWITCH: + #if defined JIT + reloc_count++; + #endif + RELOC_ABS(code, cip); + cip+=sizeof(cell); + break; + +// case OP_CALLN: +// #if defined JIT +// reloc_count++; +// #endif +// RELOC_ABS(code, cip); +// cip+=2*sizeof(cell); +// break; + + case OP_FILE: { + cell num; + DBGPARAM(num); + DBGPARAM(amx->curfile); + amx->dbgname=(char *)(code+(int)cip); + cip+=num - sizeof(cell); + if (debug) { + assert(amx->flags==(AMX_FLAG_DEBUG | AMX_FLAG_BROWSE)); + amx->dbgcode=DBG_FILE; + amx->debug(amx); + } /* if */ + break; + } /* case */ + case OP_LINE: + DBGPARAM(amx->curline); + DBGPARAM(amx->curfile); + if (debug) { + assert(amx->flags==(AMX_FLAG_DEBUG | AMX_FLAG_BROWSE)); + amx->dbgcode=DBG_LINE; + amx->debug(amx); + } /* if */ + break; + case OP_SYMBOL: { + cell num; + DBGPARAM(num); + DBGPARAM(amx->dbgaddr); + DBGPARAM(amx->dbgparam); + amx->dbgname=(char *)(code+(int)cip); + cip+=num - 2*sizeof(cell); + last_sym_global = (amx->dbgparam >> 8)==0; + if (debug && last_sym_global) { /* do global symbols only */ + assert(amx->flags==(AMX_FLAG_DEBUG | AMX_FLAG_BROWSE)); + amx->dbgcode=DBG_SYMBOL; + amx->debug(amx); + } /* if */ + break; + } /* case */ + case OP_SRANGE: + DBGPARAM(amx->dbgaddr); /* dimension level */ + DBGPARAM(amx->dbgparam); /* length */ + if (debug && last_sym_global) { /* do global symbols only */ + assert(amx->flags==(AMX_FLAG_DEBUG | AMX_FLAG_BROWSE)); + amx->dbgcode=DBG_SRANGE; + amx->debug(amx); + } /* if */ + break; + case OP_CASETBL: { + cell num; + int i; + DBGPARAM(num); /* number of records follows the opcode */ + for (i=0; i<=num; i++) { + RELOC_ABS(code, cip+2*i*sizeof(cell)); + #if defined JIT + reloc_count++; + #endif + } /* for */ + cip+=(2*num + 1)*sizeof(cell); + break; + } /* case */ + default: + return AMX_ERR_INVINSTR; + } /* switch */ + } /* for */ + + #if defined JIT + amx->code_size = getMaxCodeSize()*opcode_count + hdr->cod + + (hdr->stp - hdr->dat); + amx->reloc_size = 2*sizeof(cell)*reloc_count; + #endif + + amx->flags |= AMX_FLAG_RELOC; + return AMX_ERR_NONE; +} + +static void expand(unsigned char *code, long codesize, long memsize) +{ +#define SPARESIZE 32 + ucell c; + struct { + long memloc; + ucell c; + } spare[SPARESIZE]; + int sh=0,st=0,sc=0; + int shift; + + /* for in-place expansion, move from the end backward */ + assert(memsize % sizeof(cell) == 0); + while (codesize>0) { + c=0; + shift=0; + do { + codesize--; + /* no input byte should be shifted out completely */ + assert(shift<8*sizeof(cell)); + /* we work from the end of a sequence backwards; the final code in + * a sequence may not have the continuation bit set */ + assert(shift>0 || (code[(size_t)codesize] & 0x80)==0); + c|=(ucell)(code[(size_t)codesize] & 0x7f) << shift; + shift+=7; + } while (codesize>0 && (code[(size_t)codesize-1] & 0x80)!=0); + /* sign expand */ + if ((code[(size_t)codesize] & 0x40)!=0) { + while (shift < 8*sizeof(cell)) { + c|=(ucell)0xff << shift; + shift+=8; + } /* while */ + } /* if */ + /* store */ + while (sc&&(spare[sh].memloc>codesize)) { + *(ucell *)(code+(int)spare[sh].memloc)=spare[sh].c; + sh=(sh+1)%SPARESIZE; + sc--; + } /* while */ + memsize -= sizeof(cell); + assert(memsize>=0); + if ((memsize>codesize)||((memsize==codesize)&&(memsize==0))) { + *(ucell *)(code+(size_t)memsize)=c; + } else { + assert(scsize); + amx_Align16(&hdr->magic); + amx_Align16((uint16_t*)&hdr->flags); + amx_Align16((uint16_t*)&hdr->defsize); + amx_Align32((uint32_t*)&hdr->cod); + amx_Align32((uint32_t*)&hdr->dat); + amx_Align32((uint32_t*)&hdr->hea); + amx_Align32((uint32_t*)&hdr->stp); + amx_Align32((uint32_t*)&hdr->cip); + amx_Align32((uint32_t*)&hdr->publics); + amx_Align32((uint32_t*)&hdr->natives); + amx_Align32((uint32_t*)&hdr->libraries); + amx_Align32((uint32_t*)&hdr->pubvars); + amx_Align32((uint32_t*)&hdr->tags); + } /* if */ + + if (hdr->magic!=AMX_MAGIC || hdr->defsize!=sizeof(AMX_FUNCSTUB)) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionstp<=0) + return AMX_ERR_FORMAT; + if ((hdr->flags & AMX_FLAG_CHAR16)!=0) + return AMX_ERR_FORMAT; /* 16-bit characters currently not supported */ + if (!amx_LittleEndian && (hdr->flags & AMX_FLAG_COMPACT)==0) + return AMX_ERR_FORMAT; /* On Big Endian machines, use compact encoding */ + assert((hdr->flags & AMX_FLAG_COMPACT)!=0 || hdr->hea == hdr->size); + if ((hdr->flags & AMX_FLAG_COMPACT)!=0) + expand((unsigned char *)program+(int)hdr->cod, + hdr->size - hdr->cod, hdr->hea - hdr->cod); + + amx->base=(unsigned char *)program; + + /* Set a zero cell at the top of the stack, which functions + * as a sentinel for strings. + */ + * (cell *)(amx->base+(int)hdr->stp-sizeof(cell)) = 0; + + /* set initial values */ + amx->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ + amx->stp=hdr->stp - hdr->dat - sizeof(cell); + amx->hea=amx->hlw; + amx->stk=amx->stp; + if (amx->callback==NULL) + amx->callback=amx_Callback; + if (amx->debug==NULL) + amx->debug=amx_Debug; + amx->curline=0; + amx->curfile=0; + amx->data=NULL; + + /* also align all addresses in the public function, public variable and + * public tag tables + */ + if (!amx_LittleEndian) { + AMX_FUNCSTUB *fs; + int i,num; + + fs=(AMX_FUNCSTUB *)(amx->base + (int)hdr->publics); + assert(hdr->publics<=hdr->natives); + num=NUMENTRIES(*hdr,publics,natives); + for (i=0; iaddress); + fs++; + } /* for */ + + fs=(AMX_FUNCSTUB *)(amx->base + (int)hdr->pubvars); + assert(hdr->pubvars<=hdr->tags); + num=NUMENTRIES(*hdr,pubvars,tags); + for (i=0; iaddress); + fs++; + } /* for */ + + fs=(AMX_FUNCSTUB *)(amx->base + (int)hdr->tags); + assert(hdr->tags<=hdr->cod); + num=NUMENTRIES(*hdr,tags,cod); + for (i=0; iaddress); + fs++; + } /* for */ + } /* if */ + + /* relocate call and jump instructions, optionally gather debug information */ + amx_BrowseRelocate(amx); + + return AMX_ERR_NONE; +} + +int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data) +{ + AMX_HEADER *hdr; + u_char FAR *dataSource; + + if (amxSource==NULL) + return AMX_ERR_FORMAT; + if (amxClone==NULL) + return AMX_ERR_PARAMS; + hdr=(AMX_HEADER *)amxSource->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionbase=amxSource->base; + amxClone->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ + amxClone->stp=hdr->stp - hdr->dat - sizeof(cell); + amxClone->hea=amxClone->hlw; + amxClone->stk=amxClone->stp; + if (amxClone->callback==NULL) + amxClone->callback=amxSource->callback; + if (amxClone->debug==NULL) + amxClone->debug=amxSource->debug; + amxClone->curline=0; + amxClone->curfile=0; + + /* copy the data segment; the stack and the heap can be left uninitialized */ + assert(data!=NULL); + amxClone->data=(u_char FAR *)data; + dataSource=(amxSource->data!=NULL) ? amxSource->data : amxSource->base+(int)hdr->dat; + memcpy(amxClone->data,dataSource,(size_t)(hdr->hea-hdr->dat)); + + /* Set a zero cell at the top of the stack, which functions + * as a sentinel for strings. + */ + * (cell *)(amxClone->data+(int)amxClone->stp) = 0; + + return AMX_ERR_NONE; +} + +int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap) +{ + AMX_HEADER *hdr; + + if (amx==NULL) + return AMX_ERR_FORMAT; + hdr=(AMX_HEADER *)amx->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versiondat-hdr->cod; + if (datasize!=NULL) + *datasize=hdr->hea-hdr->dat; + if (stackheap!=NULL) + *stackheap=hdr->stp-hdr->hea; + + return AMX_ERR_NONE; +} + +#if defined JIT + +#if defined __WIN32__ /* this also applies to Win32 "console" applications */ + +int memoryFullAccess( void* addr, int len ) +{ + DWORD op; + + if ( VirtualProtect( addr, len, PAGE_EXECUTE_READWRITE, &op ) ) + return op; + return 0; +} + +int memorySetAccess( void* addr, int len, int access ) +{ + DWORD op; + + if ( access == 0 ) + return 0; + return VirtualProtect( addr, len, access, &op ); +} + +#else /* #if defined __WIN32 __ */ + +// TODO: Add cases for Linux, Unix, OS/2, ... + +// DOS32 has no imposed limits on its segments. +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +int memoryFullAccess( void* addr, int len ) { return 1; } + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +int memorySetAccess( void* addr, int len, int access ) { return 1; } + +#endif /* #if defined __WIN32 __ */ + +int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code) +{ + int mac, res; + AMX_HEADER *hdr; + + mac = memoryFullAccess( asm_runJIT, 20000 ); + if ( ! mac ) + return AMX_ERR_INIT_JIT; + + /* copy the prefix */ + memcpy( native_code, amx->base, ((AMX_HEADER *)(amx->base))->cod ); + hdr = (AMX_HEADER*)native_code; + + /* JIT rulz! (TM) */ + /* MP: added check for correct compilation */ + res = asm_runJIT( amx->base, reloc_table, native_code ); + if ( res != 0 ) + { + memorySetAccess( asm_runJIT, 20000, mac ); + return AMX_ERR_INIT_JIT; + } + + /* update the required memory size (the previous value was a + * conservative estimate, now we know the exact size) + */ + amx->code_size = (hdr->dat + hdr->stp + 3) & ~3; + /* The compiled code is relocatable, since only relative jumps are + * used for destinations within the generated code and absoulute + * addresses for jumps into the runtime, which is fixed in memory. + */ + amx->base = (unsigned char*) native_code; + amx->cip = hdr->cip; + amx->hea = hdr->hea; + amx->stp = hdr->stp - sizeof(cell); + /* also put a sentinel for strings at the top the stack */ + *(cell *)((char*)native_code + hdr->dat + hdr->stp - sizeof(cell)) = 0; + amx->stk = amx->stp; + + memorySetAccess( asm_runJIT, 20000, mac ); + return AMX_ERR_NONE; +} + +#else /* #if defined JIT */ + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +int AMXAPI amx_InitJIT(AMX *amx,void *compiled_program,void *reloc_table) +{ + return AMX_ERR_INIT_JIT; +} + +#endif /* #if defined JIT */ + +int AMXAPI amx_NameLength(AMX *amx, int *length) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + *length=hdr->defsize - sizeof(uint32_t); + return AMX_ERR_NONE; +} + +int AMXAPI amx_NumPublics(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->publics<=hdr->natives); + *number=NUMENTRIES(*hdr,publics,natives); + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->publics<=hdr->natives); + if (index>=(cell)NUMENTRIES(*hdr,publics,natives)) + return AMX_ERR_INDEX; + + func=(AMX_FUNCSTUB *)(amx->base+(int)hdr->publics+index*sizeof(AMX_FUNCSTUB)); + strcpy(funcname,func->name); + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindPublic(AMX *amx, char *name, int *index) +{ + int first,last,mid,result; + char pname[sEXPMAX+1]; + + amx_NumPublics(amx, &last); + last--; /* last valid index is 1 less than the number of functions */ + first=0; + /* binary search */ + while (first<=last) { + mid=(first+last)/2; + amx_GetPublic(amx, mid, pname); + result=strcmp(pname,name); + if (result>0) { + last=mid-1; + } else if (result<0) { + first=mid+1; + } else { + *index=mid; + return AMX_ERR_NONE; + } /* if */ + } /* while */ + /* not found, set to an invalid index, so amx_Exec() will fail */ + *index=INT_MAX; + return AMX_ERR_NOTFOUND; +} + +int AMXAPI amx_NumPubVars(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->pubvars<=hdr->tags); + *number=NUMENTRIES(*hdr,pubvars,tags); + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *var; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->pubvars<=hdr->tags); + if (index>=(cell)NUMENTRIES(*hdr,pubvars,tags)) + return AMX_ERR_INDEX; + + var=(AMX_FUNCSTUB *)(amx->base+(int)hdr->pubvars+index*sizeof(AMX_FUNCSTUB)); + strcpy(varname,var->name); + *amx_addr=var->address; + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindPubVar(AMX *amx, char *varname, cell *amx_addr) +{ + int first,last,mid,result; + char pname[sEXPMAX+1]; + cell paddr; + + amx_NumPubVars(amx, &last); + last--; /* last valid index is 1 less than the number of functions */ + first=0; + /* binary search */ + while (first<=last) { + mid=(first+last)/2; + amx_GetPubVar(amx, mid, pname, &paddr); + result=strcmp(pname,varname); + if (result>0) { + last=mid-1; + } else if (result<0) { + first=mid+1; + } else { + *amx_addr=paddr; + return AMX_ERR_NONE; + } /* if */ + } /* while */ + /* not found */ + *amx_addr=0; + return AMX_ERR_NOTFOUND; +} + +int AMXAPI amx_NumTags(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + if (hdr->file_version<5) { /* the tagname table appeared in file format 5 */ + *number=0; + return AMX_ERR_VERSION; + } /* if */ + assert(hdr->tags<=hdr->cod); + *number=NUMENTRIES(*hdr,tags,cod); + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *tag; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + if (hdr->file_version<5) { /* the tagname table appeared in file format 5 */ + *tagname='\0'; + *tag_id=0; + return AMX_ERR_VERSION; + } /* if */ + + assert(hdr->tags<=hdr->cod); + if (index>=(cell)NUMENTRIES(*hdr,tags,cod)) + return AMX_ERR_INDEX; + + tag=(AMX_FUNCSTUB *)(amx->base+(int)hdr->tags+index*sizeof(AMX_FUNCSTUB)); + strcpy(tagname,tag->name); + *tag_id=tag->address; + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname) +{ + int first,last,mid; + cell mid_id; + + #if !defined NDEBUG + /* verify that the tagname table is sorted on the tag_id */ + amx_NumTags(amx, &last); + if (last>0) { + cell cur_id; + amx_GetTag(amx,0,tagname,&cur_id); + for (first=1; firsttag_id) + last=mid-1; + else if (mid_idusertags[index]!=tag; index++) + /* nothing */; + if (index>=AMX_USERNUM) + return AMX_ERR_USERDATA; + *ptr=amx->userdata[index]; + return AMX_ERR_NONE; +} + +int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr) +{ + int index; + + assert(amx!=NULL); + assert(tag!=0); + /* try to find existing tag */ + for (index=0; indexusertags[index]!=tag; index++) + /* nothing */; + /* if not found, try to find empty tag */ + if (index>=AMX_USERNUM) + for (index=0; indexusertags[index]!=0; index++) + /* nothing */; + /* if still not found, quit with error */ + if (index>=AMX_USERNUM) + return AMX_ERR_INDEX; + /* set the tag and the value */ + amx->usertags[index]=tag; + amx->userdata[index]=ptr; + return AMX_ERR_NONE; +} + +static AMX_NATIVE findfunction(char *name, AMX_NATIVE_INFO *list, int number) +{ + int i; + + assert(list!=NULL); + for (i=0; list[i].name!=NULL && (ibase; + assert(hdr!=NULL); + assert(hdr->natives<=hdr->libraries); + numnatives=NUMENTRIES(*hdr,natives,libraries); + + err=AMX_ERR_NONE; + func=(AMX_FUNCSTUB *)(amx->base+(int)hdr->natives); + for (i=0; iaddress==0) { + /* this function is not yet located */ + funcptr=(list!=NULL) ? findfunction(func->name,list,number) : NULL; + if (funcptr!=NULL) + func->address=(uint32_t)funcptr; + else + { + err=AMX_ERR_NOTFOUND; + no_function = func->name; + } + } /* if */ + func++; + } /* for */ + return err; +} + +AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(char *name,AMX_NATIVE func) +{ + static AMX_NATIVE_INFO n; + n.name=name; + n.func=func; + return &n; +} + +#define GETPARAM(v) ( v=*(cell *)cip++ ) +#define PUSH(v) ( stk-=sizeof(cell), *(cell *)(data+(int)stk)=v ) +#define POP(v) ( v=*(cell *)(data+(int)stk), stk+=sizeof(cell) ) +#define ABORT(amx,v) { (amx)->stk=reset_stk; (amx)->hea=reset_hea; return v; } + +#define STKMARGIN ((cell)(16*sizeof(cell))) +#define CHKMARGIN() if (hea+STKMARGIN>stk) return AMX_ERR_STACKERR +#define CHKSTACK() if (stk>amx->stp) return AMX_ERR_STACKLOW +#define CHKHEAP() if (heahlw) return AMX_ERR_HEAPLOW + +#if defined __GNUC__ + /* GNU C version uses the "labels as values" extension to create + * fast "indirect threaded" interpreter. + */ + +#define NEXT(cip) goto **cip++ + +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) +{ +static void *labels[] = { + &&op_none, &&op_load_pri, &&op_load_alt, &&op_load_s_pri, + &&op_load_s_alt,&&op_lref_pri, &&op_lref_alt, &&op_lref_s_pri, + &&op_lref_s_alt,&&op_load_i, &&op_lodb_i, &&op_const_pri, + &&op_const_alt, &&op_addr_pri, &&op_addr_alt, &&op_stor_pri, + &&op_stor_alt, &&op_stor_s_pri,&&op_stor_s_alt,&&op_sref_pri, + &&op_sref_alt, &&op_sref_s_pri,&&op_sref_s_alt,&&op_stor_i, + &&op_strb_i, &&op_lidx, &&op_lidx_b, &&op_idxaddr, + &&op_idxaddr_b, &&op_align_pri, &&op_align_alt, &&op_lctrl, + &&op_sctrl, &&op_move_pri, &&op_move_alt, &&op_xchg, + &&op_push_pri, &&op_push_alt, &&op_push_r, &&op_push_c, + &&op_push, &&op_push_s, &&op_pop_pri, &&op_pop_alt, + &&op_stack, &&op_heap, &&op_proc, &&op_ret, + &&op_retn, &&op_call, &&op_call_pri, &&op_jump, + &&op_jrel, &&op_jzer, &&op_jnz, &&op_jeq, + &&op_jneq, &&op_jless, &&op_jleq, &&op_jgrtr, + &&op_jgeq, &&op_jsless, &&op_jsleq, &&op_jsgrtr, + &&op_jsgeq, &&op_shl, &&op_shr, &&op_sshr, + &&op_shl_c_pri, &&op_shl_c_alt, &&op_shr_c_pri, &&op_shr_c_alt, + &&op_smul, &&op_sdiv, &&op_sdiv_alt, &&op_umul, + &&op_udiv, &&op_udiv_alt, &&op_add, &&op_sub, + &&op_sub_alt, &&op_and, &&op_or, &&op_xor, + &&op_not, &&op_neg, &&op_invert, &&op_add_c, + &&op_smul_c, &&op_zero_pri, &&op_zero_alt, &&op_zero, + &&op_zero_s, &&op_sign_pri, &&op_sign_alt, &&op_eq, + &&op_neq, &&op_less, &&op_leq, &&op_grtr, + &&op_geq, &&op_sless, &&op_sleq, &&op_sgrtr, + &&op_sgeq, &&op_eq_c_pri, &&op_eq_c_alt, &&op_inc_pri, + &&op_inc_alt, &&op_inc, &&op_inc_s, &&op_inc_i, + &&op_dec_pri, &&op_dec_alt, &&op_dec, &&op_dec_s, + &&op_dec_i, &&op_movs, &&op_cmps, &&op_fill, + &&op_halt, &&op_bounds, &&op_sysreq_pri,&&op_sysreq_c, + &&op_file, &&op_line, &&op_symbol, &&op_srange, + &&op_jump_pri, &&op_switch, &&op_casetbl, &&op_swap_pri, + &&op_swap_alt, &&op_pushaddr, &&op_nop /*, &&op_calln*/ }; + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + u_char *code, *data; + cell pri,alt,stk,frm,hea; + cell reset_stk, reset_hea, *cip; + cell offs; + int num,i; + va_list ap; + //int debug; + + /* HACK: return label table (for amx_BrowseRelocate) if amx structure + * is not passed. + */ + if (amx==NULL) { + assert(sizeof(cell)==sizeof(void *)); + assert(retval!=NULL); + *retval=(cell)labels; + return 0; + } /* if */ + + if (amx->callback==NULL) + return AMX_ERR_CALLBACK; + /*i=amx_Register(amx,NULL,0); // verify that all natives are registered + if (i!=AMX_ERR_NONE) + return i;*/ + + amx->flags &= ~AMX_FLAG_BROWSE; + //if ((amx->flags & AMX_FLAG_RELOC)==0) + // return AMX_ERR_INIT; + //debug= (amx->flags & AMX_FLAG_DEBUG)!=0; + + /* set up the registers */ + hdr=(AMX_HEADER *)amx->base; + code=amx->base+(int)hdr->cod; + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + hea=amx->hea; + stk=amx->stk; + reset_stk=stk; + reset_hea=hea; + frm=0; /* just to avoid compiler warnings */ + + /* get the start address */ + /*if (index==AMX_EXEC_MAIN) { + if (hdr->cip<0) + return AMX_ERR_INDEX; + cip=(cell *)(code + (int)hdr->cip); + } else if (index==AMX_EXEC_CONT) { + // all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea + frm=amx->frm; + stk=amx->stk; + hea=amx->hea; + pri=amx->pri; + alt=amx->alt; + reset_stk=amx->reset_stk; + reset_hea=amx->reset_hea; + cip=(cell *)(code + (int)amx->cip); + } else if (index<0) { + return AMX_ERR_INDEX; + } else { + if (index>=NUMENTRIES(*hdr,publics,natives)) + return AMX_ERR_INDEX;*/ + func=(AMX_FUNCSTUB *)(amx->base + (int)hdr->publics + index*sizeof(AMX_FUNCSTUB)); + cip=(cell *)(code + (int)func->address); + //} /* if */ + /* check values just copied */ + CHKSTACK(); + CHKHEAP(); + + //if (debug && index!=AMX_EXEC_CONT) { + /* set the entry point in the debugger by marking a "call" to the + * exported function + */ + // amx->dbgcode=DBG_CALL; + // amx->dbgaddr=(ucell)((u_char*)cip-code); + // amx->debug(amx); + //} /* if */ + + /* sanity checks */ + /*assert(OP_PUSH_PRI==36); + assert(OP_PROC==46); + assert(OP_SHL==65); + assert(OP_SMUL==72); + assert(OP_EQ==95); + assert(OP_INC_PRI==107); + assert(OP_MOVS==117); + assert(OP_SYMBOL==126); + assert(sizeof(cell)==4);*/ + + //if (index!=AMX_EXEC_CONT) { + /* push the parameters to the stack (in reverse order) */ + if (numparams & 0xFFFF0000) { + cell *params; + stk-=(numparams>>=16)*sizeof(cell); + va_start(ap,numparams); + params = va_arg(ap,cell*); + va_end(ap); + for (i=0; i=hea && pri=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)pri); + NEXT(cip); + op_lodb_i: + GETPARAM(offs); + /* verify address */ + if (pri>=hea && pri=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch (offs) { + case 1: + pri= * (data+(int)pri); + break; + case 2: + pri= * (uint16_t *)(data+(int)pri); + break; + case 4: + pri= * (uint32_t *)(data+(int)pri); + break; + } /* switch */ + NEXT(cip); + op_const_pri: + GETPARAM(pri); + NEXT(cip); + op_const_alt: + GETPARAM(alt); + NEXT(cip); + op_addr_pri: + GETPARAM(pri); + pri+=frm; + NEXT(cip); + op_addr_alt: + GETPARAM(alt); + alt+=frm; + NEXT(cip); + op_stor_pri: + GETPARAM(offs); + *(cell *)(data+(int)offs)=pri; + NEXT(cip); + op_stor_alt: + GETPARAM(offs); + *(cell *)(data+(int)offs)=alt; + NEXT(cip); + op_stor_s_pri: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=pri; + NEXT(cip); + op_stor_s_alt: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=alt; + NEXT(cip); + op_sref_pri: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + *(cell *)(data+(int)offs)=pri; + NEXT(cip); + op_sref_alt: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + *(cell *)(data+(int)offs)=alt; + NEXT(cip); + op_sref_s_pri: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + *(cell *)(data+(int)offs)=pri; + NEXT(cip); + op_sref_s_alt: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + *(cell *)(data+(int)offs)=alt; + NEXT(cip); + op_stor_i: + /* verify address */ + if (alt>=hea && alt=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + *(cell *)(data+(int)alt)=pri; + NEXT(cip); + op_strb_i: + GETPARAM(offs); + /* verify address */ + if (alt>=hea && alt=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch (offs) { + case 1: + *(data+(int)alt)=(u_char)pri; + break; + case 2: + *(uint16_t *)(data+(int)alt)=(uint16_t)pri; + break; + case 4: + *(uint32_t *)(data+(int)alt)=(uint32_t)pri; + break; + } /* switch */ + NEXT(cip); + op_lidx: + offs=pri*sizeof(cell)+alt; + /* verify address */ + if (offs>=hea && offs=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)offs); + NEXT(cip); + op_lidx_b: + GETPARAM(offs); + offs=(pri << (int)offs)+alt; + /* verify address */ + if (offs>=hea && offs=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)offs); + NEXT(cip); + op_idxaddr: + pri=pri*sizeof(cell)+alt; + NEXT(cip); + op_idxaddr_b: + GETPARAM(offs); + pri=(pri << (int)offs)+alt; + NEXT(cip); + op_align_pri: + GETPARAM(offs); + if (amx_LittleEndian && offscod; + break; + case 1: + pri=hdr->dat; + break; + case 2: + pri=hea; + break; + case 3: + pri=amx->stp; + break; + case 4: + pri=stk; + break; + case 5: + pri=frm; + break; + case 6: + pri=(cell)((u_char *)cip - code); + break; + } /* switch */ + NEXT(cip); + op_sctrl: + GETPARAM(offs); + switch (offs) { + case 0: + case 1: + case 3: + /* cannot change these parameters */ + break; + case 2: + hea=pri; + break; + case 4: + stk=pri; + break; + case 5: + frm=pri; + break; + case 6: + cip=(cell *)(code + (int)pri); + break; + } /* switch */ + NEXT(cip); + op_move_pri: + pri=alt; + NEXT(cip); + op_move_alt: + alt=pri; + NEXT(cip); + op_xchg: + offs=pri; /* offs is a temporary variable */ + pri=alt; + alt=offs; + NEXT(cip); + op_push_pri: + PUSH(pri); + NEXT(cip); + op_push_alt: + PUSH(alt); + NEXT(cip); + op_push_c: + GETPARAM(offs); + PUSH(offs); + NEXT(cip); + op_push_r: + GETPARAM(offs); + while (offs--) + PUSH(pri); + NEXT(cip); + op_push: + GETPARAM(offs); + PUSH(* (cell *)(data+(int)offs)); + NEXT(cip); + op_push_s: + GETPARAM(offs); + PUSH(* (cell *)(data+(int)frm+(int)offs)); + NEXT(cip); + op_pop_pri: + POP(pri); + NEXT(cip); + op_pop_alt: + POP(alt); + NEXT(cip); + op_stack: + GETPARAM(offs); + alt=stk; + stk+=offs; + CHKMARGIN(); + CHKSTACK(); + /* if (debug && offs>0) { + amx->dbgcode=DBG_CLRSYM; + amx->stk=stk; + amx->hea=hea; + amx->debug(amx); + }*/ /* if */ + NEXT(cip); + op_heap: + GETPARAM(offs); + alt=hea; + hea+=offs; + CHKMARGIN(); + CHKHEAP(); + NEXT(cip); + op_proc: + PUSH(frm); + frm=stk; + CHKMARGIN(); + NEXT(cip); + op_ret: + POP(frm); + POP(offs); + cip=(cell *)(code+(int)offs); + //if (debug) { + // amx->dbgcode=DBG_RETURN; + // amx->dbgparam=pri; /* store "return value" */ + // amx->debug(amx); + //} /* if */ + NEXT(cip); + op_retn: + POP(frm); + POP(offs); + cip=(cell *)(code+(int)offs); + stk+= *(cell *)(data+(int)stk) + sizeof(cell); /* remove parameters from the stack */ + /*if (debug) { + amx->stk=stk; + amx->hea=hea; + amx->dbgcode=DBG_RETURN; + amx->dbgparam=pri; //store "return value" + amx->debug(amx); + amx->dbgcode=DBG_CLRSYM; + amx->debug(amx); + }*/ /* if */ + NEXT(cip); + op_call: + PUSH(((u_char *)cip-code)+sizeof(cell)); /* push address behind instruction */ + cip=JUMPABS(code, cip); /* jump to the address */ + //if (debug) { + // amx->dbgcode=DBG_CALL; + // amx->dbgaddr=(ucell)((u_char*)cip-code); + // amx->debug(amx); + //} /* if */ + NEXT(cip); + op_call_pri: + PUSH((u_char *)cip-code); + cip=(cell *)(code+(int)pri); + //if (debug) { + // amx->dbgcode=DBG_CALL; + // amx->dbgaddr=pri; + // amx->debug(amx); + //} /* if */ + NEXT(cip); +//op_calln: +// GETPARAM(offs); +// PUSH(offs); +// PUSH(((u_char *)cip-code)+sizeof(cell)); /* skip address */ +// cip=JUMPABS(code, cip); /* jump to the address */ +// if (debug) { +// amx->dbgcode=DBG_CALL; +// amx->dbgaddr=(ucell)((u_char *)cip-code); +// amx->debug(amx); +// } /* if */ +// NEXT(cip); + op_jump: + /* since the GETPARAM() macro modifies cip, you cannot + * do GETPARAM(cip) directly */ + cip=JUMPABS(code, cip); + NEXT(cip); + op_jrel: + offs=*cip; + cip=(cell *)((u_char *)cip + (int)offs + sizeof(cell)); + NEXT(cip); + op_jzer: + if (pri==0) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_jnz: + if (pri!=0) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_jeq: + if (pri==alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_jneq: + if (pri!=alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_jless: + if ((ucell)pri < (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_jleq: + if ((ucell)pri <= (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_jgrtr: + if ((ucell)pri > (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_jgeq: + if ((ucell)pri >= (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_jsless: + if (prialt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_jsgeq: + if (pri>=alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + NEXT(cip); + op_shl: + pri<<=alt; + NEXT(cip); + op_shr: + pri=(ucell)pri >> (ucell)alt; + NEXT(cip); + op_sshr: + pri>>=alt; + NEXT(cip); + op_shl_c_pri: + GETPARAM(offs); + pri<<=offs; + NEXT(cip); + op_shl_c_alt: + GETPARAM(offs); + alt<<=offs; + NEXT(cip); + op_shr_c_pri: + GETPARAM(offs); + pri=(ucell)pri >> (ucell)offs; + NEXT(cip); + op_shr_c_alt: + GETPARAM(offs); + alt=(ucell)alt >> (ucell)offs; + NEXT(cip); + op_smul: + pri*=alt; + NEXT(cip); + op_sdiv: + if (alt==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* divide must always round down; this is a bit + * involved to do in a machine-independent way. + */ + offs=(pri % alt + alt) % alt; /* true modulus */ + pri=(pri - offs) / alt; /* division result */ + alt=offs; + NEXT(cip); + op_sdiv_alt: + if (pri==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* divide must always round down; this is a bit + * involved to do in a machine-independent way. + */ + offs=(alt % pri + pri) % pri; /* true modulus */ + pri=(alt - offs) / pri; /* division result */ + alt=offs; + NEXT(cip); + op_umul: + pri=(ucell)pri * (ucell)alt; + NEXT(cip); + op_udiv: + if (alt==0) + ABORT(amx,AMX_ERR_DIVIDE); + offs=(ucell)pri % (ucell)alt; /* temporary storage */ + pri=(ucell)pri / (ucell)alt; + alt=offs; + NEXT(cip); + op_udiv_alt: + if (pri==0) + ABORT(amx,AMX_ERR_DIVIDE); + offs=(ucell)alt % (ucell)pri; /* temporary storage */ + pri=(ucell)alt / (ucell)pri; + alt=offs; + NEXT(cip); + op_add: + pri+=alt; + NEXT(cip); + op_sub: + pri-=alt; + NEXT(cip); + op_sub_alt: + pri=alt-pri; + NEXT(cip); + op_and: + pri&=alt; + NEXT(cip); + op_or: + pri|=alt; + NEXT(cip); + op_xor: + pri^=alt; + NEXT(cip); + op_not: + pri=!pri; + NEXT(cip); + op_neg: + pri=-pri; + NEXT(cip); + op_invert: + pri=~pri; + NEXT(cip); + op_add_c: + GETPARAM(offs); + pri+=offs; + NEXT(cip); + op_smul_c: + GETPARAM(offs); + pri*=offs; + NEXT(cip); + op_zero_pri: + pri=0; + NEXT(cip); + op_zero_alt: + alt=0; + NEXT(cip); + op_zero: + GETPARAM(offs); + *(cell *)(data+(int)offs)=0; + NEXT(cip); + op_zero_s: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=0; + NEXT(cip); + op_sign_pri: + if ((pri & 0xff)>=0x80) + pri|= ~ (ucell)0xff; + NEXT(cip); + op_sign_alt: + if ((alt & 0xff)>=0x80) + alt|= ~ (ucell)0xff; + NEXT(cip); + op_eq: + pri= pri==alt ? 1 : 0; + NEXT(cip); + op_neq: + pri= pri!=alt ? 1 : 0; + NEXT(cip); + op_less: + pri= (ucell)pri < (ucell)alt ? 1 : 0; + NEXT(cip); + op_leq: + pri= (ucell)pri <= (ucell)alt ? 1 : 0; + NEXT(cip); + op_grtr: + pri= (ucell)pri > (ucell)alt ? 1 : 0; + NEXT(cip); + op_geq: + pri= (ucell)pri >= (ucell)alt ? 1 : 0; + NEXT(cip); + op_sless: + pri= prialt ? 1 : 0; + NEXT(cip); + op_sgeq: + pri= pri>=alt ? 1 : 0; + NEXT(cip); + op_eq_c_pri: + GETPARAM(offs); + pri= pri==offs ? 1 : 0; + NEXT(cip); + op_eq_c_alt: + GETPARAM(offs); + pri= alt==offs ? 1 : 0; + NEXT(cip); + op_inc_pri: + pri++; + NEXT(cip); + op_inc_alt: + alt++; + NEXT(cip); + op_inc: + GETPARAM(offs); + *(cell *)(data+(int)offs) += 1; + NEXT(cip); + op_inc_s: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs) += 1; + NEXT(cip); + op_inc_i: + *(cell *)(data+(int)pri) += 1; + NEXT(cip); + op_dec_pri: + pri--; + NEXT(cip); + op_dec_alt: + alt--; + NEXT(cip); + op_dec: + GETPARAM(offs); + *(cell *)(data+(int)offs) -= 1; + NEXT(cip); + op_dec_s: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs) -= 1; + NEXT(cip); + op_dec_i: + *(cell *)(data+(int)pri) -= 1; + NEXT(cip); + op_movs: + GETPARAM(offs); + memcpy(data+(int)alt, data+(int)pri, (int)offs); + NEXT(cip); + op_cmps: + GETPARAM(offs); + pri=memcmp(data+(int)alt, data+(int)pri, (int)offs); + NEXT(cip); + op_fill: + GETPARAM(offs); + for (i=(int)alt; offs>=sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell)) + *(cell *)(data+i) = pri; + NEXT(cip); + op_halt: + GETPARAM(offs); + if (retval!=NULL) + *retval=pri; + /* store complete status */ + amx->frm=frm; + amx->stk=stk; + amx->hea=hea; + amx->pri=pri; + amx->alt=alt; + amx->cip=(cell)((u_char*)cip-code); + //if (debug) { + // amx->dbgcode=DBG_TERMINATE; + // amx->dbgaddr=(cell)((u_char *)cip-code); + // amx->dbgparam=offs; + // amx->debug(amx); + // } /* if */ + //if (offs==AMX_ERR_SLEEP) { + // amx->reset_stk=reset_stk; + // amx->reset_hea=reset_hea; + // return (int)offs; + //} /* if */ + ABORT(amx,(int)offs); + op_bounds: + GETPARAM(offs); + if (pri>=offs || pri<0) + ABORT(amx,AMX_ERR_BOUNDS); + NEXT(cip); + op_sysreq_pri: + /* save a few registers */ + amx->cip=(cell)((u_char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + num=amx->callback(amx,pri,&pri,(cell *)(data+(int)stk)); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return (int)offs; + } /* if */ + ABORT(amx,num); + } /* if */ + NEXT(cip); + op_sysreq_c: + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((u_char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return (int)offs; + } /* if */ + ABORT(amx,num); + } /* if */ + NEXT(cip); + op_file: + GETPARAM(offs); + cip=(cell *)((u_char *)cip + (int)offs); + assert(0); /* this code should not occur during execution */ + NEXT(cip); + op_line: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + GETPARAM(amx->curline); + GETPARAM(amx->curfile); + //if (debug) { + // amx->frm=frm; + // amx->stk=stk; + // amx->hea=hea; + // amx->dbgcode=DBG_LINE; + // num=amx->debug(amx); + // if (num!=AMX_ERR_NONE) + // ABORT(amx,num); + // } /* if */ + NEXT(cip); + op_symbol: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + GETPARAM(offs); + GETPARAM(amx->dbgaddr); + GETPARAM(amx->dbgparam); + amx->dbgname=(char *)cip; + cip=(cell *)((u_char *)cip + (int)offs - 2*sizeof(cell)); + amx->dbgcode=DBG_SYMBOL; + assert((amx->dbgparam >> 8)>0); /* local symbols only */ + // if (debug) { + // amx->frm=frm; /* debugger needs this to relocate the symbols */ + // amx->debug(amx); + // } /* if */ + NEXT(cip); + op_srange: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + GETPARAM(amx->dbgaddr); /* dimension level */ + GETPARAM(amx->dbgparam); /* length */ + amx->dbgcode=DBG_SRANGE; + // if (debug) { + // amx->frm=frm; /* debugger needs this to relocate the symbols */ + // amx->debug(amx); + // } /* if */ + NEXT(cip); + op_jump_pri: + cip=(cell *)(code+(int)pri); + NEXT(cip); + op_switch: { + cell *cptr; + + cptr=(cell *)*cip + 1; /* +1, to skip the "casetbl" opcode */ + cip=(cell *)*(cptr+1); /* preset to "none-matched" case */ + num=(int)*cptr; /* number of records in the case table */ + for (cptr+=2; num>0 && *cptr!=pri; num--,cptr+=2) + /* nothing */; + if (num>0) + cip=(cell *)*(cptr+1); /* case found */ + NEXT(cip); + } + op_casetbl: + assert(0); /* this should not occur during execution */ + NEXT(cip); + op_swap_pri: + offs=*(cell *)(data+(int)stk); + *(cell *)(data+(int)stk)=pri; + pri=offs; + NEXT(cip); + op_swap_alt: + offs=*(cell *)(data+(int)stk); + *(cell *)(data+(int)stk)=alt; + alt=offs; + NEXT(cip); + op_pushaddr: + GETPARAM(offs); + PUSH(frm+offs); + NEXT(cip); + op_nop: + NEXT(cip); +} + +#else + /* ANSI C & assembler versions */ + +#if defined ASM32 || defined JIT + /* For Watcom C/C++ use register calling convention (faster); for + * Microsoft C/C++ (and possibly others) use __cdecl. + * The important point is that you assemble AMXEXEC.ASM with the matching + * calling convention, or the right jit, respectively. + * jitr.asm is for Watcom's register calling convention, jits.asm for __cdecl. + */ + #if defined __WATCOMC__ + #if defined amx_Init && !defined STACKARGS /* for AMX32.DLL */ + extern cell amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); + /* The following pragma tells the compiler into which registers + * the parameters have to go. */ + #pragma aux amx_exec_asm parm [eax] [edx] [ebx] [ecx]; + #else + extern cell AMXAPI amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); + #endif + #else + extern cell __cdecl amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); + #endif +#endif + +//#include + +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + u_char *code, *data; + cell pri,alt,stk,frm,hea; + cell reset_stk, reset_hea, *cip; + int i; + va_list ap; + //int debug; + #if defined ASM32 || defined JIT + extern void *amx_opcodelist[]; + #ifdef __WATCOMC__ + #pragma aux amx_opcodelist "_*" + #endif + cell parms[9]; /* MP: registers for assembler AMX */ + #else + OPCODE op; + cell offs; + int num; + #endif + + #if defined ASM32 || defined JIT + /* HACK: return label table (for amx_BrowseRelocate) if amx structure + * is not passed. + */ + if (amx==NULL) { + assert(sizeof(cell)==sizeof(void *)); + assert(retval!=NULL); + *retval=(cell)amx_opcodelist; + return 0; + } /* if */ + #endif + + if (amx->callback==NULL) + return AMX_ERR_CALLBACK; + + + //i=amx_Register(amx,NULL,0); /* verify that all natives are registered */ + //if (i!=AMX_ERR_NONE) + // return i; + + amx->flags &= ~AMX_FLAG_BROWSE; + if ((amx->flags & AMX_FLAG_RELOC)==0) + return AMX_ERR_INIT; + //debug= (amx->flags & AMX_FLAG_DEBUG)!=0; + + /* set up the registers */ + hdr=(AMX_HEADER *)amx->base; + code=amx->base+(int)hdr->cod; + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + hea=amx->hea; + stk=amx->stk; + reset_stk=stk; + reset_hea=hea; + frm=alt=pri=0; /* silence up compiler */ + + /* get the start address */ + //if (index==AMX_EXEC_MAIN) { + // if (hdr->cip<0) + // return AMX_ERR_INDEX; + // cip=(cell *)(code + (int)hdr->cip); + //} else if (index==AMX_EXEC_CONT) { + /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */ + // frm=amx->frm; + // stk=amx->stk; + // hea=amx->hea; + // pri=amx->pri; + // alt=amx->alt; + // reset_stk=amx->reset_stk; + // reset_hea=amx->reset_hea; + // cip=(cell *)(code + (int)amx->cip); + //} else if (index<0) { + // return AMX_ERR_INDEX; + //} else { + if (index>=(cell)NUMENTRIES(*hdr,publics,natives)) + return AMX_ERR_INDEX; + func=(AMX_FUNCSTUB *)(amx->base + (int)hdr->publics + index*sizeof(AMX_FUNCSTUB)); + cip=(cell *)(code + (int)func->address); + //} /* if */ + /* check values just copied */ + CHKSTACK(); + CHKHEAP(); + + + //if (debug && index!=AMX_EXEC_CONT) { + /* set the entry point in the debugger by marking a "call" to the + * exported function + */ + // amx->dbgcode=DBG_CALL; + // amx->dbgaddr=(ucell)((u_char *)cip-code); + // amx->debug(amx); + //} /* if */ + + /* sanity checks */ + //assert(OP_PUSH_PRI==36); + //assert(OP_PROC==46); + //assert(OP_SHL==65); + //assert(OP_SMUL==72); + // assert(OP_EQ==95); + // assert(OP_INC_PRI==107); + //assert(OP_MOVS==117); + //assert(OP_SYMBOL==126); + //#if defined(BIT16) + // assert(sizeof(cell)==2); + //#else + // assert(sizeof(cell)==4); + //#endif + + //if (index!=AMX_EXEC_CONT) { + /* push the parameters to the stack (in reverse order) */ + if (numparams & 0xFFFF0000L) { + cell *params; + stk-=(numparams>>=16)*sizeof(cell); + va_start(ap,numparams); + params = va_arg(ap,cell*); + va_end(ap); + for (i=0; istp,hea); + if (i == AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + } else { + /* remove parameters from the stack; do this the "hard" way, because + * the assembler version has no internal knowledge of the local + * variables, so any "clean" way would be a kludge anyway. + */ + amx->stk=reset_stk; + amx->hea=reset_hea; + } /* if */ + return i; + +#else + + for ( ;; ) { + op=(OPCODE) *cip++; + switch (op) { + case OP_LOAD_PRI: + GETPARAM(offs); + pri= * (cell *)(data+(int)offs); + break; + case OP_LOAD_ALT: + GETPARAM(offs); + alt= * (cell *)(data+(int)offs); + break; + case OP_LOAD_S_PRI: + GETPARAM(offs); + pri= * (cell *)(data+(int)frm+(int)offs); + break; + case OP_LOAD_S_ALT: + GETPARAM(offs); + alt= * (cell *)(data+(int)frm+(int)offs); + break; + case OP_LREF_PRI: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + pri= * (cell *)(data+(int)offs); + break; + case OP_LREF_ALT: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + alt= * (cell *)(data+(int)offs); + break; + case OP_LREF_S_PRI: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + pri= * (cell *)(data+(int)offs); + break; + case OP_LREF_S_ALT: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + alt= * (cell *)(data+(int)offs); + break; + case OP_LOAD_I: + /* verify address */ + if (pri>=hea && pri=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)pri); + break; + case OP_LODB_I: + GETPARAM(offs); + /* verify address */ + if (pri>=hea && pri=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch (offs) { + case 1: + pri= * (data+(int)pri); + break; + case 2: + pri= * (uint16_t *)(data+(int)pri); + break; + case 4: + pri= * (uint32_t *)(data+(int)pri); + break; + } /* switch */ + break; + case OP_CONST_PRI: + GETPARAM(pri); + break; + case OP_CONST_ALT: + GETPARAM(alt); + break; + case OP_ADDR_PRI: + GETPARAM(pri); + pri+=frm; + break; + case OP_ADDR_ALT: + GETPARAM(alt); + alt+=frm; + break; + case OP_STOR_PRI: + GETPARAM(offs); + *(cell *)(data+(int)offs)=pri; + break; + case OP_STOR_ALT: + GETPARAM(offs); + *(cell *)(data+(int)offs)=alt; + break; + case OP_STOR_S_PRI: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=pri; + break; + case OP_STOR_S_ALT: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=alt; + break; + case OP_SREF_PRI: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + *(cell *)(data+(int)offs)=pri; + break; + case OP_SREF_ALT: + GETPARAM(offs); + offs= * (cell *)(data+(int)offs); + *(cell *)(data+(int)offs)=alt; + break; + case OP_SREF_S_PRI: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + *(cell *)(data+(int)offs)=pri; + break; + case OP_SREF_S_ALT: + GETPARAM(offs); + offs= * (cell *)(data+(int)frm+(int)offs); + *(cell *)(data+(int)offs)=alt; + break; + case OP_STOR_I: + /* verify address */ + if (alt>=hea && alt=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + *(cell *)(data+(int)alt)=pri; + break; + case OP_STRB_I: + GETPARAM(offs); + /* verify address */ + if (alt>=hea && alt=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch (offs) { + case 1: + *(data+(int)alt)=(u_char)pri; + break; + case 2: + *(uint16_t *)(data+(int)alt)=(uint16_t)pri; + break; + case 4: + *(uint32_t *)(data+(int)alt)=(uint32_t)pri; + break; + } /* switch */ + break; + case OP_LIDX: + offs=pri*sizeof(cell)+alt; + /* verify address */ + if (offs>=hea && offs=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)offs); + break; + case OP_LIDX_B: + GETPARAM(offs); + offs=(pri << (int)offs)+alt; + /* verify address */ + if (offs>=hea && offs=amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri= * (cell *)(data+(int)offs); + break; + case OP_IDXADDR: + pri=pri*sizeof(cell)+alt; + break; + case OP_IDXADDR_B: + GETPARAM(offs); + pri=(pri << (int)offs)+alt; + break; + case OP_ALIGN_PRI: + GETPARAM(offs); + if (amx_LittleEndian && (size_t)offscod; + break; + case 1: + pri=hdr->dat; + break; + case 2: + pri=hea; + break; + case 3: + pri=amx->stp; + break; + case 4: + pri=stk; + break; + case 5: + pri=frm; + break; + case 6: + pri=(cell)((u_char *)cip - code); + break; + } /* switch */ + break; + case OP_SCTRL: + GETPARAM(offs); + switch (offs) { + case 0: + case 1: + case 3: + /* cannot change these parameters */ + break; + case 2: + hea=pri; + break; + case 4: + stk=pri; + break; + case 5: + frm=pri; + break; + case 6: + cip=(cell *)(code + (int)pri); + break; + } /* switch */ + break; + case OP_MOVE_PRI: + pri=alt; + break; + case OP_MOVE_ALT: + alt=pri; + break; + case OP_XCHG: + offs=pri; /* offs is a temporary variable */ + pri=alt; + alt=offs; + break; + case OP_PUSH_PRI: + PUSH(pri); + break; + case OP_PUSH_ALT: + PUSH(alt); + break; + case OP_PUSH_C: + GETPARAM(offs); + PUSH(offs); + break; + case OP_PUSH_R: + GETPARAM(offs); + while (offs--) + PUSH(pri); + break; + case OP_PUSH: + GETPARAM(offs); + PUSH(* (cell *)(data+(int)offs)); + break; + case OP_PUSH_S: + GETPARAM(offs); + PUSH(* (cell *)(data+(int)frm+(int)offs)); + break; + case OP_POP_PRI: + POP(pri); + break; + case OP_POP_ALT: + POP(alt); + break; + case OP_STACK: + GETPARAM(offs); + alt=stk; + stk+=offs; + CHKMARGIN(); + CHKSTACK(); + /*if (debug && offs>0) { + amx->dbgcode=DBG_CLRSYM; + amx->hea=hea; + amx->stk=stk; + amx->debug(amx); + } *//* if */ + break; + case OP_HEAP: + GETPARAM(offs); + alt=hea; + hea+=offs; + CHKMARGIN(); + CHKHEAP(); + break; + case OP_PROC: + PUSH(frm); + frm=stk; + CHKMARGIN(); + break; + case OP_RET: + POP(frm); + POP(offs); + cip=(cell *)(code+(int)offs); + //if (debug) { + // amx->dbgcode=DBG_RETURN; + // amx->dbgparam=pri; /* store "return value" */ + // amx->debug(amx); + //} /* if */ + break; + case OP_RETN: + POP(frm); + POP(offs); + cip=(cell *)(code+(int)offs); + stk+= *(cell *)(data+(int)stk) + sizeof(cell); /* remove parameters from the stack */ + amx->stk=stk; + //if (debug) { + // amx->stk=stk; + // amx->hea=hea; + // amx->dbgcode=DBG_RETURN; + // amx->dbgparam=pri; /* store "return value" */ + // amx->debug(amx); + // amx->dbgcode=DBG_CLRSYM; + // amx->debug(amx); + //} /* if */ + break; + case OP_CALL: + PUSH(((u_char *)cip-code)+sizeof(cell)); /* skip address */ + cip=JUMPABS(code, cip); /* jump to the address */ + //if (debug) { + // amx->dbgcode=DBG_CALL; + // amx->dbgaddr=(ucell)((u_char *)cip-code); + // amx->debug(amx); + // } /* if */ + break; + case OP_CALL_PRI: + PUSH((u_char *)cip-code); + cip=(cell *)(code+(int)pri); + //if (debug) { + // amx->dbgcode=DBG_CALL; + // amx->dbgaddr=pri; + // amx->debug(amx); + //} /* if */ + break; +// case OP_CALLN: +// GETPARAM(offs); +// PUSH(offs); +// PUSH(((u_char *)cip-code)+sizeof(cell)); /* skip address */ +// cip=JUMPABS(code, cip); /* jump to the address */ +// if (debug) { +// amx->dbgcode=DBG_CALL; +// amx->dbgaddr=(ucell)((u_char *)cip-code); +// amx->debug(amx); +// } /* if */ +// break; + case OP_JUMP: + /* since the GETPARAM() macro modifies cip, you cannot + * do GETPARAM(cip) directly */ + cip=JUMPABS(code, cip); + break; + case OP_JREL: + offs=*cip; + cip=(cell *)((u_char *)cip + (int)offs + sizeof(cell)); + break; + case OP_JZER: + if (pri==0) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_JNZ: + if (pri!=0) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_JEQ: + if (pri==alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_JNEQ: + if (pri!=alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_JLESS: + if ((ucell)pri < (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_JLEQ: + if ((ucell)pri <= (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_JGRTR: + if ((ucell)pri > (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_JGEQ: + if ((ucell)pri >= (ucell)alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_JSLESS: + if (prialt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_JSGEQ: + if (pri>=alt) + cip=JUMPABS(code, cip); + else + cip=(cell *)((u_char *)cip+sizeof(cell)); + break; + case OP_SHL: + pri<<=alt; + break; + case OP_SHR: + pri=(ucell)pri >> (int)alt; + break; + case OP_SSHR: + pri>>=alt; + break; + case OP_SHL_C_PRI: + GETPARAM(offs); + pri<<=offs; + break; + case OP_SHL_C_ALT: + GETPARAM(offs); + alt<<=offs; + break; + case OP_SHR_C_PRI: + GETPARAM(offs); + pri=(ucell)pri >> (int)offs; + break; + case OP_SHR_C_ALT: + GETPARAM(offs); + alt=(ucell)alt >> (int)offs; + break; + case OP_SMUL: + pri*=alt; + break; + case OP_SDIV: + if (alt==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* divide must always round down; this is a bit + * involved to do in a machine-independent way. + */ + offs=(pri % alt + alt) % alt; /* true modulus */ + pri=(pri - offs) / alt; /* division result */ + alt=offs; + break; + case OP_SDIV_ALT: + if (pri==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* divide must always round down; this is a bit + * involved to do in a machine-independent way. + */ + offs=(alt % pri + pri) % pri; /* true modulus */ + pri=(alt - offs) / pri; /* division result */ + alt=offs; + break; + case OP_UMUL: + pri=(ucell)pri * (ucell)alt; + break; + case OP_UDIV: + if (alt==0) + ABORT(amx,AMX_ERR_DIVIDE); + offs=(ucell)pri % (ucell)alt; /* temporary storage */ + pri=(ucell)pri / (ucell)alt; + alt=offs; + break; + case OP_UDIV_ALT: + if (pri==0) + ABORT(amx,AMX_ERR_DIVIDE); + offs=(ucell)alt % (ucell)pri; /* temporary storage */ + pri=(ucell)alt / (ucell)pri; + alt=offs; + break; + case OP_ADD: + pri+=alt; + break; + case OP_SUB: + pri-=alt; + break; + case OP_SUB_ALT: + pri=alt-pri; + break; + case OP_AND: + pri&=alt; + break; + case OP_OR: + pri|=alt; + break; + case OP_XOR: + pri^=alt; + break; + case OP_NOT: + pri=!pri; + break; + case OP_NEG: + pri=-pri; + break; + case OP_INVERT: + pri=~pri; + break; + case OP_ADD_C: + GETPARAM(offs); + pri+=offs; + break; + case OP_SMUL_C: + GETPARAM(offs); + pri*=offs; + break; + case OP_ZERO_PRI: + pri=0; + break; + case OP_ZERO_ALT: + alt=0; + break; + case OP_ZERO: + GETPARAM(offs); + *(cell *)(data+(int)offs)=0; + break; + case OP_ZERO_S: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs)=0; + break; + case OP_SIGN_PRI: + if ((pri & 0xff)>=0x80) + pri|= ~ (ucell)0xff; + break; + case OP_SIGN_ALT: + if ((alt & 0xff)>=0x80) + alt|= ~ (ucell)0xff; + break; + case OP_EQ: + pri= pri==alt ? 1 : 0; + break; + case OP_NEQ: + pri= pri!=alt ? 1 : 0; + break; + case OP_LESS: + pri= (ucell)pri < (ucell)alt ? 1 : 0; + break; + case OP_LEQ: + pri= (ucell)pri <= (ucell)alt ? 1 : 0; + break; + case OP_GRTR: + pri= (ucell)pri > (ucell)alt ? 1 : 0; + break; + case OP_GEQ: + pri= (ucell)pri >= (ucell)alt ? 1 : 0; + break; + case OP_SLESS: + pri= prialt ? 1 : 0; + break; + case OP_SGEQ: + pri= pri>=alt ? 1 : 0; + break; + case OP_EQ_C_PRI: + GETPARAM(offs); + pri= pri==offs ? 1 : 0; + break; + case OP_EQ_C_ALT: + GETPARAM(offs); + pri= alt==offs ? 1 : 0; + break; + case OP_INC_PRI: + pri++; + break; + case OP_INC_ALT: + alt++; + break; + case OP_INC: + GETPARAM(offs); + *(cell *)(data+(int)offs) += 1; + break; + case OP_INC_S: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs) += 1; + break; + case OP_INC_I: + *(cell *)(data+(int)pri) += 1; + break; + case OP_DEC_PRI: + pri--; + break; + case OP_DEC_ALT: + alt--; + break; + case OP_DEC: + GETPARAM(offs); + *(cell *)(data+(int)offs) -= 1; + break; + case OP_DEC_S: + GETPARAM(offs); + *(cell *)(data+(int)frm+(int)offs) -= 1; + break; + case OP_DEC_I: + *(cell *)(data+(int)pri) -= 1; + break; + case OP_MOVS: + GETPARAM(offs); + memcpy(data+(int)alt, data+(int)pri, (int)offs); + break; + case OP_CMPS: + GETPARAM(offs); + pri=memcmp(data+(int)alt, data+(int)pri, (int)offs); + break; + case OP_FILL: + GETPARAM(offs); + for (i=(int)alt; (size_t)offs>=sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell)) + *(cell *)(data+i) = pri; + break; + case OP_HALT: + GETPARAM(offs); + if (retval!=NULL) + *retval=pri; + /* store complete status */ + amx->frm=frm; + amx->stk=stk; + amx->hea=hea; + amx->pri=pri; + amx->alt=alt; + amx->cip=(cell)((u_char*)cip-code); + //if (debug) { + // amx->dbgcode=DBG_TERMINATE; + // amx->dbgaddr=(cell)((u_char *)cip-code); + // amx->dbgparam=offs; + // amx->debug(amx); + //} /* if */ + if (offs==AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return (int)offs; + } /* if */ + ABORT(amx,(int)offs); + case OP_BOUNDS: + GETPARAM(offs); + if (pri>=offs || pri<0) + ABORT(amx,AMX_ERR_BOUNDS); + break; + case OP_SYSREQ_PRI: + /* save a few registers */ + amx->cip=(cell)((u_char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + num=amx->callback(amx,pri,&pri,(cell *)(data+(int)stk)); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return (int)offs; + } /* if */ + ABORT(amx,num); + } /* if */ + break; + case OP_SYSREQ_C: + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((u_char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return (int)offs; + } /* if */ + ABORT(amx,num); + } /* if */ + break; + case OP_FILE: + GETPARAM(offs); + cip=(cell *)((u_char *)cip+(int)offs); + assert(0); /* this code should not occur during execution */ + break; + case OP_LINE: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + GETPARAM(amx->curline); + GETPARAM(amx->curfile); + /*if (debug) { + amx->frm=frm; + amx->stk=stk; + amx->hea=hea; + amx->dbgcode=DBG_LINE; + num=amx->debug(amx); + if (num!=AMX_ERR_NONE) + ABORT(amx,num); + } *//* if */ + break; + case OP_SYMBOL: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + GETPARAM(offs); + GETPARAM(amx->dbgaddr); + GETPARAM(amx->dbgparam); + amx->dbgname=(char *)cip; + cip=(cell *)((u_char *)cip + (int)offs - 2*sizeof(cell)); + assert((amx->dbgparam >> 8)>0); /* local symbols only */ + //if (debug) { + // amx->frm=frm; /* debugger needs this to relocate the symbols */ + // amx->dbgcode=DBG_SYMBOL; + // amx->debug(amx); + //} /* if */ + break; + case OP_SRANGE: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + GETPARAM(amx->dbgaddr); /* dimension level */ + GETPARAM(amx->dbgparam); /* length */ + //if (debug) { + // amx->frm=frm; /* debugger needs this to relocate the symbols */ + // amx->dbgcode=DBG_SRANGE; + // amx->debug(amx); + //} /* if */ + break; + case OP_JUMP_PRI: + cip=(cell *)(code+(int)pri); + break; + case OP_SWITCH: { + cell *cptr; + + cptr=(cell *)*cip + 1; /* +1, to skip the "casetbl" opcode */ + cip=(cell *)*(cptr+1); /* preset to "none-matched" case */ + num=(int)*cptr; /* number of records in the case table */ + for (cptr+=2; num>0 && *cptr!=pri; num--,cptr+=2) + /* nothing */; + if (num>0) + cip=(cell *)*(cptr+1); /* case found */ + break; + } /* case */ + case OP_SWAP_PRI: + offs=*(cell *)(data+(int)stk); + *(cell *)(data+(int)stk)=pri; + pri=offs; + break; + case OP_SWAP_ALT: + offs=*(cell *)(data+(int)stk); + *(cell *)(data+(int)stk)=alt; + alt=offs; + break; + case OP_PUSHADDR: + GETPARAM(offs); + PUSH(frm+offs); + break; + case OP_NOP: + break; + case OP_CASETBL: + assert(0); /* should not occur during execution */ + /* drop through to "invalid instruction" */ + default: + ABORT(amx,AMX_ERR_INVINSTR); + } /* switch */ + } /* for */ +#endif +} + +#endif /* __GNUC__ */ + +/* For interfacing applications not written in C/C++, amx_Execv() works like + * amx_Exec(), but has all parameters passed via an array. + */ +int AMXAPI amx_Execv(AMX *amx, cell *retval, int index, int numparams, cell params[]) +{ + return amx_Exec(amx, retval, index, numparams<<16, params); +} + +int AMXAPI amx_SetCallback(AMX *amx,AMX_CALLBACK callback) +{ + assert(amx!=NULL); + assert(callback!=NULL); + amx->callback=callback; + return AMX_ERR_NONE; +} + +int AMXAPI amx_SetDebugHook(AMX *amx,AMX_DEBUG debug) +{ + assert(amx!=NULL); + assert(debug!=NULL); + amx->debug=debug; + return AMX_ERR_NONE; +} + +int AMXAPI amx_RaiseError(AMX *amx, int error) +{ + assert(error>0); + amx->error=error; + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr) +{ + AMX_HEADER *hdr; + u_char *data; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + + if (amx_addr>=amx->hea && amx_addrstk || amx_addr<0 || amx_addr>=amx->stp) + return AMX_ERR_MEMACCESS; + *phys_addr=(cell *)(data + (int)amx_addr); + return AMX_ERR_NONE; +} + +int AMXAPI amx_Allot(AMX *amx,int cells,cell *amx_addr,cell **phys_addr) +{ + AMX_HEADER *hdr; + u_char *data; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + + if (amx->stk - amx->hea - cells*sizeof(cell) < STKMARGIN) + return AMX_ERR_MEMORY; + assert(amx_addr!=NULL); + assert(phys_addr!=NULL); + *amx_addr=amx->hea; + *phys_addr=(cell *)(data + (int)amx->hea); + amx->hea += cells*sizeof(cell); + return AMX_ERR_NONE; +} + +int AMXAPI amx_Release(AMX *amx,cell amx_addr) +{ + if (amx->hea > amx_addr) + amx->hea=amx_addr; + return AMX_ERR_NONE; +} + +#define CHARBITS (8*sizeof(char)) +#if defined BIT16 + #define CHARMASK (0xffffu << 8*(2-sizeof(char))) +#else + #define CHARMASK (0xffffffffuL << 8*(4-sizeof(char))) +#endif + +int AMXAPI amx_StrLen(cell *cstr, int *length) +{ + register int len = 0; + if ((ucell)*cstr>UCHAR_MAX) { + /* packed string */ + assert(sizeof(char)==1); /* Unicode needs different functions */ + len=strlen((char *)cstr); /* find '\0' */ + if (amx_LittleEndian) { + /* on Little Endian machines, toggle the last bytes */ + cell c=cstr[len/sizeof(cell)]; /* get last cell */ + len=len - len % sizeof(cell); /* len = multiple of "cell" bytes */ + while ((c & CHARMASK)!=0) { + len++; + c <<= 8*sizeof(char); + } /* if */ + } /* if */ + } else { + while( cstr[ len ] ) + ++len; + /* nothing */ + } /* if */ + *length = len; + return AMX_ERR_NONE; +} + +int AMXAPI amx_SetString(cell *dest,char *source,int pack) +{ /* the memory blocks should not overlap */ + if (pack) { + int len=strlen(source); + /* create a packed string */ + dest[len/sizeof(cell)]=0; /* clear last bytes of last (semi-filled) cell*/ + memcpy(dest,source,len); + /* On Big Endian machines, the characters are well aligned in the + * cells; on Little Endian machines, we must swap all cells. + */ + if (amx_LittleEndian) { + len /= sizeof(cell); + while (len>=0) + swapcell((ucell *)&dest[len--]); + } /* if */ + } else { + /* create an unpacked string */ + while (*dest++=(cell)*source++) + ; + } /* if */ + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetString(char *dest,cell *source) +{ + if ((ucell)*source>UCHAR_MAX) { + /* source string is packed */ + cell c = 0; /* to avoid a compiler warning */ + int i=sizeof(cell)-1; + do { + if (i==sizeof(cell)-1) + c=*source++; + *dest=(char)(c >> i*CHARBITS); + i=(i+sizeof(cell)-1) % sizeof(cell); + } while (*dest++!='\0'); + } else { + /* source string is unpacked */ + while (*dest++=(char)*source++) + ; + } /* if */ + return AMX_ERR_NONE; +} + diff --git a/amxmodx/amx.h b/amxmodx/amx.h new file mode 100755 index 00000000..feb13178 --- /dev/null +++ b/amxmodx/amx.h @@ -0,0 +1,271 @@ +/* Abstract Machine for the Small compiler + * + * Copyright (c) ITB CompuPhase, 1997-2002 + * This file may be freely used. No warranties of any kind. + * + * Version: $Id$ + */ + +#if defined __linux__ + #include +#endif + +#ifndef __AMX_H +#define __AMX_H + +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L + /* The ISO C99 defines the int16_t and int_32t types. If the compiler got + * here, these types are probably undefined. + */ + #if defined __LCC__ || defined __linux__ + #include + #else + typedef short int int16_t; + typedef unsigned short int uint16_t; + #if defined SN_TARGET_PS2 + typedef int int32_t; + typedef unsigned int uint32_t; + #else + typedef long int int32_t; + typedef unsigned long int uint32_t; + #endif + #endif +#endif + +/* Some compilers do not support the #pragma align, which should be fine. Some + * compilers give a warning on unknown #pragmas, which is not so fine... + */ +#if defined SN_TARGET_PS2 + #define AMX_NO_ALIGN +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* calling convention for native functions */ +#if !defined AMX_NATIVE_CALL + #define AMX_NATIVE_CALL +#endif +/* calling convention for all interface functions and callback functions */ +#if !defined AMXAPI + #define AMXAPI +#endif + +/* File format version Required AMX version + * 0 (original version) 0 + * 1 (opcodes JUMP.pri, SWITCH and CASETBL) 1 + * 2 (compressed files) 2 + * 3 (public variables) 2 + * 4 (opcodes SWAP.pri/alt and PUSHADDR) 4 + * 5 (tagnames table) 4 + * 6 (reformatted header) 6 + */ +#define MIN_FILE_VERSION 6 /* lowest file format version */ +#define CUR_FILE_VERSION 6 /* current AMX version (parallel with file version) */ + +#if !defined CELL_TYPE + #define CELL_TYPE + #if defined(BIT16) + typedef uint16_t ucell; /* only for type casting */ + typedef int16_t cell; + #else + typedef uint32_t ucell; + typedef int32_t cell; + #endif +#endif + +struct __amx; +typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct __amx *amx, cell *params); +typedef int (AMXAPI *AMX_CALLBACK)(struct __amx *amx, cell index, + cell *result, cell *params); +typedef int (AMXAPI *AMX_DEBUG)(struct __amx *amx); +#if !defined FAR + #define FAR +#endif + +#if defined _MSC_VER + #pragma warning(disable:4103) /* disable warning message 4103 that complains + * about pragma pack in a header file */ +#endif + +#if !defined AMX_NO_ALIGN + #if defined __linux__ + #pragma pack(1) /* structures must be packed (byte-aligned) */ + #else + #pragma pack(push) + #pragma pack(1) /* structures must be packed (byte-aligned) */ + #if defined __TURBOC__ + #pragma option -a- /* "pack" pragma for older Borland compilers */ + #endif + #endif +#endif + +typedef struct { + char FAR *name; + AMX_NATIVE func; +} AMX_NATIVE_INFO; + +#define AMX_USERNUM 4 +#define sEXPMAX 19 +typedef struct { + uint32_t address; + char name[sEXPMAX+1]; +} AMX_FUNCSTUB; + +/* The AMX structure is the internal structure for many functions. Not all + * fields are valid at all times; many fields are cached in local variables. + */ +typedef struct __amx { + unsigned char FAR *base; /* points to the AMX header ("amxhdr") plus the code, optionally also the data */ + unsigned char FAR *data; /* points to separate data+stack+heap, may be NULL */ + AMX_CALLBACK callback; + AMX_DEBUG debug; + /* for external functions a few registers must be accessible from the outside */ + cell cip; /* relative to base + amxhdr->cod */ + cell frm; /* relative to base + amxhdr->dat */ + cell hea, hlw, stk, stp; /* all four are relative to base + amxhdr->dat */ + int flags; /* current status, see amx_Flags() */ + /* for assertions and debug hook */ + cell curline, curfile; + int dbgcode; + cell dbgaddr, dbgparam; + char FAR *dbgname; + /* user data */ + long usertags[AMX_USERNUM]; + void FAR *userdata[AMX_USERNUM]; + /* native functions can raise an error */ + int error; + /* the sleep opcode needs to store the full AMX status */ + cell pri, alt, reset_stk, reset_hea; + #if defined JIT + /* support variables for the JIT */ + int reloc_size; /* required temporary buffer for relocations */ + long code_size; /* estimated memory footprint of the native code */ + #endif +} AMX; + +/* The AMX_HEADER structure is both the memory format as the file format. The + * structure is used internaly. + */ +typedef struct __amx_header { + int32_t size; /* size of the "file" */ + uint16_t magic; /* signature */ + char file_version; /* file format version */ + char amx_version; /* required version of the AMX */ + int16_t flags; + int16_t defsize; + int32_t cod; /* initial value of COD - code block */ + int32_t dat; /* initial value of DAT - data block */ + int32_t hea; /* initial value of HEA - start of the heap */ + int32_t stp; /* initial value of STP - stack top */ + int32_t cip; /* initial value of CIP - the instruction pointer */ + int32_t publics; /* offset to the "public functions" table */ + int32_t natives; /* offset to the "native functions" table */ + int32_t libraries; /* offset to the table of libraries */ + int32_t pubvars; /* the "public variables" table */ + int32_t tags; /* the "public tagnames" table */ +} AMX_HEADER; +#define AMX_MAGIC 0xf1e0 + +enum { + AMX_ERR_NONE, + /* reserve the first 15 error codes for exit codes of the abstract machine */ + AMX_ERR_EXIT, /* forced exit */ + AMX_ERR_ASSERT, /* assertion failed */ + AMX_ERR_STACKERR, /* stack/heap collision */ + AMX_ERR_BOUNDS, /* index out of bounds */ + AMX_ERR_MEMACCESS, /* invalid memory access */ + AMX_ERR_INVINSTR, /* invalid instruction */ + AMX_ERR_STACKLOW, /* stack underflow */ + AMX_ERR_HEAPLOW, /* heap underflow */ + AMX_ERR_CALLBACK, /* no callback, or invalid callback */ + AMX_ERR_NATIVE, /* native function failed */ + AMX_ERR_DIVIDE, /* divide by zero */ + AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */ + + AMX_ERR_MEMORY = 16, /* out of memory */ + AMX_ERR_FORMAT, /* invalid file format */ + AMX_ERR_VERSION, /* file is for a newer version of the AMX */ + AMX_ERR_NOTFOUND, /* function not found */ + AMX_ERR_INDEX, /* invalid index parameter (bad entry point) */ + AMX_ERR_DEBUG, /* debugger cannot run */ + AMX_ERR_INIT, /* AMX not initialized (or doubly initialized) */ + AMX_ERR_USERDATA, /* unable to set user data field (table full) */ + AMX_ERR_INIT_JIT, /* cannot initialize the JIT */ + AMX_ERR_PARAMS, /* parameter error */ +}; + +enum { + DBG_INIT, /* query/initialize */ + DBG_FILE, /* file number in curfile, filename in name */ + DBG_LINE, /* line number in curline, file number in curfile */ + DBG_SYMBOL, /* address in dbgaddr, class/type in dbgparam */ + DBG_CLRSYM, /* stack address below which locals should be removed. stack address in stk */ + DBG_CALL, /* function call, address jumped to in dbgaddr */ + DBG_RETURN, /* function returns */ + DBG_TERMINATE, /* program ends, code address in dbgaddr, reason in dbgparam */ + DBG_SRANGE, /* symbol size and dimensions (arrays); level in dbgaddr (!); length in dbgparam */ +}; + +#define AMX_FLAG_CHAR16 0x01 /* characters are 16-bit */ +#define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */ +#define AMX_FLAG_COMPACT 0x04 /* compact encoding */ +#define AMX_FLAG_BIGENDIAN 0x08 /* big endian encoding */ +#define AMX_FLAG_BROWSE 0x4000 +#define AMX_FLAG_RELOC 0x8000 /* jump/call addresses relocated */ + +#define AMX_EXEC_MAIN -1 /* start at program entry point */ +#define AMX_EXEC_CONT -2 /* continue from last address */ + +#define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24)) + +uint16_t * AMXAPI amx_Align16(uint16_t *v); +uint32_t * AMXAPI amx_Align32(uint32_t *v); +int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr); +int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params); +int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data); +int AMXAPI amx_Debug(AMX *amx); /* default debug procedure, does nothing */ +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...); +int AMXAPI amx_Execv(AMX *amx, cell *retval, int index, int numparams, cell params[]); +int AMXAPI amx_FindPublic(AMX *amx, char *funcname, int *index); +int AMXAPI amx_FindPubVar(AMX *amx, char *varname, cell *amx_addr); +int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname); +int AMXAPI amx_Flags(AMX *amx,uint16_t *flags); +int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr); +int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname); +int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr); +int AMXAPI amx_GetString(char *dest,cell *source); +int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id); +int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr); +int AMXAPI amx_Init(AMX *amx, void *program); +int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code); +int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap); +int AMXAPI amx_NameLength(AMX *amx, int *length); +AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(char *name,AMX_NATIVE func); +int AMXAPI amx_NumPublics(AMX *amx, int *number); +int AMXAPI amx_NumPubVars(AMX *amx, int *number); +int AMXAPI amx_NumTags(AMX *amx, int *number); +int AMXAPI amx_RaiseError(AMX *amx, int error); +int AMXAPI amx_Register(AMX *amx, AMX_NATIVE_INFO *nativelist, int number); +int AMXAPI amx_Release(AMX *amx, cell amx_addr); +int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback); +int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug); +int AMXAPI amx_SetString(cell *dest, char *source, int pack); +int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr); +int AMXAPI amx_StrLen(cell *cstring, int *length); + +#if !defined AMX_NO_ALIGN + #if defined __linux__ + #pragma pack() /* reset default packing */ + #else + #pragma pack(pop) /* reset previous packing */ + #endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __AMX_H */ + diff --git a/amxmodx/amx_mm.def b/amxmodx/amx_mm.def new file mode 100755 index 00000000..d9f23593 --- /dev/null +++ b/amxmodx/amx_mm.def @@ -0,0 +1,11 @@ +; /usr/local/cross-tools/bin/i386-mingw32msvc-dlltool --base-file /tmp/cc4kB6s0.base --output-exp amx_mm.exp --dllname amx_mm.dll --output-def amx_mm.def --add-stdcall-alias --exclude-symbol=DllMainCRTStartup@12 --def /tmp/ccyI7I7K.def +EXPORTS + GetEngineFunctions @ 1 ; + GetEngineFunctions_Post @ 2 ; + GetEntityAPI2 @ 3 ; + GetEntityAPI2_Post @ 4 ; + GiveFnptrsToDll = GiveFnptrsToDll@8 @ 5 ; + GiveFnptrsToDll@8 @ 6 ; + Meta_Attach @ 7 ; + Meta_Detach @ 8 ; + Meta_Query @ 9 ; diff --git a/amxmodx/amxcore.c b/amxmodx/amxcore.c new file mode 100755 index 00000000..014c41d9 --- /dev/null +++ b/amxmodx/amxcore.c @@ -0,0 +1,548 @@ +/* Core module for the Small AMX + * + * Copyright (c) ITB CompuPhase, 1997-2002 + * This file may be freely used. No warranties of any kind. + * + * Version: $Id$ + */ +#include +#include +#include +#include +#include +#include "amx.h" + +#define NOPROPLIST + +/* A few compilers do not provide the ANSI C standard "time" functions */ +#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE + #include +#endif + +#define CHARBITS (8*sizeof(char)) +typedef unsigned char uchar; + +#if !defined NOPROPLIST +typedef struct _property_list { + struct _property_list *next; + cell id; + char *name; + cell value; +} proplist; + +static proplist proproot = { NULL }; + +static proplist *list_additem(proplist *root) +{ + proplist *item; + + assert(root!=NULL); + if ((item=(proplist *)malloc(sizeof(proplist)))==NULL) + return NULL; + item->name=NULL; + item->id=0; + item->value=0; + item->next=root->next; + root->next=item; + return item; +} +static void list_delete(proplist *pred,proplist *item) +{ + assert(pred!=NULL); + assert(item!=NULL); + pred->next=item->next; + assert(item->name!=NULL); + free(item->name); + free(item); +} +static void list_setitem(proplist *item,cell id,char *name,cell value) +{ + char *ptr; + + assert(item!=NULL); + if ((ptr=(char *)malloc(strlen(name)+1))==NULL) + return; + if (item->name!=NULL) + free(item->name); + strcpy(ptr,name); + item->name=ptr; + item->id=id; + item->value=value; +} +static proplist *list_finditem(proplist *root,cell id,char *name,cell value, + proplist **pred) +{ + proplist *item=root->next; + proplist *prev=root; + + /* check whether to find by name or by value */ + assert(name!=NULL); + if (strlen(name)>0) { + /* find by name */ + while (item!=NULL && (item->id!=id || stricmp(item->name,name)!=0)) { + prev=item; + item=item->next; + } /* while */ + } else { + /* find by value */ + while (item!=NULL && (item->id!=id || item->value!=value)) { + prev=item; + item=item->next; + } /* while */ + } /* if */ + if (pred!=NULL) + *pred=prev; + return item; +} +#endif + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL numargs(AMX *amx, cell *params) +{ + AMX_HEADER *hdr; + uchar *data; + cell bytes; + + hdr=(AMX_HEADER *)amx->base; + data=amx->base+(int)hdr->dat; + /* the number of bytes is on the stack, at "frm + 2*cell" */ + bytes= * (cell *)(data+(int)amx->frm+2*sizeof(cell)); + /* the number of arguments is the number of bytes divided + * by the size of a cell */ + return bytes/sizeof(cell); +} + +static cell AMX_NATIVE_CALL getarg(AMX *amx, cell *params) +{ + AMX_HEADER *hdr; + uchar *data; + cell value; + + hdr=(AMX_HEADER *)amx->base; + data=amx->base+(int)hdr->dat; + /* get the base value */ + value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell)); + /* adjust the address in "value" in case of an array access */ + value+=params[2]*sizeof(cell); + /* get the value indirectly */ + value= * (cell *)(data+(int)value); + return value; +} + +static cell AMX_NATIVE_CALL setarg(AMX *amx, cell *params) +{ + AMX_HEADER *hdr; + uchar *data; + cell value; + + hdr=(AMX_HEADER *)amx->base; + data=amx->base+(int)hdr->dat; + /* get the base value */ + value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell)); + /* adjust the address in "value" in case of an array access */ + value+=params[2]*sizeof(cell); + /* verify the address */ + if (value<0 || value>=amx->hea && valuestk) + return 0; + /* set the value indirectly */ + * (cell *)(data+(int)value) = params[3]; + return 1; +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL heapspace(AMX *amx,cell *params) +{ + return amx->stk - amx->hea; +} + +static cell AMX_NATIVE_CALL funcidx(AMX *amx,cell *params) +{ + char name[64]; + cell *cstr; + int index,err,len; + + amx_GetAddr(amx,params[1],&cstr); + + /* verify string length */ + amx_StrLen(cstr,&len); + if (len>=64) { + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } /* if */ + + amx_GetString(name,cstr); + err=amx_FindPublic(amx,name,&index); + if (err!=AMX_ERR_NONE) + index=-1; /* this is not considered a fatal error */ + return index; +} + +int amx_StrPack(cell *dest,cell *source) +{ + int len; + + amx_StrLen(source,&len); + if ((ucell)*source>UCHAR_MAX) { + /* source string is already packed */ + while (len >= 0) { + *dest++ = *source++; + len-=sizeof(cell); + } /* while */ + } else { + /* pack string, from bottom up */ + cell c; + int i; + for (c=0,i=0; iUCHAR_MAX) { + /* unpack string, from top down (so string can be unpacked in place) */ + cell c; + int i,len; + amx_StrLen(source,&len); + dest[len]=0; + for (i=len-1; i>=0; i--) { + c=source[i/sizeof(cell)] >> (sizeof(cell)-i%sizeof(cell)-1)*CHARBITS; + dest[i]=c & UCHAR_MAX; + } /* for */ + } else { + /* source string is already unpacked */ + while ((*dest++ = *source++) != 0) + /* nothing */; + } /* if */ + return AMX_ERR_NONE; +} + +static int verify_addr(AMX *amx,cell addr) +{ + int err; + cell *cdest; + + err=amx_GetAddr(amx,addr,&cdest); + if (err!=AMX_ERR_NONE) + amx_RaiseError(amx,err); + return err; +} + +static cell AMX_NATIVE_CALL core_strlen(AMX *amx,cell *params) +{ + cell *cptr; + int len = 0; + + if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE) + amx_StrLen(cptr,&len); + return len; +} + +static cell AMX_NATIVE_CALL strpack(AMX *amx,cell *params) +{ + cell *cdest,*csrc; + int len,needed,lastaddr,err; + + /* calculate number of cells needed for (packed) destination */ + amx_GetAddr(amx,params[2],&csrc); + amx_StrLen(csrc,&len); + needed=(len+sizeof(cell))/sizeof(cell); /* # of cells needed */ + assert(needed>0); + lastaddr=params[1]+sizeof(cell)*needed-1; + if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE) + return 0; + + amx_GetAddr(amx,params[1],&cdest); + err=amx_StrPack(cdest,csrc); + if (err!=AMX_ERR_NONE) + return amx_RaiseError(amx,err); + + return len; +} + +static cell AMX_NATIVE_CALL strunpack(AMX *amx,cell *params) +{ + cell *cdest,*csrc; + int len,err,lastaddr; + + /* calculate number of cells needed for (packed) destination */ + amx_GetAddr(amx,params[2],&csrc); + amx_StrLen(csrc,&len); + assert(len>=0); + lastaddr=params[1]+sizeof(cell)*(len+1)-1; + if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE) + return 0; + + amx_GetAddr(amx,params[1],&cdest); + err=amx_StrUnpack(cdest,csrc); + if (err!=AMX_ERR_NONE) + return amx_RaiseError(amx,err); + + return len; +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL swapchars(AMX *amx,cell *params) +{ + union { + cell c; + #if defined BIT16 + uchar b[2]; + #else + uchar b[4]; + #endif + } value; + uchar t; + + assert((size_t)params[0]==sizeof(cell)); + value.c = params[1]; + #if defined BIT16 + t = value.b[0]; + value.b[0] = value.b[1]; + value.b[1] = t; + #else + t = value.b[0]; + value.b[0] = value.b[3]; + value.b[3] = t; + t = value.b[1]; + value.b[1] = value.b[2]; + value.b[2] = t; + #endif + return value.c; +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL core_tolower(AMX *amx,cell *params) +{ + assert((size_t)params[0]==sizeof(cell)); + return tolower((int)params[1]); +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL core_toupper(AMX *amx,cell *params) +{ + assert((size_t)params[0]==sizeof(cell)); + return toupper((int)params[1]); +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL core_min(AMX *amx,cell *params) +{ + return params[1] <= params[2] ? params[1] : params[2]; +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL core_max(AMX *amx,cell *params) +{ + return params[1] >= params[2] ? params[1] : params[2]; +} + +static cell AMX_NATIVE_CALL core_clamp(AMX *amx,cell *params) +{ + cell value = params[1]; + if (params[2] > params[3]) /* minimum value > maximum value ! */ + amx_RaiseError(amx,AMX_ERR_NATIVE); + if (value < params[2]) + value = params[2]; + else if (value > params[3]) + value = params[3]; + return value; +} + +#if !defined NOPROPLIST +static char *MakePackedString(cell *cptr) +{ + int len; + char *dest; + + amx_StrLen(cptr,&len); + dest=(char *)malloc(len+sizeof(cell)); + amx_GetString(dest,cptr); + return dest; +} + +static cell AMX_NATIVE_CALL getproperty(AMX *amx,cell *params) +{ + cell *cstr; + char *name; + proplist *item; + + amx_GetAddr(amx,params[2],&cstr); + name=MakePackedString(cstr); + item=list_finditem(&proproot,params[1],name,params[3],NULL); + /* if list_finditem() found the value, store the name */ + if (item!=NULL && item->value==params[3] && strlen(name)==0) { + int needed=(strlen(item->name)+sizeof(cell)-1)/sizeof(cell); /* # of cells needed */ + if (verify_addr(amx,(cell)(params[4]+needed))!=AMX_ERR_NONE) { + free(name); + return 0; + } /* if */ + amx_GetAddr(amx,params[4],&cstr); + amx_SetString(cstr,item->name,1); + } /* if */ + free(name); + return (item!=NULL) ? item->value : 0; +} + +static cell AMX_NATIVE_CALL setproperty(AMX *amx,cell *params) +{ + cell prev=0; + cell *cstr; + char *name; + proplist *item; + + amx_GetAddr(amx,params[2],&cstr); + name=MakePackedString(cstr); + item=list_finditem(&proproot,params[1],name,params[3],NULL); + if (item==NULL) + item=list_additem(&proproot); + if (item==NULL) { + amx_RaiseError(amx,AMX_ERR_MEMORY); + } else { + prev=item->value; + if (strlen(name)==0) { + free(name); + amx_GetAddr(amx,params[4],&cstr); + name=MakePackedString(cstr); + } /* if */ + list_setitem(item,params[1],name,params[3]); + } /* if */ + free(name); + return prev; +} + +static cell AMX_NATIVE_CALL delproperty(AMX *amx,cell *params) +{ + cell prev=0; + cell *cstr; + char *name; + proplist *item,*pred; + + amx_GetAddr(amx,params[2],&cstr); + name=MakePackedString(cstr); + item=list_finditem(&proproot,params[1],name,params[3],&pred); + if (item!=NULL) { + prev=item->value; + list_delete(pred,item); + } /* if */ + free(name); + return prev; +} + +static cell AMX_NATIVE_CALL existproperty(AMX *amx,cell *params) +{ + cell *cstr; + char *name; + proplist *item; + + amx_GetAddr(amx,params[2],&cstr); + name=MakePackedString(cstr); + item=list_finditem(&proproot,params[1],name,params[3],NULL); + free(name); + return (item!=NULL); +} +#endif + +/* This routine comes from the book "Inner Loops" by Rick Booth, Addison-Wesley + * (ISBN 0-201-47960-5). This is a "multiplicative congruential random number + * generator" that has been extended to 31-bits (the standard C version returns + * only 15-bits). + */ +static unsigned long IL_StandardRandom_seed = 0L; +#define IL_RMULT 1103515245L +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL core_random(AMX *amx,cell *params) +{ + unsigned long lo, hi, ll, lh, hh, hl; + unsigned long result; + + /* one-time initialization (or, mostly one-time) */ + #if !defined SN_TARGET_PS2 && !defined _WIN32_WCE + if (IL_StandardRandom_seed == 0L) + IL_StandardRandom_seed=(unsigned long)time(NULL); + #endif + + lo = IL_StandardRandom_seed & 0xffff; + hi = IL_StandardRandom_seed >> 16; + IL_StandardRandom_seed = IL_StandardRandom_seed * IL_RMULT + 12345; + ll = lo * (IL_RMULT & 0xffff); + lh = lo * (IL_RMULT >> 16 ); + hl = hi * (IL_RMULT & 0xffff); + hh = hi * (IL_RMULT >> 16 ); + result = ((ll + 12345) >> 16) + lh + hl + (hh << 16); + result &= ~LONG_MIN; /* remove sign bit */ + if (params[1]!=0) + result %= params[1]; + return (cell)result; +} + +#if 0 + +void core_Init(void) +{ + /* reduced to a do-nothing routine */ +} + +void core_Exit(void) +{ + #if !defined NOPROPLIST + while (proproot.next!=NULL) + list_delete(&proproot,proproot.next); + #endif +} + +#endif + +AMX_NATIVE_INFO core_Natives[] = { + { "numargs", numargs }, + { "getarg", getarg }, + { "setarg", setarg }, + { "heapspace", heapspace }, + { "funcidx", funcidx }, + { "strlen", core_strlen }, + { "strpack", strpack }, + { "strunpack", strunpack }, + { "swapchars", swapchars }, + { "tolower", core_tolower }, + { "toupper", core_toupper }, + { "random", core_random }, + { "min", core_min }, + { "max", core_max }, + { "clamp", core_clamp }, +#if !defined NOPROPLIST + { "getproperty", getproperty }, + { "setproperty", setproperty }, + { "deleteproperty",delproperty }, + { "existproperty", existproperty }, +#endif + { NULL, NULL } /* terminator */ +}; + + diff --git a/amxmodx/amxmod.cpp b/amxmodx/amxmod.cpp new file mode 100755 index 00000000..679df8ab --- /dev/null +++ b/amxmodx/amxmod.cpp @@ -0,0 +1,2202 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" + + +static cell AMX_NATIVE_CALL get_xvar_id(AMX *amx, cell *params) +{ + int len; + char* sName = get_amxstring(amx,params[1],0,len); + cell ptr; + + for ( CPluginMngr::iterator a = g_plugins.begin(); a ; ++a ) + { + if ( (*a).isValid() && amx_FindPubVar( (*a).getAMX() , sName , &ptr ) == AMX_ERR_NONE ) + return g_xvars.put( (*a).getAMX() , get_amxaddr( (*a).getAMX() , ptr ) ); + } + return -1; +} + +static cell AMX_NATIVE_CALL get_xvar_num(AMX *amx, cell *params) +{ + return g_xvars.getValue(params[1]); +} + +static cell AMX_NATIVE_CALL set_xvar_num(AMX *amx, cell *params) +{ + if ( g_xvars.setValue( params[1] , params[2] ) ){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + return 1; +} + +static cell AMX_NATIVE_CALL xvar_exists(AMX *amx, cell *params) +{ + return (get_xvar_id( amx , params ) != -1) ? 1 : 0; +} + +static cell AMX_NATIVE_CALL emit_sound(AMX *amx, cell *params) /* 7 param */ +{ + + int len; + char* szSample = get_amxstring(amx,params[3],0,len); + float vol = *(float *)((void *)¶ms[4]); + float att = *(float *)((void *)¶ms[5]); + int channel = params[2]; + int pitch = params[7]; + int flags = params[6]; + + if (params[1] == 0) { + for(int i = 1; i <= gpGlobals->maxClients ; ++i){ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->ingame) + EMIT_SOUND_DYN2(pPlayer->pEdict,channel, szSample, vol, att,flags , pitch); + } + } + else + { + edict_t* pEdict = INDEXENT(params[1]); + if (!FNullEnt(pEdict)) + EMIT_SOUND_DYN2(pEdict,channel , szSample, vol, att, flags, pitch); + } + + return 1; +} + +static cell AMX_NATIVE_CALL server_print(AMX *amx, cell *params) /* 1 param */ +{ + int len; + char* message = format_amxstring(amx,params,1,len); + if ( len > 254 ) len = 254; + message[len++]='\n'; + message[len]=0; + SERVER_PRINT( message ); + return len; +} + +static cell AMX_NATIVE_CALL engclient_print(AMX *amx, cell *params) /* 3 param */ +{ + int len; + char* message = format_amxstring(amx,params,3,len); + message[len++]='\n'; + message[len]=0; + if (params[1] == 0) { + for(int i = 1; i <= gpGlobals->maxClients ; ++i){ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->ingame) + CLIENT_PRINT(pPlayer->pEdict, (PRINT_TYPE)(int)params[2] , message ); + } + } + else { + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame) + CLIENT_PRINT(pPlayer->pEdict, (PRINT_TYPE)(int)params[2] , message ); + } + return len; +} + +static cell AMX_NATIVE_CALL console_cmd(AMX *amx, cell *params) /* 2 param */ +{ + int len; + char* cmd = format_amxstring(amx,params,2,len); + cmd[len++]='\n'; + cmd[len]=0; + + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + SERVER_COMMAND( cmd ); + } + else{ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if ( !pPlayer->bot && pPlayer->initialized ) CLIENT_COMMAND(pPlayer->pEdict, cmd ); + } + + return len; +} + +static cell AMX_NATIVE_CALL console_print(AMX *amx, cell *params) /* 2 param */ +{ + int len; + char* message = format_amxstring(amx,params,2,len); + if ( len > 254 ) len = 254; + message[len++]='\n'; + message[len]=0; + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + SERVER_PRINT( message ); + } + else { + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame) + UTIL_ClientPrint(pPlayer->pEdict, 2 , message ); + } + return len; +} + + +static cell AMX_NATIVE_CALL client_print(AMX *amx, cell *params) /* 3 param */ +{ + int len; + char* message = format_amxstring(amx,params,3,len); + message[len++]='\n'; + message[len]=0; + if (params[1] == 0) { + UTIL_ClientPrint(NULL, params[2] , message ); + } + else { + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame) + UTIL_ClientPrint(pPlayer->pEdict, params[2] , message ); + } + return len; +} + +static cell AMX_NATIVE_CALL show_motd(AMX *amx, cell *params) /* 2 param */ +{ + int ilen; + const char* szHead = get_amxstring(amx,params[3],0,ilen); + if ( !ilen ) szHead = hostname->string; + char* szBody = get_amxstring(amx,params[2],1,ilen); + int iFile = 0; + char* sToShow;// = szBody; + if (ilen<128) sToShow = (char*)LOAD_FILE_FOR_ME( szBody , &iFile ); + if (!iFile) + sToShow = szBody; + else + ilen = iFile; + if (params[1] == 0) { + for(int i = 1; i <= gpGlobals->maxClients; ++i){ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->ingame) + UTIL_ShowMOTD(pPlayer->pEdict, sToShow , ilen, szHead); + } + } + else { + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + if (iFile) FREE_FILE(sToShow); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame) + UTIL_ShowMOTD(pPlayer->pEdict, sToShow,ilen, szHead ); + } + if (iFile) FREE_FILE(sToShow); + return 1; +} + +static cell AMX_NATIVE_CALL set_hudmessage(AMX *amx, cell *params) /* 11 param */ +{ + g_hudset.a1 = 0; + g_hudset.a2 = 0; + g_hudset.r2 = 255; + g_hudset.g2 = 255; + g_hudset.b2 = 250; + g_hudset.r1 = params[1]; + g_hudset.g1 = params[2]; + g_hudset.b1 = params[3]; + g_hudset.x = *(float *)((void *)¶ms[4]); + g_hudset.y = *(float *)((void *)¶ms[5]); + g_hudset.effect = params[6]; + g_hudset.fxTime = *(float *)((void *)¶ms[7]); + g_hudset.holdTime = *(float *)((void *)¶ms[8]); + g_hudset.fadeinTime = *(float *)((void *)¶ms[9]); + g_hudset.fadeoutTime = *(float *)((void *)¶ms[10]); + g_hudset.channel = params[11]; + return 1; +} + +static cell AMX_NATIVE_CALL show_hudmessage(AMX *amx, cell *params) /* 2 param */ +{ + int len; + char* message = UTIL_SplitHudMessage( format_amxstring(amx,params,2,len) ); + if (params[1] == 0) { + UTIL_HudMessage(NULL, g_hudset, message ); + } + else { + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame) + UTIL_HudMessage(pPlayer->pEdict, g_hudset, message ); + } + return len; +} + +static cell AMX_NATIVE_CALL get_user_name(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + return set_amxstring(amx,params[2],(index<1||index>gpGlobals->maxClients) ? + hostname->string : g_players[index].name.str() , params[3]); +} + +static cell AMX_NATIVE_CALL get_user_index(AMX *amx, cell *params) /* 1 param */ +{ + int i; + char* sptemp = get_amxstring(amx,params[1],0,i); + for(i = 1; i <= gpGlobals->maxClients; ++i) { + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if ( strcmp(pPlayer->name.str(), sptemp) == 0 ) + return i; + } + + return 0; +} + +static cell AMX_NATIVE_CALL is_dedicated_server(AMX *amx, cell *params) +{ + return (IS_DEDICATED_SERVER() ? 1 : 0); +} + +static cell AMX_NATIVE_CALL is_linux_server(AMX *amx, cell *params) +{ +#ifdef __linux__ + return 1; +#else + return 0; +#endif +} + +static cell AMX_NATIVE_CALL is_map_valid(AMX *amx, cell *params) /* 1 param */ +{ + int ilen; + return (IS_MAP_VALID(get_amxstring(amx,params[1],0,ilen)) ? 1 : 0); +} + +static cell AMX_NATIVE_CALL is_user_connected(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + return (pPlayer->ingame ? 1 : 0); +} + +static cell AMX_NATIVE_CALL is_user_connecting(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + return ( !pPlayer->ingame && pPlayer->initialized + && (GETPLAYERUSERID(pPlayer->pEdict)>0) ) ? 1 : 0; +} + +static cell AMX_NATIVE_CALL is_user_bot(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + return (GET_PLAYER_POINTER_I(index)->bot ? 1 : 0); +} + + +static cell AMX_NATIVE_CALL is_user_hltv(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + return ((GET_PLAYER_POINTER_I(index)->pEdict->v.flags & FL_PROXY) ? 1 : 0); +} + +static cell AMX_NATIVE_CALL is_user_alive(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + return ((pPlayer->ingame && pPlayer->IsAlive()) ? 1 : 0); +} + +static cell AMX_NATIVE_CALL get_user_frags(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + return (cell)(pPlayer->ingame ? pPlayer->pEdict->v.frags : 0); +} + +static cell AMX_NATIVE_CALL get_user_deaths(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + return (pPlayer->ingame ? pPlayer->deaths : 0); +} + +static cell AMX_NATIVE_CALL get_user_armor(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + return (cell)(pPlayer->ingame ? pPlayer->pEdict->v.armorvalue : 0); +} + +static cell AMX_NATIVE_CALL get_user_health(AMX *amx, cell *params) /* param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + return (cell)(pPlayer->ingame ? pPlayer->pEdict->v.health : 0); +} + +static cell AMX_NATIVE_CALL get_user_userid(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + return pPlayer->initialized ? GETPLAYERUSERID(pPlayer->pEdict) : -1; +} + +static cell AMX_NATIVE_CALL get_user_wonid(AMX *amx, cell *params) //1 param +{ + return 0; +} + + +static cell AMX_NATIVE_CALL get_user_authid(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + const char* authid = 0; + if (index>0&&index<=gpGlobals->maxClients) + authid = GETPLAYERAUTHID(g_players[index].pEdict); + return set_amxstring(amx,params[2], authid ? authid : "" ,params[3]); +} + +static cell AMX_NATIVE_CALL is_user_authorized(AMX *amx, cell *params) +{ + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients) + return 0; + return GET_PLAYER_POINTER_I(index)->authorized; +} + +static cell AMX_NATIVE_CALL get_weaponname(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + if (index < 1 || index >= MAX_WEAPONS ){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + return set_amxstring(amx,params[2],g_weaponsData[index].fullName.str(),params[3]); +} + +static cell AMX_NATIVE_CALL get_user_weapons(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame){ + cell *cpNum = get_amxaddr(amx,params[3]); + cell *cpIds = get_amxaddr(amx,params[2]); + int weapons = pPlayer->pEdict->v.weapons & ~(1<<31); // don't count last element + for(int i = 1; i < MAX_WEAPONS; ++i){ + if (weapons & (1< gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame){ + int mode = params[3]; + cell *cpOrigin = get_amxaddr(amx,params[2]); + if (mode == 4) { + cpOrigin[0] = (long int)pPlayer->lastHit.x; + cpOrigin[1] = (long int)pPlayer->lastHit.y; + cpOrigin[2] = (long int)pPlayer->lastHit.z; + return 1; + } + edict_t* edict = pPlayer->pEdict; + Vector pos = edict->v.origin; + if (mode && mode!=2) + pos = pos + edict->v.view_ofs; + if (mode > 1) { + Vector v_forward; + ANGLEVECTORS( edict->v.v_angle , v_forward, NULL, NULL ); + TraceResult trEnd; + Vector v_dest = pos + v_forward * 9999; + TRACE_LINE( pos , v_dest, 0 , edict, &trEnd ); + pos = (trEnd.flFraction < 1.0) ? trEnd.vecEndPos : Vector(0,0,0); + } + cpOrigin[0] = (long int)pos.x; + cpOrigin[1] = (long int)pos.y; + cpOrigin[2] = (long int)pos.z; + return 1; + } + return 0; +} + +static cell AMX_NATIVE_CALL get_user_ip(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + char *ptr; + char szIp[32]; + strcpy(szIp,(index<1||index>gpGlobals->maxClients)? + CVAR_GET_STRING("net_address"):g_players[index].ip.str()); + if (params[4] && (ptr = strstr(szIp,":"))!=0) + *ptr = '\0'; + return set_amxstring(amx,params[2],szIp,params[3]); +} + +static cell AMX_NATIVE_CALL get_user_attacker(AMX *amx, cell *params) /* 2 param */ +{ + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + edict_t *enemy = NULL; + if (pPlayer->ingame){ + enemy = pPlayer->pEdict->v.dmg_inflictor; + if (!FNullEnt(enemy)) { + int weapon = 0; + if (enemy->v.flags & (FL_CLIENT | FL_FAKECLIENT) ){ + pPlayer = GET_PLAYER_POINTER(enemy); + weapon = pPlayer->current; + } + else if( g_grenades.find( enemy, &pPlayer, weapon ) ) + enemy = pPlayer->pEdict; + else + enemy = NULL; + + if (enemy){ + switch(*params/sizeof(cell)){ + case 3: *get_amxaddr(amx,params[3]) = pPlayer->aiming; + case 2: *get_amxaddr(amx,params[2]) = weapon; + } + } + } + } + return (enemy ? pPlayer->index : 0); +} + +static cell AMX_NATIVE_CALL get_user_weapon(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame){ + int wpn = pPlayer->current; + cell *cpTemp = get_amxaddr(amx,params[2]); + *cpTemp = pPlayer->weapons[wpn].clip; + cpTemp = get_amxaddr(amx,params[3]); + *cpTemp = pPlayer->weapons[wpn].ammo; + return wpn; + } + return 0; +} + +static cell AMX_NATIVE_CALL get_user_ammo(AMX *amx, cell *params) /* 4 param */ +{ + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame){ + int wpn = params[2]; + if (wpn < 1 || wpn >= MAX_WEAPONS ){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + cell *cpTemp = get_amxaddr(amx,params[3]); + *cpTemp = pPlayer->weapons[wpn].clip; + cpTemp = get_amxaddr(amx,params[4]); + *cpTemp = pPlayer->weapons[wpn].ammo; + return 1; + } + return 0; +} + +static cell AMX_NATIVE_CALL get_user_team(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return -1; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame){ + if ( params[3] ) + set_amxstring(amx,params[2],pPlayer->team.str(),params[3]); + return pPlayer->teamId; + } + return -1; +} + +static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */ +{ + int ilen; + char* sMenu = get_amxstring(amx,params[3],0,ilen); + int menuid = g_menucmds.findMenuId( sMenu, amx ); + int keys = params[2]; + int time = params[4]; + if (params[1] == 0) { + for(int i = 1; i <= gpGlobals->maxClients; ++i){ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->ingame){ + pPlayer->keys = keys; + pPlayer->menu = menuid; + UTIL_ShowMenu(pPlayer->pEdict, keys, time, sMenu, ilen ); + } + } + } + else { + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame){ + pPlayer->keys = keys; + pPlayer->menu = menuid; + UTIL_ShowMenu(pPlayer->pEdict, keys, time, sMenu, ilen ); + } + } + return 1; +} + + + +static cell AMX_NATIVE_CALL register_plugin(AMX *amx, cell *params) /* 3 param */ +{ + CPluginMngr::CPlugin* a = g_plugins.findPluginFast( amx ); + int i; + a->setTitle( get_amxstring(amx,params[1],0,i) ); + a->setVersion( get_amxstring(amx,params[2],0,i) ); + a->setAuthor( get_amxstring(amx,params[3],0,i) ); + return 1; +} + +static cell AMX_NATIVE_CALL register_menucmd(AMX *amx, cell *params) /* 3 param */ +{ + CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx ); + int ilen, idx; + char* sptemp = get_amxstring(amx,params[3],0,ilen); + + if(amx_FindPublic(amx, sptemp ,&idx)!=AMX_ERR_NONE) { + print_srvconsole("[AMX] Function is not present (function \"%s\") (plugin \"%s\")\n",sptemp,plugin->getName() ); + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + + g_menucmds.registerMenuCmd( plugin , params[1] , params[2] , idx ); + + return 1; +} + +static cell AMX_NATIVE_CALL get_plugin(AMX *amx, cell *params) /* 11 param */ +{ + CPluginMngr::CPlugin* a; + + if ( params[1]<0 ) + a = g_plugins.findPluginFast( amx ); + else + a = g_plugins.findPlugin( (int)params[1] ); + + if (a){ + set_amxstring(amx,params[2],a->getName(),params[3]); + set_amxstring(amx,params[4],a->getTitle(),params[5]); + set_amxstring(amx,params[6],a->getVersion(),params[7]); + set_amxstring(amx,params[8],a->getAuthor(),params[9]); + set_amxstring(amx,params[10],a->getStatus(),params[11]); + return a->getId(); + } + return -1; +} + +static cell AMX_NATIVE_CALL get_pluginsnum(AMX *amx, cell *params) +{ + return g_plugins.getPluginsNum(); +} + + + +static cell AMX_NATIVE_CALL register_concmd(AMX *amx, cell *params) /* 4 param */ +{ + CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx ); + int i, idx = 0; + char* temp = get_amxstring(amx,params[2],0, i ); + if(amx_FindPublic(amx, temp ,&idx)!=AMX_ERR_NONE) { + print_srvconsole("[AMX] Function is not present (function \"%s\") (plugin \"%s\")\n",temp,plugin->getName() ); + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + temp = get_amxstring(amx,params[1],0, i ); + char* info = get_amxstring(amx,params[4],1, i ); + CmdMngr::Command* cmd; + int access = params[3]; + bool listable = true; + if ( access < 0 ) { // is access is -1 then hide from listing + access = 0; + listable = false; + } + if ( (cmd = g_commands.registerCommand( plugin , idx , temp , info , access ,listable )) == NULL) + return 0; + cmd->setCmdType( CMD_ConsoleCommand ); + + REG_SVR_COMMAND( (char*)cmd->getCommand() , plugin_srvcmd ); + return 1; +} + +static cell AMX_NATIVE_CALL register_clcmd(AMX *amx, cell *params) /* 4 param */ +{ + CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx ); + int i, idx = 0; + char* temp = get_amxstring(amx,params[2],0, i ); + if(amx_FindPublic(amx, temp ,&idx)!=AMX_ERR_NONE) { + print_srvconsole("[AMX] Function is not present (function \"%s\") (plugin \"%s\")\n",temp,plugin->getName() ); + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + temp = get_amxstring(amx,params[1],0, i ); + char* info = get_amxstring(amx,params[4],1, i ); + CmdMngr::Command* cmd; + int access = params[3]; + bool listable = true; + if ( access < 0 ) { // is access is -1 then hide from listing + access = 0; + listable = false; + } + if ( (cmd = g_commands.registerCommand(plugin , idx , temp , info , access , listable )) == NULL) + return 0; + cmd->setCmdType( CMD_ClientCommand ); + return 1; +} + +static cell AMX_NATIVE_CALL register_srvcmd(AMX *amx, cell *params) /* 2 param */ +{ + CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx ); + int i, idx = 0; + char* temp = get_amxstring(amx,params[2],0, i ); + if(amx_FindPublic(amx, temp ,&idx)!=AMX_ERR_NONE) { + print_srvconsole("[AMX] Function is not present (function \"%s\") (plugin \"%s\")\n",temp,plugin->getName() ); + amx_RaiseError(amx,AMX_ERR_NATIVE); + return NULL; + } + temp = get_amxstring(amx,params[1],0, i ); + char* info = get_amxstring(amx,params[4],1, i ); + CmdMngr::Command* cmd; + int access = params[3]; + bool listable = true; + if ( access < 0 ) { // is access is -1 then hide from listing + access = 0; + listable = false; + } + if ( (cmd = g_commands.registerCommand(plugin ,idx , temp , info ,access,listable )) == NULL) + return 0; + cmd->setCmdType( CMD_ServerCommand ); + REG_SVR_COMMAND( (char*)cmd->getCommand() , plugin_srvcmd ); + return 0; +} + +static cell AMX_NATIVE_CALL get_concmd(AMX *amx, cell *params) /* 7 param */ +{ + int who = params[8]; + + if ( who > 0 ) // id of player - client command + who = CMD_ClientCommand; + else if ( who == 0 ) // server + who = CMD_ServerCommand; + else // -1 parameter - all commands + who = CMD_ConsoleCommand; + + CmdMngr::Command* cmd = g_commands.getCmd(params[1] ,who , params[7] ); + + if ( cmd == 0 ) return 0; + set_amxstring(amx,params[2], cmd->getCmdLine() ,params[3]); + set_amxstring(amx,params[5], cmd->getCmdInfo() ,params[6]); + cell *cpFlags = get_amxaddr(amx,params[4]); + *cpFlags = cmd->getFlags(); + return 1; +} + +static cell AMX_NATIVE_CALL get_clcmd(AMX *amx, cell *params) /* 7 param */ +{ + CmdMngr::Command* cmd = g_commands.getCmd(params[1] ,CMD_ClientCommand , params[7]); + if ( cmd == 0 ) return 0; + set_amxstring(amx,params[2], cmd->getCmdLine() ,params[3]); + set_amxstring(amx,params[5], cmd->getCmdInfo() ,params[6]); + cell *cpFlags = get_amxaddr(amx,params[4]); + *cpFlags = cmd->getFlags(); + + return 1; +} + +static cell AMX_NATIVE_CALL get_srvcmd(AMX *amx, cell *params) +{ + CmdMngr::Command* cmd = g_commands.getCmd(params[1] ,CMD_ServerCommand , params[7] ); + if ( cmd == 0 ) return 0; + set_amxstring(amx,params[2], cmd->getCmdLine() ,params[3]); + set_amxstring(amx,params[5], cmd->getCmdInfo() ,params[6]); + cell *cpFlags = get_amxaddr(amx,params[4]); + *cpFlags = cmd->getFlags(); + return 1; +} + +static cell AMX_NATIVE_CALL get_srvcmdsnum(AMX *amx, cell *params) +{ + return g_commands.getCmdNum( CMD_ServerCommand , params[1] ); +} + +static cell AMX_NATIVE_CALL get_clcmdsnum(AMX *amx, cell *params) /* 1 param */ +{ + return g_commands.getCmdNum( CMD_ClientCommand , params[1] ); +} + +static cell AMX_NATIVE_CALL get_concmdsnum(AMX *amx, cell *params) /* 1 param */ +{ + int who = params[2]; + if ( who > 0 ) + return g_commands.getCmdNum( CMD_ClientCommand , params[1] ); + if ( who == 0 ) + return g_commands.getCmdNum( CMD_ServerCommand , params[1] ); + return g_commands.getCmdNum( CMD_ConsoleCommand , params[1] ); +} + + +static cell AMX_NATIVE_CALL register_event(AMX *amx, cell *params) /* 2 param */ +{ + CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx ); + + int len, pos, iFunction; + + char* sTemp = get_amxstring(amx,params[1],0,len); + + if ( (pos = g_events.getEventId( sTemp )) == 0 ) { + print_srvconsole("[AMX] Invalid event (name \"%s\") (plugin \"%s\")\n", sTemp , plugin->getName() ); + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + + sTemp = get_amxstring(amx,params[2],0,len); + + if ( amx_FindPublic(amx, sTemp , &iFunction) != AMX_ERR_NONE){ + print_srvconsole("[AMX] Function is not present (function \"%s\") (plugin \"%s\")\n",sTemp,plugin->getName() ); + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + + int numparam = *params/sizeof(cell); + + int flags = 0; + + if ( numparam > 2) + flags = UTIL_ReadFlags( get_amxstring(amx,params[3],0,len) ); + + EventsMngr::ClEvent* a = + g_events.registerEvent( plugin , iFunction , flags , pos ); + + if ( a == 0 ) return 0; + + for(int i = 4; i <= numparam; ++i) + a->registerFilter( get_amxstring(amx,params[i],0,len) ); + + return 1; +} + +static cell AMX_NATIVE_CALL user_kill(AMX *amx, cell *params) /* 2 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame && pPlayer->IsAlive()){ + int bef = pPlayer->pEdict->v.frags; + MDLL_ClientKill(pPlayer->pEdict); + if (params[2]) pPlayer->pEdict->v.frags = bef; + return 1; + } + + return 0; +} + +static cell AMX_NATIVE_CALL user_slap(AMX *amx, cell *params) /* 2 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + int power = abs((int)params[2]); + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame && pPlayer->IsAlive()){ + if (pPlayer->pEdict->v.health <= power) { + int bef = pPlayer->pEdict->v.frags; + MDLL_ClientKill(pPlayer->pEdict); + pPlayer->pEdict->v.frags = bef; + } + else { + edict_t *pEdict = pPlayer->pEdict; + int numparam = *params/sizeof(cell); + if (numparam<3 || params[3]) { + pEdict->v.velocity.x += RANDOM_LONG(-600,600); + pEdict->v.velocity.y += RANDOM_LONG(-180,180); + pEdict->v.velocity.z += RANDOM_LONG(100,200); + } + else { + Vector v_forward, v_right; + ANGLEVECTORS( pEdict->v.angles, v_forward, v_right, NULL ); + pEdict->v.velocity = pEdict->v.velocity + v_forward * 220 + Vector(0,0,200); + } + pEdict->v.punchangle.x = RANDOM_LONG(-10,10); + pEdict->v.punchangle.y = RANDOM_LONG(-10,10); + pEdict->v.health -= power; + int armor = (int)pEdict->v.armorvalue; + armor -= power; + if (armor < 0) armor = 0; + pEdict->v.armorvalue = armor; + pEdict->v.dmg_inflictor = pEdict; + if (g_bmod_cstrike){ + static const char *cs_sound[4] = { + "player/bhit_flesh-3.wav", + "player/bhit_flesh-2.wav", + "player/pl_die1.wav", + "player/pl_pain6.wav" }; + EMIT_SOUND_DYN2(pEdict, CHAN_VOICE, cs_sound[RANDOM_LONG(0,3)], 1.0, ATTN_NORM, 0, PITCH_NORM); + } + else{ + static const char *bit_sound[3] = { + "weapons/cbar_hitbod1.wav", + "weapons/cbar_hitbod2.wav", + "weapons/cbar_hitbod3.wav" }; + EMIT_SOUND_DYN2(pEdict, CHAN_VOICE, bit_sound[RANDOM_LONG(0,2)], 1.0, ATTN_NORM, 0, PITCH_NORM); + } + } + return 1; + } + + return 0; +} + +static cell AMX_NATIVE_CALL server_cmd(AMX *amx, cell *params) /* 1 param */ +{ + int len; + char* cmd = format_amxstring(amx,params,1,len); + cmd[len++]='\n'; + cmd[len]=0; + SERVER_COMMAND( cmd ); + return len; +} + +static cell AMX_NATIVE_CALL client_cmd(AMX *amx, cell *params) /* 2 param */ +{ + int len; + char* cmd = format_amxstring(amx,params,2,len); + cmd[len++]='\n'; + cmd[len]=0; + + if (params[1] == 0) { + for(int i = 1; i <= gpGlobals->maxClients; ++i){ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if (!pPlayer->bot && pPlayer->initialized /*&& pPlayer->ingame*/ ) + CLIENT_COMMAND(pPlayer->pEdict, cmd ); + } + } + else { + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if ( !pPlayer->bot && pPlayer->initialized /*&& pPlayer->ingame*/ ) + CLIENT_COMMAND(pPlayer->pEdict, cmd ); + } + return len; +} + +static cell AMX_NATIVE_CALL get_cvar_string(AMX *amx, cell *params) /* 3 param */ +{ + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + return set_amxstring(amx,params[2],CVAR_GET_STRING(sptemp),params[3]); +} + +static cell AMX_NATIVE_CALL get_cvar_float(AMX *amx, cell *params) /* 1 param */ +{ + int ilen; + float pFloat = CVAR_GET_FLOAT(get_amxstring(amx,params[1],0,ilen)); + return *(cell*)((void *)&pFloat); +} + +static cell AMX_NATIVE_CALL set_cvar_float(AMX *amx, cell *params) /* 2 param */ +{ + int ilen; + CVAR_SET_FLOAT(get_amxstring(amx,params[1],0,ilen),*(float *)((void *)¶ms[2])); + return 1; +} + +static cell AMX_NATIVE_CALL get_cvar_num(AMX *amx, cell *params) /* 1 param */ +{ + int ilen; + return (int)CVAR_GET_FLOAT(get_amxstring(amx,params[1],0,ilen)); +} + +static cell AMX_NATIVE_CALL set_cvar_num(AMX *amx, cell *params) /* 2 param */ +{ + int ilen; + CVAR_SET_FLOAT(get_amxstring(amx,params[1],0,ilen),(float)params[2]); + return 1; +} + +static cell AMX_NATIVE_CALL set_cvar_string(AMX *amx, cell *params) /* 2 param */ +{ + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + char* szValue = get_amxstring(amx,params[2],1,ilen); + CVAR_SET_STRING(sptemp,szValue); + return 1; +} + +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; +} + +static cell AMX_NATIVE_CALL log_message(AMX *amx, cell *params) /* 1 param */ +{ + int len; + char* message = format_amxstring(amx,params,1,len); + message[len++]='\n'; + message[len]=0; + ALERT( at_logged, "%s", message ); + return len; +} + +static cell AMX_NATIVE_CALL log_to_file(AMX *amx, cell *params) /* 1 param */ +{ + int ilen; + char* szFile = get_amxstring(amx,params[1],0,ilen); + FILE*fp; + const char* filename = build_pathname("%s/%s",g_log_dir.str(),szFile); + bool first_time = true; + if ((fp=fopen(filename,"r"))!=NULL){ + first_time = false; + fclose(fp); + } + if ((fp=fopen(filename,"a")) == NULL){ + //amx_RaiseError(amx,AMX_ERR_NATIVE); + //would cause too much troubles in old plugins + return 0; + } + char date[32]; + time_t td; time(&td); + strftime(date,31,"%m/%d/%Y - %H:%M:%S",localtime(&td)); + int len; + char* message = format_amxstring(amx,params,2,len); + message[len++]='\n'; + message[len]=0; + if ( first_time ){ + char game_dir[512]; + GET_GAME_DIR(game_dir); + filename = build_pathname("%s/%s",g_log_dir.str(),szFile); + fprintf(fp,"L %s: Log file started (file \"%s\") (game \"%s\") (amx \"%s\")\n", + date,filename,g_mod_name.str(),Plugin_info.version); + print_srvconsole("L %s: Log file started (file \"%s\") (game \"%s\") (amx \"%s\")\n", + date,filename,g_mod_name.str(),Plugin_info.version); + } + fprintf(fp,"L %s: %s",date,message); + print_srvconsole("L %s: %s",date,message); + fclose(fp); + return 1; +} + +static cell AMX_NATIVE_CALL num_to_word(AMX *amx, cell *params) /* 3 param */ +{ + char sptemp[512]; + UTIL_IntToString(params[1], sptemp); + return set_amxstring(amx,params[2],sptemp,params[3]); +} + + +static cell AMX_NATIVE_CALL get_timeleft(AMX *amx, cell *params) +{ + float flCvarTimeLimit = mp_timelimit->value; + + if (flCvarTimeLimit) { + int iReturn = (int)((g_game_timeleft + flCvarTimeLimit * 60.0) - gpGlobals->time); + return (iReturn < 0) ? 0 : iReturn; + } + + return 0; +} + +static cell AMX_NATIVE_CALL get_time(AMX *amx, cell *params) /* 3 param */ +{ + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + time_t td = time(NULL); + tm* lt = localtime(&td); + if ( lt == 0 ) { + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + char szDate[512]; + strftime(szDate,511,sptemp, lt ); + return set_amxstring(amx,params[2],szDate,params[3]); +} + +static cell AMX_NATIVE_CALL format_time(AMX *amx, cell *params) /* 3 param */ +{ + int ilen; + char* sptemp = get_amxstring(amx,params[3],0,ilen); + time_t tim = params[4]; + time_t td = ( tim != -1 ) ? tim : time(NULL); + tm* lt = localtime(&td); + if ( lt == 0 ) { + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + char szDate[512]; + strftime(szDate,511,sptemp, lt ); + return set_amxstring(amx,params[1],szDate,params[2]); + +} + +static cell AMX_NATIVE_CALL parse_time(AMX *amx, cell *params) /* 3 param */ +{ + int ilen; + char* sTime = get_amxstring(amx,params[1],1,ilen); + char* sFormat = get_amxstring(amx,params[2],0,ilen); + tm* mytime; + time_t td; + if ( params[3] == -1 ) { + td = time(NULL); + mytime = localtime(&td); + if ( mytime == 0 ){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + strptime (sTime,sFormat,mytime , 0 ); + } + else { + td = params[3]; + mytime = localtime(&td); + if ( mytime == 0 ){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + strptime (sTime,sFormat,mytime , 1 ); + } + return mktime(mytime); +} + +static cell AMX_NATIVE_CALL get_systime(AMX *amx, cell *params) /* 3 param */ +{ + time_t td = time(NULL); + td += params[1]; + return td; +} + +static cell AMX_NATIVE_CALL read_datanum(AMX *amx, cell *params) /* 0 param */ +{ + return g_events.getArgNum(); +} + +static cell AMX_NATIVE_CALL read_data(AMX *amx, cell *params) /* 3 param */ +{ + switch( *params/sizeof(cell) ) { + case 1: + return g_events.getArgInteger( params[1] ); + case 3: + return set_amxstring(amx,params[2], g_events.getArgString( params[1] ),*get_amxaddr(amx,params[3])); + default: + cell *fCell = get_amxaddr(amx,params[2]); + float *pFloat = (float *)((void *)fCell); + *pFloat = g_events.getArgFloat( params[1] ); + return (int)(*pFloat); + } +} + +static cell AMX_NATIVE_CALL get_playersnum(AMX *amx, cell *params) +{ + if (!params[1]) + return g_players_num; + + int a = 0; + for(int i = 1; i <= gpGlobals->maxClients; ++i){ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if ( pPlayer->initialized && (GETPLAYERUSERID(pPlayer->pEdict) > 0) ) + ++a; + } + + return a; +} + +static cell AMX_NATIVE_CALL get_players(AMX *amx, cell *params) /* 4 param */ +{ + int iNum = 0; + int ilen; + char* sptemp = get_amxstring(amx,params[3],0,ilen); + int flags = UTIL_ReadFlags(sptemp); + + cell *aPlayers = get_amxaddr(amx,params[1]); + cell *iMax = get_amxaddr(amx,params[2]); + + int team; + + if (flags & 48) { + sptemp = get_amxstring(amx,params[4],0,ilen); + + if ( flags & 16 ) { + if (flags & 64) + team = g_teamsIds.findTeamId( sptemp ); + else + team = g_teamsIds.findTeamIdCase( sptemp ); + } + } + + for(int i = 1; i <= gpGlobals->maxClients; ++i){ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->ingame){ + if (pPlayer->IsAlive() ? (flags & 2) : (flags & 1)) + continue; + if (pPlayer->bot ? (flags & 4) : (flags & 8)) + continue; + if ((flags & 16) && (pPlayer->teamId != team) ) + continue; + /*if ( flags & 16 ) { + if (flags & 64){ + if (strcmpi(pPlayer->team.str(),sptemp)) + continue; + } + else if (strcmp(pPlayer->team.str(),sptemp)) + continue; + }*/ + if (flags & 32){ + if (flags & 64){ + if (stristr(pPlayer->name.str(),sptemp)==NULL) + continue; + } + else if (strstr(pPlayer->name.str(),sptemp)==NULL) + continue; + } + aPlayers[iNum++] = i; + } + } + + *iMax = iNum; + return 1; +} + +static cell AMX_NATIVE_CALL find_player(AMX *amx, cell *params) /* 1 param */ +{ + int ilen, userid = 0; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + int flags = UTIL_ReadFlags(sptemp); + if (flags&31) + sptemp = get_amxstring(amx,params[2],0,ilen); + else if (flags&1024) + userid = *get_amxaddr(amx,params[2]); + // a b c d e f g h i j k l + int result = 0; + for(int i = 1; i <= gpGlobals->maxClients; ++i){ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->ingame){ + if (pPlayer->IsAlive()?(flags&64):(flags&32)) + continue; + if (pPlayer->bot?(flags&128):(flags&256)) + continue; + if (flags&1){ + if (flags&2048) { + if (strcmpi(pPlayer->name.str(),sptemp)) + continue; + } + else if (strcmp(pPlayer->name.str(),sptemp)) + continue; + } + if (flags&2){ + if (flags&2048) { + if (stristr(pPlayer->name.str(),sptemp)==NULL) + continue; + } + else if (strstr(pPlayer->name.str(),sptemp)==NULL) + continue; + } + if (flags&4){ + const char* authid = GETPLAYERAUTHID(pPlayer->pEdict); + if (!authid || strcmp(authid,sptemp)) + continue; + } + if (flags&1024){ + if (userid != GETPLAYERUSERID(pPlayer->pEdict)) + continue; + } + if (flags&8){ + if (strncmp(pPlayer->ip.str(),sptemp,ilen)) + continue; + } + if (flags&16){ + if (flags&2048) { + if (strcmpi(pPlayer->team.str(),sptemp)) + continue; + } + else if (strcmp(pPlayer->team.str(),sptemp)) + continue; + } + result = i; + if ((flags&512)==0) + break; + } + } + + return result; +} + +static cell AMX_NATIVE_CALL get_maxplayers(AMX *amx, cell *params) +{ + return gpGlobals->maxClients; +} + +static cell AMX_NATIVE_CALL get_gametime(AMX *amx, cell *params) +{ + float pFloat = gpGlobals->time; + return *(cell*)((void *)&pFloat); +} + +static cell AMX_NATIVE_CALL get_mapname(AMX *amx, cell *params) /* 2 param */ +{ + return set_amxstring(amx,params[1],STRING(gpGlobals->mapname),params[2]); +} + +static cell AMX_NATIVE_CALL get_modname(AMX *amx, cell *params) /* 2 param */ +{ + return set_amxstring(amx,params[1],g_mod_name.str(),params[2]); +} + + +static cell AMX_NATIVE_CALL get_localinfo(AMX *amx, cell *params) /* 3 param */ +{ + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + return set_amxstring(amx,params[2],LOCALINFO(sptemp),params[3]); +} + +static cell AMX_NATIVE_CALL set_localinfo(AMX *amx, cell *params) /* 2 param */ +{ + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + char* szValue = get_amxstring(amx,params[2],1,ilen); + SET_LOCALINFO(sptemp,szValue); + return 1; +} + +static cell AMX_NATIVE_CALL get_user_info(AMX *amx, cell *params) /* 4 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + int ilen; + char* sptemp = get_amxstring(amx,params[2],0,ilen); + return set_amxstring(amx,params[3],ENTITY_KEYVALUE(pPlayer->pEdict,sptemp ),params[4]); + return 1; +} + +static cell AMX_NATIVE_CALL set_user_info(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + int ilen; + char* sptemp = get_amxstring(amx,params[2],0,ilen); + char* szValue = get_amxstring(amx,params[3],1,ilen); + ENTITY_SET_KEYVALUE(pPlayer->pEdict,sptemp,szValue); + return 1; +} + +static cell AMX_NATIVE_CALL read_argc(AMX *amx, cell *params) +{ + return CMD_ARGC(); +} + +static cell AMX_NATIVE_CALL read_argv(AMX *amx, cell *params) /* 3 param */ +{ + return set_amxstring(amx,params[2], /*( params[1] < 0 || + params[1] >= CMD_ARGC() ) ? "" : */CMD_ARGV(params[1]) , params[3]); +} + +static cell AMX_NATIVE_CALL read_args(AMX *amx, cell *params) /* 2 param */ +{ + const char* sValue = CMD_ARGS(); + return set_amxstring(amx,params[1],sValue ? sValue : "",params[2]); +} + +static cell AMX_NATIVE_CALL get_user_msgid(AMX *amx, cell *params) /* 1 param */ +{ + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + return GET_USER_MSG_ID(PLID, sptemp , NULL ); +} + +static cell AMX_NATIVE_CALL set_task(AMX *amx, cell *params) /* 2 param */ +{ + + CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); + + int a, iFunc; + + char* stemp = get_amxstring(amx,params[2],1, a ); + + if (amx_FindPublic(amx, stemp , &iFunc) != AMX_ERR_NONE){ + print_srvconsole("[AMX] Function is not present (function \"%s\") (plugin \"%s\")\n",stemp,plugin->getName() ); + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + + float base = *(float *)((void *)¶ms[1]); + + if ( base < 0.1 ) + base = 0.1; + + char* temp = get_amxstring(amx,params[6],0,a); + + g_tasksMngr.registerTask( plugin , + iFunc , UTIL_ReadFlags(temp), params[3], base , + gpGlobals->time + base , params[5] , + get_amxaddr(amx,params[4]) , params[7] ); + + return 1; +} + +static cell AMX_NATIVE_CALL remove_task(AMX *amx, cell *params) /* 1 param */ +{ + return g_tasksMngr.removeTasks( params[1] , params[2] ? 0 : amx ); +} + +static cell AMX_NATIVE_CALL task_exists(AMX *amx, cell *params) /* 1 param */ +{ + return g_tasksMngr.taskExists( params[1] , params[2] ? 0 : amx ); +} + +static cell AMX_NATIVE_CALL cvar_exists(AMX *amx, cell *params) /* 1 param */ +{ + int ilen; + return (CVAR_GET_POINTER(get_amxstring(amx,params[1],0,ilen))?1:0); +} + +static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params) /* 3 param */ +{ + int i; + char* temp = get_amxstring(amx,params[1],0,i); + + if ( !g_cvars.find( temp ) ) + { + CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); + CCVar* cvar = new CCVar( temp , plugin->getName() , params[3] , + *(float *)((void *)¶ms[4]) ); + + if ( cvar == 0 ) + return 0; + + g_cvars.put( cvar ); + + if ( CVAR_GET_POINTER(temp) == 0 ) + CVAR_REGISTER( cvar->getCvar() ); + + CVAR_SET_STRING( temp ,get_amxstring(amx,params[2],1,i)); + return 1; + } + + return 0; +} + +static cell AMX_NATIVE_CALL get_user_ping(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame){ + cell *cpPing = get_amxaddr(amx,params[2]); + cell *cpLoss = get_amxaddr(amx,params[3]); + int ping, loss; + PLAYER_CNX_STATS(pPlayer->pEdict , &ping, &loss); + *cpPing = ping; + *cpLoss = loss; + return 1; + } + return 0; +} + +static cell AMX_NATIVE_CALL get_user_time(AMX *amx, cell *params) /* 1 param */ +{ + int index = params[1]; + if (index<1||index>gpGlobals->maxClients) + return 0; + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame){ + int time = (int)(gpGlobals->time - (params[2] ? pPlayer->playtime : pPlayer->time)); + return time; + } + return 0; +} + +static cell AMX_NATIVE_CALL server_exec(AMX *amx, cell *params) +{ + SERVER_EXECUTE( ); + return 1; +} + +static cell AMX_NATIVE_CALL engclient_cmd(AMX *amx, cell *params) /* 4 param */ +{ + int ilen; + const char* szCmd = get_amxstring(amx,params[2],0,ilen); + const char* sArg1 = get_amxstring(amx,params[3],1,ilen); + if ( ilen == 0 ) sArg1 = 0; + const char* sArg2 = get_amxstring(amx,params[4],2,ilen); + if ( ilen == 0 ) sArg2 = 0; + if (params[1] == 0) { + for(int i = 1; i <= gpGlobals->maxClients; ++i){ + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->ingame /*&& pPlayer->initialized */) + UTIL_FakeClientCommand(pPlayer->pEdict, szCmd,sArg1,sArg2); + } + } + else { + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if ( /*pPlayer->initialized && */pPlayer->ingame ) + UTIL_FakeClientCommand(pPlayer->pEdict, szCmd,sArg1,sArg2); + } + return 1; +} + +static cell AMX_NATIVE_CALL pause(AMX *amx, cell *params) /* 3 param */ +{ + int ilen; + char* temp = get_amxstring(amx,params[1],0,ilen); + int flags = UTIL_ReadFlags(temp); + + CPluginMngr::CPlugin *plugin = 0; + + if ( flags & 2 ) { // pause function + if (flags&4){ //look out side the plugin + temp = get_amxstring(amx,params[3],0,ilen); + plugin = g_plugins.findPlugin(temp); + } + else plugin = g_plugins.findPluginFast(amx); + if ( !plugin ) return 0; // plugin not found + temp = get_amxstring(amx,params[2],0,ilen); + int err, index; + if ((err = amx_FindPublic( plugin->getAMX(), temp , &index) )!= AMX_ERR_NONE){ + print_srvconsole("[AMX] Function is not present (function \"%s\") (plugin \"%s\")\n", temp,plugin->getName() ); + return 0; + } + plugin->pauseFunction( index ); + return 1; + } + else if (flags&4){ + temp = get_amxstring(amx,params[2],0,ilen); + plugin = g_plugins.findPlugin(temp); + } + else + plugin = g_plugins.findPluginFast(amx); + if ( plugin && plugin->isValid() ){ + if ( flags & 8 ) + plugin->setStatus( ps_stopped ); + else if ( flags & 16 ) + plugin->setStatus( ps_locked ); + else + plugin->pausePlugin(); + return 1; + } + return 0; +} + +static cell AMX_NATIVE_CALL unpause(AMX *amx, cell *params) /* 3 param */ +{ + + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + int flags = UTIL_ReadFlags(sptemp); + CPluginMngr::CPlugin *plugin = 0; + if (flags&2) { + if (flags&4){ + sptemp = get_amxstring(amx,params[3],0,ilen); + plugin = g_plugins.findPlugin(sptemp); + } + else + plugin = g_plugins.findPluginFast(amx); + if ( !plugin ) return 0; + sptemp = get_amxstring(amx,params[2],0,ilen); + int err, index; + if ((err = amx_FindPublic(plugin->getAMX(), sptemp , &index) )!= AMX_ERR_NONE){ + print_srvconsole("[AMX] Function is not present (function \"%s\") (plugin \"%s\")\n", sptemp,plugin->getName() ); + return 0; + } + plugin->unpauseFunction( index ); + return 1; + } + else if (flags&4){ + sptemp = get_amxstring(amx,params[2],0,ilen); + plugin = g_plugins.findPlugin(sptemp); + } + else + plugin = g_plugins.findPluginFast( amx); + if (plugin && plugin->isValid()) { + plugin->unpausePlugin(); + return 1; + } + + return 0; + +} + +static cell AMX_NATIVE_CALL read_flags(AMX *amx, cell *params) /* 1 param */ +{ + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + return UTIL_ReadFlags(sptemp); +} + +static cell AMX_NATIVE_CALL get_flags(AMX *amx, cell *params) /* 1 param */ +{ + char flags[32]; + UTIL_GetFlags( flags , params[1] ); + return set_amxstring(amx,params[2],flags,params[3]); +} + +static cell AMX_NATIVE_CALL get_user_flags(AMX *amx, cell *params) /* 2 param */ +{ + int index = params[1]; + if (index<0||index>gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + int id = params[2]; + if (id < 0) id = 0; + if (id > 31) id = 31; + return GET_PLAYER_POINTER_I(index)->flags[id]; +} + +static cell AMX_NATIVE_CALL set_user_flags(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + if (index < 0 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + int flag = params[2]; + int id = params[3]; + if (id < 0) id = 0; + if (id > 31) id = 31; + pPlayer->flags[id] |= flag; + return 1; +} + +static cell AMX_NATIVE_CALL remove_user_flags(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + if (index < 0 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + int flag = params[2]; + int id = params[3]; + if (id < 0) id = 0; + if (id > 31) id = 31; + pPlayer->flags[id] &= ~flag; + return 1; +} + +static cell AMX_NATIVE_CALL register_menuid(AMX *amx, cell *params) /* 1 param */ +{ + int i; + char* temp = get_amxstring(amx,params[1],0,i); + AMX* a = (*params/sizeof(cell) < 2 || params[2] ) ? 0 : amx; + return g_menucmds.registerMenuId( temp , a ); +} + +static cell AMX_NATIVE_CALL get_user_menu(AMX *amx, cell *params) /* 3 param */ +{ + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + cell *cpMenu = get_amxaddr(amx,params[2]); + cell *cpKeys = get_amxaddr(amx,params[3]); + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + if (pPlayer->ingame){ + *cpMenu = pPlayer->menu; + *cpKeys = pPlayer->keys; + return 1; + } + return 0; +} + +static cell AMX_NATIVE_CALL precache_sound(AMX *amx, cell *params) /* 1 param */ +{ + if ( g_dontprecache ) { + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + PRECACHE_SOUND((char*)STRING(ALLOC_STRING(sptemp))); + return 1; +} + +static cell AMX_NATIVE_CALL precache_model(AMX *amx, cell *params) /* 1 param */ +{ + if ( g_dontprecache ) { + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + int ilen; + char* sptemp = get_amxstring(amx,params[1],0,ilen); + return PRECACHE_MODEL((char*)STRING(ALLOC_STRING(sptemp))); +} + +static cell AMX_NATIVE_CALL get_distance(AMX *amx, cell *params) /* 2 param */ +{ + cell *cpVec1 = get_amxaddr(amx,params[1]); + cell *cpVec2 = get_amxaddr(amx,params[2]); + Vector vec1 = Vector(cpVec1[0],cpVec1[1],cpVec1[2]); + Vector vec2 = Vector(cpVec2[0],cpVec2[1],cpVec2[2]); + int iDist = (int)((vec1 - vec2).Length()); + return iDist; +} + +static cell AMX_NATIVE_CALL random_float(AMX *amx, cell *params) /* 2 param */ +{ + float one = *(float *)((void *)¶ms[1]); + float two = *(float *)((void *)¶ms[2]); + float fRnd = RANDOM_FLOAT(one,two); + return *(cell*)((void *)&fRnd); +} + +static cell AMX_NATIVE_CALL random_num(AMX *amx, cell *params) /* 2 param */ +{ + return RANDOM_LONG(params[1],params[2]); +} + +static cell AMX_NATIVE_CALL remove_quotes(AMX *amx, cell *params) /* 1 param */ +{ + cell *text = get_amxaddr(amx,params[1]); + if (*text=='\"') { + register cell *temp = text; + int len = 0; + while(*temp++) ++len; // get length + cell *src = text; + if ( src[len-1]=='\r' ) + src[--len] = 0; + if (src[--len]=='\"'){ + src[len] = 0; + temp = src+1; + while((*src++ = *temp++)) + ; + return 1; + } + } + return 0; +} + +static cell AMX_NATIVE_CALL get_user_aiming(AMX *amx, cell *params) /* 4 param */ +{ + int index = params[1]; + if (index < 1 || index > gpGlobals->maxClients){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + cell *cpId = get_amxaddr(amx,params[2]); + cell *cpBody = get_amxaddr(amx,params[3]); + cell fCell; + float *pFloat = (float *)((void *)&fCell); + *pFloat = 0.0; + if (pPlayer->ingame) { + edict_t* edict = pPlayer->pEdict; + Vector v_forward; + Vector v_src = edict->v.origin + edict->v.view_ofs; + ANGLEVECTORS( edict->v.v_angle , v_forward, NULL, NULL ); + TraceResult trEnd; + Vector v_dest = v_src + v_forward * params[4]; + TRACE_LINE( v_src , v_dest, 0 , edict, &trEnd ); + *cpId = FNullEnt(trEnd.pHit) ? 0 : ENTINDEX(trEnd.pHit); + *cpBody = trEnd.iHitgroup; + if (trEnd.flFraction < 1.0) { + *pFloat = (trEnd.vecEndPos - v_src).Length(); + return fCell; + } + else { + return fCell; + } + } + *cpId = 0; + *cpBody = 0; + return fCell; +} + +static cell AMX_NATIVE_CALL remove_cvar_flags(AMX *amx, cell *params) +{ + int ilen; + char* sCvar = get_amxstring(amx,params[1],0,ilen); + if ( !strcmp(sCvar,"amx_version") || + !strcmp(sCvar,"fun_version") || !strcmp(sCvar,"sv_cheats") ) + return 0; + cvar_t* pCvar = CVAR_GET_POINTER(sCvar); + if (pCvar) { + pCvar->flags &= ~((int)(params[2])); + return 1; + } + return 0; +} + +static cell AMX_NATIVE_CALL get_cvar_flags(AMX *amx, cell *params) +{ + int ilen; + char* sCvar = get_amxstring(amx,params[1],0,ilen); + cvar_t* pCvar = CVAR_GET_POINTER(sCvar); + return pCvar ? pCvar->flags : 0; +} + +static cell AMX_NATIVE_CALL set_cvar_flags(AMX *amx, cell *params) +{ + int ilen; + char* sCvar = get_amxstring(amx,params[1],0,ilen); + if ( !strcmp(sCvar,"amx_version") || + !strcmp(sCvar,"fun_version") || !strcmp(sCvar,"sv_cheats") ) + return 0; + cvar_t* pCvar = CVAR_GET_POINTER(sCvar); + if (pCvar) { + pCvar->flags |= (int)(params[2]); + return 1; + } + return 0; +} + +static cell AMX_NATIVE_CALL force_unmodified(AMX *amx, cell *params) +{ + int a; + cell *cpVec1 = get_amxaddr(amx,params[2]); + cell *cpVec2 = get_amxaddr(amx,params[3]); + Vector vec1 = Vector(cpVec1[0],cpVec1[1],cpVec1[2]); + Vector vec2 = Vector(cpVec2[0],cpVec2[1],cpVec2[2]); + char* filename = get_amxstring(amx,params[4],0,a); + + ForceObject* aaa = new ForceObject(filename , (FORCE_TYPE)((int)(params[1])) , vec1 , vec2 , amx); + + if ( aaa ) + { + if ( stristr(filename,".wav") ) + g_forcesounds.put( aaa ); + else if ( stristr(filename,".mdl") ) + g_forcemodels.put( aaa ); + else + g_forcegeneric.put( aaa ); + + return 1; + } + return 0; +} + + +static cell AMX_NATIVE_CALL read_logdata(AMX *amx, cell *params) +{ + return set_amxstring(amx,params[1], g_logevents.getLogString() ,params[2]); +} + +static cell AMX_NATIVE_CALL read_logargc(AMX *amx, cell *params) +{ + return g_logevents.getLogArgNum(); +} + +static cell AMX_NATIVE_CALL read_logargv(AMX *amx, cell *params) +{ + return set_amxstring(amx,params[2],g_logevents.getLogArg(params[1]),params[3]); +} + +static cell AMX_NATIVE_CALL parse_loguser(AMX *amx, cell *params) +{ + int len; + char *text = get_amxstring(amx,params[1],0,len); + if ( len < 6 ) { // no user to parse!? + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } +/******** GET TEAM **********/ + char* end = text + --len; + *end = 0; + while ( *end!='<' && len-- ) + --end; + ++end; + cell *cPtr = get_amxaddr(amx,params[7]); + int max = params[8]; // get TEAM +// print_srvconsole("Got team: %s (Len %d)\n",end,len); + while ( max-- && *end ) + *cPtr++ = *end++; + *cPtr = 0; +/******** GET AUTHID **********/ + if ( len <= 0 ) { + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + end = text + --len; + *end = 0; + while ( *end!='<' && len-- ) + --end; + ++end; + cPtr = get_amxaddr(amx,params[5]); + max = params[6]; // get AUTHID + // print_srvconsole("Got auth: %s (Len %d)\n",end,len); + while ( max-- && *end ) + *cPtr++ = *end++; + *cPtr = 0; +/******** GET USERID **********/ + if ( len <= 0 ) { + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + end = text + --len; + *end = 0; + while ( *end!='<' && len-- ) + --end; +// print_srvconsole("Got userid: %s (Len %d)\n",end + 1,len); + if ( *(cPtr = get_amxaddr(amx,params[4])) != -2 ) + *cPtr = atoi( end + 1 ); +/******** GET NAME **********/ + *end = 0; + cPtr = get_amxaddr(amx,params[2]); + max = params[3]; // get NAME +// print_srvconsole("Got name: %s (Len %d)\n",text,len); + while ( max-- && *text ) + *cPtr++ = *text++; + *cPtr = 0; + return 1; +} + +static cell AMX_NATIVE_CALL register_logevent(AMX *amx, cell *params) +{ + CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); + + int a, iFunc; + + char* temp = get_amxstring(amx,params[1],0, a ); + + if (amx_FindPublic(amx, temp , &iFunc) != AMX_ERR_NONE){ + print_srvconsole("[AMX] Function is not present (function \"%s\") (plugin \"%s\")\n", + temp,plugin->getName() ); + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + + LogEventsMngr::CLogEvent* r = + g_logevents.registerLogEvent( plugin , iFunc, params[2] ); + + if ( r == 0 ) return 0; + + int numparam = *params/sizeof(cell); + + for(int i = 3; i <= numparam; ++i) + r->registerFilter( get_amxstring(amx,params[i],0, a ) ); + + return 1; +} + + + +AMX_NATIVE_INFO amxmod_Natives[] = { + { "client_cmd", client_cmd }, + { "client_print", client_print }, + { "console_cmd", console_cmd }, + { "console_print", console_print }, + { "cvar_exists", cvar_exists }, + { "emit_sound", emit_sound }, + { "engclient_cmd", engclient_cmd }, + { "engclient_print", engclient_print }, + { "find_player", find_player }, + { "force_unmodified", force_unmodified }, + { "format_time", format_time}, + { "get_clcmd", get_clcmd}, + { "get_clcmdsnum", get_clcmdsnum}, + { "get_concmd", get_concmd}, + { "get_concmdsnum", get_concmdsnum}, + { "get_cvar_flags", get_cvar_flags }, + { "get_cvar_float", get_cvar_float }, + { "get_cvar_num", get_cvar_num }, + { "get_cvar_string", get_cvar_string }, + { "get_distance", get_distance }, + { "get_flags", get_flags }, + { "get_gametime", get_gametime}, + { "get_localinfo", get_localinfo}, + { "get_mapname", get_mapname}, + { "get_maxplayers", get_maxplayers }, + { "get_modname", get_modname}, + { "get_players", get_players }, + { "get_playersnum", get_playersnum }, + { "get_plugin", get_plugin }, + { "get_pluginsnum", get_pluginsnum }, + { "get_srvcmd", get_srvcmd }, + { "get_srvcmdsnum", get_srvcmdsnum }, + { "get_systime", get_systime}, + { "get_time", get_time}, + { "get_timeleft", get_timeleft}, + { "get_user_aiming", get_user_aiming }, + { "get_user_ammo", get_user_ammo}, + { "get_user_armor", get_user_armor }, + { "get_user_attacker",get_user_attacker }, + { "get_user_authid", get_user_authid }, + { "get_user_deaths", get_user_deaths }, + { "get_user_flags", get_user_flags }, + { "get_user_frags", get_user_frags }, + { "get_user_health", get_user_health }, + { "get_user_index", get_user_index }, + { "get_user_info", get_user_info }, + { "get_user_ip", get_user_ip }, + { "get_user_menu", get_user_menu}, + { "get_user_msgid", get_user_msgid}, + { "get_user_name", get_user_name }, + { "get_user_origin", get_user_origin}, + { "get_user_ping", get_user_ping }, + { "get_user_team", get_user_team }, + { "get_user_time", get_user_time }, + { "get_user_userid", get_user_userid }, + { "get_user_weapon", get_user_weapon}, + { "get_user_weapons", get_user_weapons}, + { "get_user_wonid", get_user_wonid}, + { "get_weaponname", get_weaponname}, + { "get_xvar_float", get_xvar_num }, + { "get_xvar_id", get_xvar_id }, + { "get_xvar_num", get_xvar_num }, + { "is_dedicated_server",is_dedicated_server }, + { "is_linux_server", is_linux_server }, + { "is_user_authorized", is_user_authorized }, + { "is_map_valid", is_map_valid }, + { "is_user_alive", is_user_alive }, + { "is_user_bot", is_user_bot }, + { "is_user_connected", is_user_connected }, + { "is_user_connecting", is_user_connecting }, + { "is_user_hltv", is_user_hltv }, + { "log_message", log_message }, + { "log_to_file", log_to_file }, + { "message_begin", message_begin }, + { "message_end", message_end }, + { "num_to_word", num_to_word }, + { "parse_loguser", parse_loguser }, + { "parse_time", parse_time }, + { "pause", pause }, + { "precache_model", precache_model }, + { "precache_sound", precache_sound }, + { "random_float", random_float }, + { "random_num", random_num }, + { "read_argc", read_argc }, + { "read_args", read_args }, + { "read_argv", read_argv }, + { "read_data", read_data }, + { "read_datanum", read_datanum }, + { "read_flags", read_flags }, + { "read_logargc", read_logargc }, + { "read_logargv", read_logargv }, + { "read_logdata", read_logdata }, + { "register_clcmd", register_clcmd }, + { "register_concmd", register_concmd }, + { "register_cvar", register_cvar }, + { "register_event", register_event }, + { "register_logevent",register_logevent}, + { "register_menucmd", register_menucmd }, + { "register_menuid", register_menuid }, + { "register_plugin", register_plugin }, + { "register_srvcmd", register_srvcmd }, + { "remove_cvar_flags", remove_cvar_flags }, + { "remove_quotes", remove_quotes }, + { "remove_task", remove_task }, + { "remove_user_flags", remove_user_flags }, + { "server_cmd", server_cmd }, + { "server_exec", server_exec }, + { "server_print", server_print }, + { "set_cvar_flags", set_cvar_flags }, + { "set_cvar_float", set_cvar_float }, + { "set_cvar_num", set_cvar_num }, + { "set_cvar_string", set_cvar_string }, + { "set_hudmessage", set_hudmessage }, + { "set_localinfo", set_localinfo}, + { "set_task", set_task }, + { "set_user_flags", set_user_flags}, + { "set_user_info", set_user_info }, + { "set_xvar_float", set_xvar_num }, + { "set_xvar_num", set_xvar_num }, + { "show_hudmessage", show_hudmessage }, + { "show_menu", show_menu }, + { "show_motd", show_motd }, + { "task_exists", task_exists }, + { "unpause", unpause }, + { "user_kill", user_kill }, + { "user_slap", user_slap }, + { "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 }, + { "xvar_exists", xvar_exists }, + { NULL, NULL } +}; \ No newline at end of file diff --git a/amxmodx/amxmod.h b/amxmodx/amxmod.h new file mode 100755 index 00000000..6acbfc97 --- /dev/null +++ b/amxmodx/amxmod.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef AMXMOD_H +#define AMXMOD_H + +#include "modules.h" +#include "CString.h" +#include "CList.h" +#include "CPlugin.h" +#include "CMisc.h" +#include "CVault.h" +#include "CModule.h" +#include "CTask.h" +#include "CLogEvent.h" +#include "CForward.h" +#include "CCmd.h" +#include "CMenu.h" +#include "CEvent.h" + +#define AMX_VERSION "0.9.7" + +#ifdef __cplusplus +extern "C" { +#endif + extern AMX_NATIVE_INFO core_Natives[]; + extern AMX_NATIVE_INFO time_Natives[]; + extern AMX_NATIVE_INFO power_Natives[]; +#ifdef __cplusplus +} +#endif +extern AMX_NATIVE_INFO amxmod_Natives[]; +extern AMX_NATIVE_INFO file_Natives[]; +extern AMX_NATIVE_INFO float_Natives[]; +extern AMX_NATIVE_INFO string_Natives[]; +extern AMX_NATIVE_INFO vault_Natives[]; + + +#ifndef __linux__ +#define DLLOAD(path) (DLHANDLE)LoadLibrary(path); +#define DLPROC(m,func) GetProcAddress(m,func); +#define DLFREE(m) FreeLibrary(m); +#else +#define DLLOAD(path) (DLHANDLE)dlopen(path, RTLD_NOW); +#define DLPROC(m,func) dlsym(m,func); +#define DLFREE(m) dlclose(m); +#endif + +#ifndef __linux__ +typedef HINSTANCE DLHANDLE; +#else +typedef void* DLHANDLE; +#endif + +#ifndef GETPLAYERAUTHID +#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId) +#endif +#define ANGLEVECTORS (*g_engfuncs.pfnAngleVectors) +#define CLIENT_PRINT (*g_engfuncs.pfnClientPrintf) +#define CVAR_DIRECTSET (*g_engfuncs.pfnCvar_DirectSet) +#define GETCLIENTLISTENING (*g_engfuncs.pfnVoice_GetClientListening) +#define RUNPLAYERMOVE (*g_engfuncs.pfnRunPlayerMove) +#define SETCLIENTLISTENING (*g_engfuncs.pfnVoice_SetClientListening) +#define SETCLIENTMAXSPEED (*g_engfuncs.pfnSetClientMaxspeed) + +char* UTIL_SplitHudMessage(register const char *src); +int UTIL_ReadFlags(const char* c); +void UTIL_ClientPrint( edict_t *pEntity, int msg_dest, char *msg ); +void UTIL_FakeClientCommand(edict_t *pEdict, const char *cmd, const char *arg1 = NULL, const char *arg2 = NULL); +void UTIL_GetFlags(char* flags,int flag); +void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, char *pMessage); +void UTIL_IntToString(int value, char *output); +void UTIL_ShowMOTD( edict_t *client , char *motd, int mlen, const char *name); +void UTIL_ShowMenu( edict_t* pEntity, int slots, int time, char *menu, int mlen ); + +#define GET_PLAYER_POINTER(e) (&g_players[ENTINDEX(e)]) +//#define GET_PLAYER_POINTER(e) (&g_players[(((int)e-g_edict_point)/sizeof(edict_t ))]) +#define GET_PLAYER_POINTER_I(i) (&g_players[i]) + +struct WeaponsVault { + String fullName; + short int iId; + short int ammoSlot; +}; + +struct fakecmd_t { + char args[256]; + const char *argv[3]; + //char argv[3][128]; + int argc; + bool fake; +}; + + +extern CPluginMngr g_plugins; +extern CTaskMngr g_tasksMngr; +extern CPlayer g_players[33]; +extern CPlayer* mPlayer; +extern CmdMngr g_commands; +extern CList g_cvars; +extern CList g_forcemodels; +extern CList g_forcesounds; +extern CList g_forcegeneric; +extern CList g_modules; +extern CList g_auth; +extern EventsMngr g_events; +extern Grenades g_grenades; +extern LogEventsMngr g_logevents; +extern MenuMngr g_menucmds; +extern String g_log_dir; +extern String g_mod_name; +extern TeamIds g_teamsIds; +extern Vault g_vault; +extern CForwardMngr g_forwards; +extern WeaponsVault g_weaponsData[MAX_WEAPONS]; +extern XVars g_xvars; +extern bool g_bmod_cstrike; +extern bool g_bmod_dod; +extern bool g_dontprecache; +extern bool g_initialized; +extern int g_srvindex; +extern cvar_t* amx_version; +extern cvar_t* hostname; +extern cvar_t* mp_timelimit; +extern fakecmd_t g_fakecmd; +extern float g_game_restarting; +extern float g_game_timeleft; +extern float g_task_time; +extern float g_auth_time; +extern hudtextparms_t g_hudset; +//extern int g_edict_point; +extern int g_players_num; +extern int mPlayerIndex; +extern int mState; +extern void (*endfunction)(void*); +extern void (*function)(void*); + +typedef void (*funEventCall)(void*); +extern funEventCall modMsgsEnd[MAX_REG_MSGS]; +extern funEventCall modMsgs[MAX_REG_MSGS]; + +extern int gmsgAmmoPickup; +extern int gmsgAmmoX; +extern int gmsgBattery; +extern int gmsgCurWeapon; +extern int gmsgDamage; +extern int gmsgDeathMsg; +extern int gmsgHealth; +extern int gmsgMOTD; +extern int gmsgScoreInfo; +extern int gmsgSendAudio; +extern int gmsgServerName; +extern int gmsgShowMenu; +extern int gmsgTeamInfo; +extern int gmsgTextMsg; +extern int gmsgVGUIMenu; +extern int gmsgWeapPickup; +extern int gmsgWeaponList; +extern int gmsgintermission; +extern int gmsgResetHUD; +extern int gmsgRoundTime; + +void Client_AmmoPickup(void*); +void Client_AmmoX(void*); +void Client_CurWeapon(void*); +void Client_ScoreInfo(void*); +void Client_ShowMenu(void*); +void Client_TeamInfo(void*); +void Client_TextMsg(void*); +void Client_VGUIMenu(void*); +void Client_WeaponList(void*); +void Client_DamageEnd(void*); +void Client_DeathMsg(void*); + +void amx_command(); +void plugin_srvcmd(); + +const char* stristr(const char* a,const char* b); +char *strptime(const char *buf, const char *fmt, struct tm *tm, short addthem); + +int loadModules(const char* filename); +void dettachModules(); +void dettachReloadModules(); +void attachModules(); +void attachMetaModModules( const char* filename ); +void dettachMetaModModules( const char* filename ); + +int add_amxnatives(module_info_s* info,AMX_NATIVE_INFO*natives); +cell* get_amxaddr(AMX *amx,cell amx_addr); +char* build_pathname(char *fmt, ... ); +char* format_amxstring(AMX *amx, cell *params, int parm,int& len); +AMX* get_amxscript(int, void**,const char**); +const char* get_amxscriptname(AMX* amx); +char* get_amxstring(AMX *amx,cell amx_addr,int id,int& len); +int amxstring_len(cell* cstr); +int load_amxscript(AMX* amx, void** program, const char* path, char error[64]); +int set_amxnatives(AMX* amx,char error[64]); +int set_amxstring(AMX *amx,cell amx_addr,const char *source,int max); +int unload_amxscript(AMX* amx,void** program); +void copy_amxmemory(cell* dest,cell* src,int len); +void get_modname(char*); +void print_srvconsole( char *fmt, ... ); +void report_error( int code, char* fmt, ... ); +void* alloc_amxmemory(void**, int size); +void free_amxmemory(void **ptr); + + +#endif // AMXMOD_H + diff --git a/amxmodx/amxtime.c b/amxmodx/amxtime.c new file mode 100755 index 00000000..867cb6a9 --- /dev/null +++ b/amxmodx/amxtime.c @@ -0,0 +1,104 @@ +/* Date/time module for the Small AMX + * + * Copyright (c) ITB CompuPhase, 2001-2002 + * This file may be freely used. No warranties of any kind. + * + * Version: $Id$ + */ +#include +#include +#if defined __WIN32__ || defined _WIN32 + #include + #include +#endif +#include "amx.h" + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL _time(AMX *amx, cell *params) +{ + time_t sec1970; + struct tm gtm; + cell *cptr; + + assert(params[0]==3*sizeof(cell)); + + time(&sec1970); + + /* on DOS/Windows, the timezone is usually not set for the C run-time + * library; in that case gmtime() and localtime() return the same value + */ + gtm=*localtime(&sec1970); + if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE) + *cptr=gtm.tm_hour; + if (amx_GetAddr(amx,params[2],&cptr)==AMX_ERR_NONE) + *cptr=gtm.tm_min; + if (amx_GetAddr(amx,params[3],&cptr)==AMX_ERR_NONE) + *cptr=gtm.tm_sec; + + /* the time() function returns the number of seconds since January 1 1970 + * in Universal Coordinated Time (the successor to Greenwich Mean Time) + */ + return sec1970; +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL _date(AMX *amx, cell *params) +{ + time_t sec1970; + struct tm gtm; + cell *cptr; + + assert(params[0]==3*sizeof(cell)); + + time(&sec1970); + + gtm=*localtime(&sec1970); + if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE) + *cptr=gtm.tm_year+1900; + if (amx_GetAddr(amx,params[2],&cptr)==AMX_ERR_NONE) + *cptr=gtm.tm_mon+1; + if (amx_GetAddr(amx,params[3],&cptr)==AMX_ERR_NONE) + *cptr=gtm.tm_mday; + + return 0; +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL _tickcount(AMX *amx, cell *params) +{ + // #if defined __WIN32__ || defined _WIN32 + // static int timerset = 0; + // #endif + cell value; + + assert(params[0]==sizeof(cell)); + + //#if defined __WIN32__ || defined _WIN32 + // if (!timerset) { + // timeBeginPeriod(1); /* timeGetTime() is more accurate on WindowsNT +// * if timeBeginPeriod(1) is set */ + // timerset=1; + // } /* if */ + // value=timeGetTime(); /* this value is already in milliseconds */ + // #else + value=(cell)clock(); + /* convert to milliseconds */ + value=(cell)((1000L * (value+CLK_TCK/2)) / CLK_TCK); + //#endif + return value; +} + + +AMX_NATIVE_INFO time_Natives[] = { + { "time", _time }, + { "date", _date }, + { "tickcount", _tickcount }, + { NULL, NULL } /* terminator */ +}; + diff --git a/amxmodx/emsg.cpp b/amxmodx/emsg.cpp new file mode 100755 index 00000000..79620995 --- /dev/null +++ b/amxmodx/emsg.cpp @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" + +int gmsgAmmoPickup; +int gmsgAmmoX; +int gmsgBattery; +int gmsgCurWeapon; +int gmsgDamage; +int gmsgDeathMsg; +int gmsgHealth; +int gmsgMOTD; +int gmsgScoreInfo; +int gmsgSendAudio; +int gmsgServerName; +int gmsgShowMenu; +int gmsgTeamInfo; +int gmsgTextMsg; +int gmsgVGUIMenu; +int gmsgWeapPickup; +int gmsgWeaponList; +int gmsgintermission; +int gmsgResetHUD; +int gmsgRoundTime; + +TeamIds g_teamsIds; +WeaponsVault g_weaponsData[MAX_WEAPONS]; + +void Client_VGUIMenu(void* mValue) +{ + if (!mPlayer) return; + switch (mState++){ + case 0: + mPlayer->menu = -(*(int*)mValue); + break; + case 1: + mPlayer->keys = *(int*)mValue; + } +} + +void Client_ShowMenu(void* mValue) +{ + if (!mPlayer) return; + switch (mState++){ + case 0: + mPlayer->keys = *(int*)mValue; + break; + case 3: + mPlayer->menu = g_menucmds.findMenuId( (char*)mValue ); + } +} + +void Client_TeamInfo(void* mValue) +{ + if (mPlayer) return; + static int index; + switch (mState++) { + case 0: + index = *(int*)mValue; + break; + case 1: + if ( index < 1 || index > gpGlobals->maxClients ) break; + char* msg = (char*)mValue; + g_players[ index ].team.set( msg ); + g_teamsIds.registerTeam( msg , -1 ); + } +} + +void Client_TextMsg(void* mValue) +{ + if ( mPlayer ) return; + switch (mState++) { + case 1:{ + char * msg = (char*)mValue; + if (!msg) break; + if ( !strncmp("#Game_C", msg , 7) ) { + g_game_timeleft = g_game_restarting = gpGlobals->time + 3; + // g_endround_time = gpGlobals->time; + // g_newround_time = gpGlobals->time + CVAR_GET_FLOAT("mp_freezetime") + 3; + } + else if (!strncmp("#Game_w", msg , 7) ) { + g_game_timeleft = -2; + } + else if ( !strncmp("#game_clan_s", msg , 12) ){ + g_game_timeleft = -3; + } + break; + } + case 2:{ + char * msg = (char*)mValue; + if (!msg) break; + if (g_game_timeleft == -2 ){ + g_game_timeleft = g_game_restarting = gpGlobals->time + atoi( msg ); + // g_newround_time = g_game_timeleft + CVAR_GET_FLOAT("mp_freezetime"); + } + else if ( g_game_timeleft == -3 ) + g_game_restarting = atoi( msg ) * 60; + break; + } + case 3:{ + char * msg = (char*)mValue; + if (!msg) break; + if ( g_game_timeleft != -3 ) break; + g_game_restarting += atoi( msg ); + g_game_timeleft = g_game_restarting = gpGlobals->time + g_game_restarting; + break; + } + } + +} + +void Client_WeaponList(void* mValue) +{ + static int wpnList = 0; + //static int wpnList2; + static int iSlot; + static const char* wpnName; + switch (mState++) { + case 0: + wpnName = (char*)mValue; + break; + case 1: + iSlot = *(int*)mValue; + break; + case 7: + int iId = *(int*)mValue; + /*int* blocker; + + int iwpn = iId; + + if (iId > 31) { + iwpn -= 31; + blocker = &wpnList2; + } + else + blocker = &wpnList;*/ + + if ( (iId < 0 || iId >= MAX_WEAPONS ) || (wpnList & (1<= MAX_WEAPONS ) ) break; + mPlayer->weapons[iId].clip = *(int*)mValue; + mPlayer->current = iId; + mPlayer->lastHit = mPlayer->lastTrace; + } +} + +void Client_AmmoX(void* mValue) +{ + + static int iAmmo; + switch (mState++){ + case 0: + iAmmo = *(int*)mValue; + break; + case 1: + if (!mPlayer) return; + for(int i=1;iweapons[i].ammo = *(int*)mValue; + } +} + +void Client_AmmoPickup(void* mValue) +{ + static int iSlot; + switch (mState++){ + case 0: + iSlot = *(int*)mValue; + break; + case 1: + if (!mPlayer) return; + for(int i=1;iweapons[i].ammo += *(int*)mValue; + } +} + +void Client_ScoreInfo(void* mValue) +{ + static int index; + static int deaths; + switch (mState++){ + case 0: + index = *(int*)mValue; + break; + case 2: + deaths = *(int*)mValue; + break; + case 4: + if ( index < 1 || index > gpGlobals->maxClients ) break; + CPlayer*pPlayer = GET_PLAYER_POINTER_I( index ); + pPlayer->deaths = deaths; + pPlayer->teamId = *(int*)mValue; + if ( g_teamsIds.isNewTeam() ) + g_teamsIds.registerTeam( pPlayer->team.str() , pPlayer->teamId ); + } +} + +void Client_DamageEnd(void* mValue) +{ + CPlayer* dead = mPlayer; + + if ( dead && dead->death_killer ) + { + g_events.parserInit( CS_DEATHMSG , &gpGlobals->time , mPlayer = 0, mPlayerIndex = 0 ); + g_events.parseValue( dead->death_killer ); + g_events.parseValue( dead->index ); + g_events.parseValue( dead->death_headshot ); + g_events.parseValue( dead->death_weapon.str() ); + g_events.parseValue( dead->death_tk ? 1 : 0 ); + g_events.executeEvents(); + dead->death_killer = 0; + } +} + +void Client_DeathMsg(void* mValue) +{ + static CPlayer *killer; + static CPlayer *victim; + static int killer_id; + static int victim_id; + static int hs; + + switch (mState++){ + case 0: + killer_id = *(int*)mValue; + killer = (killer_id > 0 && killer_id < 33) ? + GET_PLAYER_POINTER_I(killer_id) : 0; + break; + case 1: + victim_id = *(int*)mValue; + victim = (victim_id > 0 && victim_id < 33) ? + GET_PLAYER_POINTER_I(victim_id) : 0; + break; + case 2: + hs = *(int*)mValue; + break; + case 3: + + if ( !killer || !victim ) break; + + victim->death_killer = killer_id; + victim->death_weapon.set((char*)mValue); + victim->death_headshot = hs; + victim->death_tk = (killer->teamId == victim->teamId); + } +} +/* +void Client_SendAudio(void* mValue) +{ + +} + +void Client_SendAudioEnd(void* mValue) +{ + + +} + +void Client_RoundTimeEnd(void* mValue) +{ + +} + +void Client_RoundTime(void* mValue) +{ + +} + + +void Client_ResetHUD(void* mValue) +{ + +} +*/ \ No newline at end of file diff --git a/amxmodx/file.cpp b/amxmodx/file.cpp new file mode 100755 index 00000000..519db9ca --- /dev/null +++ b/amxmodx/file.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" + +// header file for unlink() +#ifdef __linux__ +#include +#else +#include +#endif + +#ifdef __GNUC__ + +//#include +#include +#include +#include + +#endif + +static cell AMX_NATIVE_CALL read_dir(AMX *amx, cell *params) +{ +#ifdef __GNUC__ + int a; + struct dirent *ep; + DIR *dp; + char* dirname = build_pathname("%s",get_amxstring(amx,params[1],0,a) ); + a = params[2]; + if ( (dp = opendir (dirname)) == NULL ) + return 0; + seekdir( dp , a ); + if ( (ep = readdir (dp)) != NULL ) { + cell *length = get_amxaddr(amx,params[5]); + *length = set_amxstring(amx,params[3], ep->d_name ,params[4]); + a = telldir( dp ); + } + else + a = 0; + closedir (dp); + return a; +#else + return 0; +#endif +} + +static cell AMX_NATIVE_CALL read_file(AMX *amx, cell *params) /* 5 param */ +{ + int iLen; + char* szFile = get_amxstring(amx,params[1],0,iLen); + FILE*fp; + if ( (fp =fopen(build_pathname("%s",szFile),"r")) == NULL) { + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + char buffor[1024]; + int i = 0, iLine = params[2]; + while((i <= iLine) && fgets(buffor,1023,fp) ) + i++; + fclose(fp); + if (i > iLine){ + int len = strlen(buffor); + if (buffor[len-1]=='\n') + buffor[--len]=0; + if (buffor[len-1]=='\r') + buffor[--len]=0; + cell *length = get_amxaddr(amx,params[5]); + *length = set_amxstring(amx,params[3],buffor,params[4]); + return i; + } + return 0; +} + +static cell AMX_NATIVE_CALL write_file(AMX *amx, cell *params) /* 3 param */ +{ + int i; + char* sFile = build_pathname("%s", get_amxstring(amx,params[1],0,i) ); + char* sText = get_amxstring(amx,params[2],0,i); + FILE* pFile; + int iLine = params[3]; + + // apending to the end + if (iLine < 0) { + if ( (pFile = fopen( sFile ,"a")) == NULL ){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + fputs( sText , pFile ); + fputc( '\n', pFile ); + fclose( pFile ); + return 1; + } + + // creating a new file with a line in a middle + if ( (pFile = fopen(sFile,"r")) == NULL ) { + if ( (pFile = fopen(sFile,"w")) == NULL ){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + for(i=0;i < iLine;++i) + fputc('\n',pFile); + fputs( sText , pFile ); + fputc( '\n', pFile ); + fclose(pFile); + return 1; + } + + // adding a new line in a middle of already existing file + FILE* pTemp; + char buffor[1024]; + + if ( (pTemp = tmpfile()) == NULL ){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + + for(i=0;;++i){ + if ( i == iLine ){ + fgets(buffor,1023,pFile); + fputs( sText , pTemp ); + fputc( '\n', pTemp ); + } + else if ( fgets(buffor,1023,pFile) ){ + fputs(buffor , pTemp ); + } + else if ( i < iLine ) { + fputc( '\n', pTemp ); + } + else break; + } + + fclose(pFile); + rewind(pTemp); + + // now rewrite because file can be now smaller... + if ( (pFile = fopen(sFile,"w")) == NULL ){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + + while(fgets(buffor,1023,pTemp)) + fputs(buffor,pFile ); + + fclose(pTemp); + fclose(pFile); + return 1; +} + +static cell AMX_NATIVE_CALL delete_file(AMX *amx, cell *params) /* 1 param */ +{ + int iLen; + char* sFile = get_amxstring(amx,params[1],0,iLen); + return (unlink( build_pathname("%s",sFile) )?0:1); +} + +static cell AMX_NATIVE_CALL file_exists(AMX *amx, cell *params) /* 1 param */ +{ + int iLen; + char* sFile = get_amxstring(amx,params[1],0,iLen); + FILE* fp = fopen(build_pathname("%s",sFile),"r"); + if ( fp != NULL) { + fclose(fp); + return 1; + } + return 0; +} + +static cell AMX_NATIVE_CALL file_size(AMX *amx, cell *params) /* 1 param */ +{ + int iLen; + char* sFile = get_amxstring(amx,params[1],0,iLen); + FILE* fp = fopen(build_pathname("%s",sFile),"r"); + if ( fp != NULL) { + if ( params[0] < 2 || params[2] == 0 ){ + fseek(fp,0,SEEK_END); + int size = ftell(fp); + fclose(fp); + return size; + } + else if ( params[2] == 1 ){ + int a = 0,lines = 0; + while( a != EOF ){ + ++lines; + while ( (a = fgetc(fp)) != '\n' && a != EOF ) + ; + } + //int a, b = '\n'; + //while( (a = fgetc(fp)) != EOF ){ + // if ( a == '\n') + // ++lines; + // b = a; + //} + //if ( b != '\n' ) + // ++lines; + return lines; + } + else if ( params[2] == 2 ){ + fseek(fp,-1,SEEK_END); + if ( fgetc(fp) == '\n' ) + return 1; + return 0; + } + } + return -1; +} + +AMX_NATIVE_INFO file_Natives[] = { + { "delete_file", delete_file }, + { "file_exists", file_exists }, + { "file_size", file_size }, + { "read_dir", read_dir }, + { "read_file", read_file }, + { "write_file", write_file }, + { NULL, NULL } +}; + diff --git a/amxmodx/float.cpp b/amxmodx/float.cpp new file mode 100755 index 00000000..1fa30510 --- /dev/null +++ b/amxmodx/float.cpp @@ -0,0 +1,96 @@ +/* Float arithmetic for the Small AMX engine + * + * Copyright (c) Artran, Inc. 1999 + * Written by Greg Garner (gmg@artran.com) + * This file may be freely used. No warranties of any kind. + * + */ + +#include +#include +#include +#include +#include "amxmod.h" + +inline cell FloatToCell(float fValue) { + return *(cell *)((void *)&fValue); +} + +inline float CellToFloat(cell cellValue){ + return *(float *)((void *)&cellValue); +} + +static cell _float(AMX *,cell *params){ + return FloatToCell((float)params[1]); +} + +static cell _floatstr(AMX *amx,cell *params){ + int len; + return FloatToCell((float)atof(get_amxstring(amx,params[1],0,len))); +} + +static cell _floatmul(AMX *,cell *params){ + return FloatToCell(CellToFloat(params[1]) * CellToFloat(params[2])); +} + +static cell _floatdiv(AMX *,cell *params){ + return FloatToCell(CellToFloat(params[1]) / CellToFloat(params[2])); +} + +static cell _floatadd(AMX *,cell *params){ + return FloatToCell(CellToFloat(params[1]) + CellToFloat(params[2])); +} + +static cell _floatsub(AMX *,cell *params){ + return FloatToCell(CellToFloat(params[1]) - CellToFloat(params[2])); +} + +static cell _floatfract(AMX *,cell *params){ + float fA = CellToFloat(params[1]); + fA -= (float)(floor((double)fA)); + return FloatToCell(fA); +} + +static cell _floatround(AMX *,cell *params){ + float fA = CellToFloat(params[1]); + switch (params[2]) { + case 1: + fA = (float)(floor((double)fA)); + break; + case 2: + float fValue; + fValue = (float)(floor((double)fA)); + if ( (fA>=0) && ((fA-fValue)!=0) ) + fValue++; + fA = fValue; + break; + default: + fA = (float)(floor((double)fA+.5)); + break; + } + return (long)fA; +} + +static cell _floatcmp(AMX *,cell *params){ + float fA = CellToFloat(params[1]); + float fB = CellToFloat(params[2]); + if (fA == fB) + return 0; + else if (fA > fB) + return 1; + else + return -1; +} + +AMX_NATIVE_INFO float_Natives[] = { + { "float", _float }, + { "floatstr", _floatstr }, + { "floatmul", _floatmul }, + { "floatdiv", _floatdiv }, + { "floatadd", _floatadd }, + { "floatsub", _floatsub }, + { "floatfract", _floatfract}, + { "floatround", _floatround}, + { "floatcmp", _floatcmp}, + { NULL, NULL } +}; \ No newline at end of file diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp new file mode 100755 index 00000000..561e0557 --- /dev/null +++ b/amxmodx/meta_api.cpp @@ -0,0 +1,1096 @@ +/* +* Copyright (c) 2002-2003 Aleksander Naszko +* +* This file is part of AMX Mod. +* +* AMX Mod 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. +* +* AMX Mod 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 AMX Mod; 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 "amxmod.h" + +plugin_info_t Plugin_info = { + META_INTERFACE_VERSION, // ifvers + "AMX", // name + AMX_VERSION, // version + __DATE__, // date + "OLO", // author + "http://www.amxmod.net", // url + "AMX", // logtag + PT_ANYTIME,// (when) loadable + PT_ANYTIME,// (when) unloadable +}; + +meta_globals_t *gpMetaGlobals; +gamedll_funcs_t *gpGamedllFuncs; +mutil_funcs_t *gpMetaUtilFuncs; +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; + +funEventCall modMsgsEnd[MAX_REG_MSGS]; +funEventCall modMsgs[MAX_REG_MSGS]; +void (*function)(void*); +void (*endfunction)(void*); + +CForwardMngr g_forwards; +CList g_auth; +CList g_cvars; +CList g_forcemodels; +CList g_forcesounds; +CList g_forcegeneric; +CPlayer g_players[33]; +CPlayer* mPlayer; +CPluginMngr g_plugins; +CTaskMngr g_tasksMngr; +CmdMngr g_commands; +EventsMngr g_events; +Grenades g_grenades; +LogEventsMngr g_logevents; +MenuMngr g_menucmds; +String g_log_dir; +String g_mod_name; +XVars g_xvars; +bool g_bmod_cstrike; +bool g_bmod_dod; +bool g_dontprecache; +bool g_forcedmodules; +bool g_forcedsounds; +bool g_initialized; +fakecmd_t g_fakecmd; +float g_game_restarting; +float g_game_timeleft; +float g_task_time; +float g_auth_time; +hudtextparms_t g_hudset; +//int g_edict_point; +int g_players_num; +int mPlayerIndex; +int mState; +int g_srvindex; + +cvar_t init_amx_version={"amx_version","", FCVAR_SERVER | FCVAR_SPONLY}; +cvar_t* amx_version = NULL; +cvar_t* hostname = NULL; +cvar_t* mp_timelimit = NULL; + +// Precache stuff from force consistency calls +// or check for pointed files won't be done +int PrecacheModel(char *s) { + if ( !g_forcedmodules ){ + g_forcedmodules = true; + for(CList::iterator a = g_forcemodels.begin(); a ; ++a){ + PRECACHE_MODEL((char*)(*a).getFilename()); + ENGINE_FORCE_UNMODIFIED((*a).getForceType(),(*a).getMin(),(*a).getMax(),(*a).getFilename()); + } + } + RETURN_META_VALUE(MRES_IGNORED, 0); +} + +int PrecacheSound(char *s) { + if ( !g_forcedsounds ) { + g_forcedsounds = true; + for(CList::iterator a = g_forcesounds.begin(); a ; ++a){ + PRECACHE_SOUND((char*)(*a).getFilename()); + ENGINE_FORCE_UNMODIFIED((*a).getForceType(),(*a).getMin(),(*a).getMax(),(*a).getFilename()); + } + if (!g_bmod_cstrike){ + PRECACHE_SOUND("weapons/cbar_hitbod1.wav"); + PRECACHE_SOUND("weapons/cbar_hitbod2.wav"); + PRECACHE_SOUND("weapons/cbar_hitbod3.wav"); + } + } + RETURN_META_VALUE(MRES_IGNORED, 0); +} + +// On InconsistentFile call forward function from plugins +int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) +{ + if ( !g_forwards.forwardsExist( FF_InconsistentFile ) ) + RETURN_META_VALUE(MRES_IGNORED, FALSE); + + if ( MDLL_InconsistentFile(player,filename,disconnect_message) ) + { + cell ret = 0; + CPlayer *pPlayer = GET_PLAYER_POINTER((edict_t *)player); + CForwardMngr::iterator a = g_forwards.begin( FF_InconsistentFile ); + +#ifdef ENABLEEXEPTIONS + try{ +#endif + + while ( a ) + { + + if ( (*a).getPlugin()->isExecutable( (*a).getFunction() ) ) + { + AMX* c = (*a).getPlugin()->getAMX(); + cell amx_addr1, *phys_addr1; + cell amx_addr2, *phys_addr2; + if ((amx_Allot(c, 64 , &amx_addr1, &phys_addr1) != AMX_ERR_NONE) || + (amx_Allot(c, 64 , &amx_addr2, &phys_addr2) != AMX_ERR_NONE) ){ + print_srvconsole("[AMX] Failed to allocate AMX memory (plugin \"%s\")\n",(*a).getPlugin()->getName()); + } + else { + int err; + set_amxstring(c,amx_addr1,filename,63); + set_amxstring(c,amx_addr2,disconnect_message,63); + if ((err = amx_Exec(c,&ret, (*a).getFunction() , 3, pPlayer->index, amx_addr1, amx_addr2)) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n", + err,c->curline,(*a).getPlugin()->getName()); + int len; + strcpy(disconnect_message,get_amxstring(c,amx_addr2,0,len)); + amx_Release(c, amx_addr2); + amx_Release(c, amx_addr1); + } + if ( ret & 1 ) RETURN_META_VALUE(MRES_SUPERCEDE, FALSE); + } + + + ++a; + } +#ifdef ENABLEEXEPTIONS + }catch( ... ) + { + print_srvconsole( "[AMX] fatal error at inconsistent file forward execution\n"); + } +#endif + + RETURN_META_VALUE(MRES_SUPERCEDE, TRUE ); + } + + RETURN_META_VALUE(MRES_IGNORED, FALSE); +} + +const char* get_localinfo( const char* name , const char* def ) +{ + const char* b = LOCALINFO( (char*)name ); + if ( b == 0 || *b == 0 ) + SET_LOCALINFO((char*)name,(char*)(b = def) ); + return b; +} + +// Very first point at map load +// Load AMX modules for new native functions +// Initialize AMX stuff and load it's plugins from plugins.ini list +// Call precache forward function from plugins +int Spawn( edict_t *pent ) { + + if ( g_initialized ) RETURN_META_VALUE(MRES_IGNORED, 0); + + g_initialized = true; + g_forcedmodules = false; + g_forcedsounds = false; + + g_srvindex = IS_DEDICATED_SERVER() ? 0 : 1; + + hostname = CVAR_GET_POINTER("hostname"); + mp_timelimit = CVAR_GET_POINTER("mp_timelimit"); + + // ###### Initialize task manager + g_tasksMngr.registerTimers( &gpGlobals->time, &mp_timelimit->value, &g_game_timeleft ); + + // ###### Initialize commands prefixes + g_commands.registerPrefix( "amx" ); + g_commands.registerPrefix( "say" ); + g_commands.registerPrefix( "admin_" ); + g_commands.registerPrefix( "sm_" ); + g_commands.registerPrefix( "cm_" ); + + Vault amx_config; + // ###### Load custom path configuration + amx_config.setSource( build_pathname("%s", + get_localinfo("amx_cfg" , "addons/amx/config.ini")) ); + + if ( amx_config.loadVault() ){ + Vault::iterator a = amx_config.begin(); + while ( a != amx_config.end() ) { + SET_LOCALINFO( (char*)a.key().str() , (char*)a.value().str() ); + ++a; + } + amx_config.clear(); + } + + // ###### Make sure basedir is set + get_localinfo("amx_basedir" , "addons/amx" ); + + // ###### Load modules + int loaded = loadModules( get_localinfo("amx_modules" , "addons/amx/modules.ini" ) ); + attachModules(); + // Set some info about amx version and modules + if ( loaded ){ + char buffer[64]; + sprintf( buffer,"%s (%d module%s)", + AMX_VERSION, loaded , (loaded == 1) ? "" : "s" ); + CVAR_SET_STRING( "amx_version" , buffer ); + } + else CVAR_SET_STRING( "amx_version" , AMX_VERSION ); + + // ###### Save log dir + g_log_dir.set( get_localinfo("amx_logdir" , "addons/amx/logs" ) ); + + // ###### Load Vault + g_vault.setSource( build_pathname("%s", + get_localinfo("amx_vault" , "addons/amx/vault.ini" ) ) ); + g_vault.loadVault( ); + + + // ###### Init time and freeze tasks + g_game_timeleft = g_bmod_dod ? 1 : 0; + g_task_time = gpGlobals->time + 99999.0; + g_auth_time = gpGlobals->time + 99999.0; + g_players_num = 0; + + // Set server flags + memset(g_players[0].flags,-1,sizeof(g_players[0].flags)); + + // ###### Load AMX scripts + g_plugins.loadPluginsFromFile( + get_localinfo("amx_plugins" , "addons/amx/plugins/plugins.ini" ) ); + + // ###### Call precache forward function + g_dontprecache = false; + g_forwards.executeForwards(FF_PluginPrecache); + g_dontprecache = true; + + for(CList::iterator a = g_forcegeneric.begin(); a ; ++a){ + PRECACHE_GENERIC((char*)(*a).getFilename()); + ENGINE_FORCE_UNMODIFIED((*a).getForceType(), + (*a).getMin(),(*a).getMax(),(*a).getFilename()); + } + + + RETURN_META_VALUE(MRES_IGNORED, 0); +} + +struct sUserMsg { + const char* name; + int* id; + funEventCall func; + bool endmsg; + bool cstrike; +} g_user_msg[] = { + { "CurWeapon" , &gmsgCurWeapon , Client_CurWeapon, false,false }, + { "Damage" , &gmsgDamage,Client_DamageEnd, true , true }, + { "DeathMsg" , &gmsgDeathMsg, Client_DeathMsg, false,true }, + { "TextMsg" , &gmsgTextMsg,Client_TextMsg , false,false}, + { "TeamInfo" , &gmsgTeamInfo,Client_TeamInfo , false,false}, + { "WeaponList" , &gmsgWeaponList, Client_WeaponList, false, false}, + { "MOTD" , &gmsgMOTD, 0 , false,false}, + { "ServerName" , &gmsgServerName, 0 , false, false}, + { "Health" , &gmsgHealth, 0 , false,false }, + { "Battery" , &gmsgBattery, 0 , false,false}, + { "ShowMenu" , &gmsgShowMenu,Client_ShowMenu , false,false}, + { "SendAudio" , &gmsgSendAudio, 0, false,false}, + { "AmmoX" , &gmsgAmmoX, Client_AmmoX , false,false }, + { "ScoreInfo" , &gmsgScoreInfo, Client_ScoreInfo, false, false}, + { "VGUIMenu" , &gmsgVGUIMenu,Client_VGUIMenu, false,false }, + { "AmmoPickup" , &gmsgAmmoPickup, Client_AmmoPickup , false,false }, + { "WeapPickup" , &gmsgWeapPickup,0, false,false }, + { "ResetHUD" , &gmsgResetHUD,0, false,false }, + { "RoundTime" , &gmsgRoundTime,0, false, false}, + { 0 , 0,0,false,false } +}; + + +int RegUserMsg_Post(const char *pszName, int iSize) +{ + for (int i = 0; g_user_msg[ i ].name; ++i ) + { + if ( strcmp( g_user_msg[ i ].name , pszName ) == 0 ) + { + int id = META_RESULT_ORIG_RET( int ); + + *g_user_msg[ i ].id = id; + + if ( !g_user_msg[ i ].cstrike || g_bmod_cstrike ) + { + if ( g_user_msg[ i ].endmsg ) + modMsgsEnd[ id ] = g_user_msg[ i ].func; + else + modMsgs[ id ] = g_user_msg[ i ].func; + } + + break; + } + } + + RETURN_META_VALUE(MRES_IGNORED, 0); +} + +/* +Much more later after precache. All is precached, server +will be flaged as ready to use so call +plugin_init forward function from plugins +*/ +void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ){ + + int id; + for (int i = 0; g_user_msg[ i ].name; ++i ) + { + if ( (*g_user_msg[ i ].id == 0) && + (id = GET_USER_MSG_ID(PLID, g_user_msg[ i ].name , NULL ))!=0) + { + *g_user_msg[ i ].id = id; + + if ( !g_user_msg[ i ].cstrike || g_bmod_cstrike ) + { + if ( g_user_msg[ i ].endmsg ) + modMsgsEnd[ id ] = g_user_msg[ i ].func; + else + modMsgs[ id ] = g_user_msg[ i ].func; + } + } + } + + RETURN_META(MRES_IGNORED); +} + +void ServerActivate_Post( edict_t *pEdictList, int edictCount, int clientMax ){ + +// g_edict_point = (int)pEdictList; + + for(int i = 1; i <= gpGlobals->maxClients; ++i) { + CPlayer *pPlayer = GET_PLAYER_POINTER_I(i); + pPlayer->Init( pEdictList + i , i ); + } + + g_forwards.executeForwards(FF_PluginInit); + g_forwards.executeForwards(FF_PluginCfg); + + // Correct time in Counter-Strike and other mods (except DOD) + if ( !g_bmod_dod) g_game_timeleft = 0; + + g_task_time = gpGlobals->time; + g_auth_time = gpGlobals->time; + + RETURN_META(MRES_IGNORED); +} + +// Call plugin_end forward function from plugins. +void ServerDeactivate() { + + for(int i = 1; i <= gpGlobals->maxClients; ++i){ + CPlayer *pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->ingame){ + + g_forwards.executeForwards(FF_ClientDisconnect , 1,pPlayer->index); + + pPlayer->Disconnect(); + --g_players_num; + } + } + + g_players_num = 0; + g_forwards.executeForwards(FF_PluginEnd); + + RETURN_META(MRES_IGNORED); +} + +// After all clear whole AMX configuration +// However leave AMX modules which are loaded only once +void ServerDeactivate_Post() { + + g_initialized = false; + + dettachReloadModules(); + + g_auth.clear(); + g_forwards.clear(); + g_commands.clear(); + g_forcemodels.clear(); + g_forcesounds.clear(); + g_forcegeneric.clear(); + g_grenades.clear(); + g_tasksMngr.clear(); + g_logevents.clearLogEvents(); + g_events.clearEvents(); + g_menucmds.clear(); + g_vault.clear(); + g_xvars.clear(); + g_plugins.clear(); + + RETURN_META(MRES_IGNORED); +} + +BOOL ClientConnect_Post( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ){ + CPlayer* pPlayer = GET_PLAYER_POINTER(pEntity); + if (!pPlayer->bot) { + + bool a = pPlayer->Connect(pszName,pszAddress); + + g_forwards.executeForwards(FF_ClientConnect , 1,pPlayer->index); + + if ( a ) + { + CPlayer** aa = new CPlayer*(pPlayer); + if ( aa ) g_auth.put( aa ); + } + else + { + pPlayer->Authorize(); + g_forwards.executeForwards(FF_ClientAuthorized , 1, pPlayer->index ); + } + } + RETURN_META_VALUE(MRES_IGNORED, TRUE); +} + +void ClientDisconnect( edict_t *pEntity ) { + CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity); + if (pPlayer->ingame) { + g_forwards.executeForwards(FF_ClientDisconnect , 1,pPlayer->index); + pPlayer->Disconnect(); + --g_players_num; + } + RETURN_META(MRES_IGNORED); +} + +void ClientPutInServer_Post( edict_t *pEntity ) { + CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity); + if (!pPlayer->bot) { + pPlayer->PutInServer(); + ++g_players_num; + + g_forwards.executeForwards(FF_ClientPutInServer , 1,pPlayer->index); + + } + RETURN_META(MRES_IGNORED); +} + +void ClientUserInfoChanged_Post( edict_t *pEntity, char *infobuffer ) { + CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity); + + g_forwards.executeForwards(FF_ClientInfoChanged , 1,pPlayer->index); + + const char* name = INFOKEY_VALUE(infobuffer,"name"); + + // Emulate bot connection and putinserver + if ( pPlayer->ingame ) + { + pPlayer->name.set(name); // Make sure player have name up to date + } + else if ( pPlayer->IsBot() ) + { + pPlayer->Connect( name ,"127.0.0.1"/*CVAR_GET_STRING("net_address")*/); + + g_forwards.executeForwards(FF_ClientConnect , 1,pPlayer->index); + + pPlayer->Authorize(); + g_forwards.executeForwards(FF_ClientAuthorized , 1, pPlayer->index ); + + + pPlayer->PutInServer(); + ++g_players_num; + + g_forwards.executeForwards(FF_ClientPutInServer , 1,pPlayer->index); + } + + RETURN_META(MRES_IGNORED); +} + +void ClientCommand( edict_t *pEntity ) { + CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity); + META_RES result = MRES_IGNORED; + cell ret = 0; + int err; + +#ifdef ENABLEEXEPTIONS + try + { +#endif + /* because of PLUGIN_HANDLED_MAIN we must call function (client_command) manualy */ + + CForwardMngr::iterator a = g_forwards.begin( FF_ClientCommand ); + + while ( a ) + { + if ( (*a).getPlugin()->isExecutable( (*a).getFunction() ) ) + { + + if ((err = amx_Exec((*a).getPlugin()->getAMX(), &ret , (*a).getFunction(), 1, pPlayer->index)) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n", + err,(*a).getPlugin()->getAMX()->curline,(*a).getPlugin()->getName() ); + + if ( ret & 2 ) result = MRES_SUPERCEDE; + if ( ret & 1 ) RETURN_META(MRES_SUPERCEDE); + + } + + ++a; + } + + +#ifdef ENABLEEXEPTIONS + }catch( ... ) + { + print_srvconsole( "[AMX] fatal error at commmand forward execution\n"); + } +#endif + + + /* check for command and if needed also for first argument and call proper function */ + const char* cmd = CMD_ARGV(0); + const char* arg = CMD_ARGV(1); + +#ifdef ENABLEEXEPTIONS + try{ +#endif + + CmdMngr::iterator aa = g_commands.clcmdprefixbegin( cmd ); + if ( !aa ) aa = g_commands.clcmdbegin(); + + while ( aa ) + { + if ( (*aa).matchCommandLine( cmd , arg ) && + (*aa).getPlugin()->isExecutable( (*aa).getFunction() ) ) + { + + if ((err =amx_Exec((*aa).getPlugin()->getAMX(), &ret , (*aa).getFunction() , 3, pPlayer->index, (*aa).getFlags(),(*aa).getId() )) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n", + err,(*aa).getPlugin()->getAMX()->curline,(*aa).getPlugin()->getName()); + + if ( ret & 2 ) result = MRES_SUPERCEDE; + if ( ret & 1 ) RETURN_META(MRES_SUPERCEDE); + } + + ++aa; + } + +#ifdef ENABLEEXEPTIONS + }catch( ... ) + { + print_srvconsole( "[AMX] fatal error at client commmand execution\n"); + } +#endif + /* check menu commands */ + + if (!strcmp(cmd,"menuselect")) + { + int pressed_key = atoi( arg ) - 1; + int bit_key = (1<keys & bit_key) + { + + int menuid = pPlayer->menu; + pPlayer->menu = 0; + +#ifdef ENABLEEXEPTIONS + try{ +#endif + MenuMngr::iterator a = g_menucmds.begin(); + + while( a ) + { + if ( (*a).matchCommand( menuid , bit_key ) && (*a).getPlugin()->isExecutable( (*a).getFunction() ) ) + { + + if ( ( err = amx_Exec((*a).getPlugin()->getAMX(), &ret ,(*a).getFunction() , 2, pPlayer->index,pressed_key)) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n", + err,(*a).getPlugin()->getAMX()->curline,(*a).getPlugin()->getName()); + + if ( ret & 2 ) result = MRES_SUPERCEDE; + if ( ret & 1 ) RETURN_META(MRES_SUPERCEDE); + } + + ++a; + } + +#ifdef ENABLEEXEPTIONS + } + catch( ... ) + { + print_srvconsole( "[AMX] fatal error at menu commmand execution\n"); + } +#endif + } + } + /* check for PLUGIN_HANDLED_MAIN and block hl call if needed */ + RETURN_META( result ); +} + +void StartFrame_Post( void ) { + + if (g_auth_time < gpGlobals->time ) + { + g_auth_time = gpGlobals->time + 0.7; + + CList::iterator a = g_auth.begin(); + + while ( a ) + { + const char* auth = GETPLAYERAUTHID( (*a)->pEdict ); + + if ( (auth == 0) || (*auth == 0) ) { + a.remove(); + continue; + } + + if ( strcmp( auth, "STEAM_ID_PENDING" ) ) + { + (*a)->Authorize(); + g_forwards.executeForwards(FF_ClientAuthorized , 1,(*a)->index); + a.remove(); + continue; + } + + ++a; + } + + } + + + + + if (g_task_time > gpGlobals->time) + RETURN_META(MRES_IGNORED); + + g_task_time = gpGlobals->time + 0.1; + + for(CTaskMngr::iterator a = g_tasksMngr.begin(); a ; ++a) + { + CTaskMngr::CTask& task = *a; + CPluginMngr::CPlugin* plugin = task.getPlugin(); + int err; + + if ( plugin->isExecutable( task.getFunction() ) ) + { + if ( task.getParamLen() ) // call with arguments + { + cell amx_addr, *phys_addr; + + if (amx_Allot(plugin->getAMX(), task.getParamLen() , &amx_addr, &phys_addr) != AMX_ERR_NONE) + { + print_srvconsole("[AMX] Failed to allocate AMX memory (task \"%d\") (plugin \"%s\")\n", task.getTaskId(),plugin->getName()); + } + else + { + copy_amxmemory(phys_addr, task.getParam() , task.getParamLen() ); + + if ((err = amx_Exec(plugin->getAMX(),NULL, task.getFunction() , 2, amx_addr, task.getTaskId() )) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (task \"%d\") (plugin \"%s\")\n", err,plugin->getAMX()->curline,task.getTaskId(),plugin->getName()); + + amx_Release(plugin->getAMX(), amx_addr); + } + } + else // call without arguments + { + if ((err = amx_Exec(plugin->getAMX(),NULL, task.getFunction() ,1, task.getTaskId() )) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (task \"%d\") (plugin \"%s\")\n", err,plugin->getAMX()->curline,task.getTaskId(),plugin->getName()); + } + } + } + + RETURN_META(MRES_IGNORED); +} + +void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) { + if (ed) + { + + if (gmsgBattery==msg_type&&g_bmod_cstrike) + { + void* ptr = GET_PRIVATE(ed); +#ifdef __linux__ + int *z = (int*)ptr + 0x171; +#else + int *z = (int*)ptr + 0x16C; +#endif + int stop = ed->v.armorvalue; + *z = stop; + ed->v.armorvalue = stop; + } + + mPlayerIndex = ENTINDEX(ed); + mPlayer = GET_PLAYER_POINTER_I(mPlayerIndex); + } + else + { + mPlayerIndex = 0; + mPlayer = 0; + } + if ( msg_type < 0 || msg_type >= MAX_REG_MSGS ) + msg_type = 0; + + mState = 0; + function=modMsgs[msg_type]; + endfunction=modMsgsEnd[msg_type]; + g_events.parserInit(msg_type, &gpGlobals->time, mPlayer ,mPlayerIndex); + RETURN_META(MRES_IGNORED); +} +void WriteByte_Post(int iValue) { + g_events.parseValue(iValue); + if (function) (*function)((void *)&iValue); + RETURN_META(MRES_IGNORED); +} +void WriteChar_Post(int iValue) { + g_events.parseValue(iValue); + if (function) (*function)((void *)&iValue); + RETURN_META(MRES_IGNORED); +} +void WriteShort_Post(int iValue) { + g_events.parseValue(iValue); + if (function) (*function)((void *)&iValue); + RETURN_META(MRES_IGNORED); +} +void WriteLong_Post(int iValue) { + g_events.parseValue(iValue); + if (function) (*function)((void *)&iValue); + RETURN_META(MRES_IGNORED); +} +void WriteAngle_Post(float flValue) { + g_events.parseValue(flValue); + if (function) (*function)((void *)&flValue); + RETURN_META(MRES_IGNORED); +} +void WriteCoord_Post(float flValue) { + g_events.parseValue(flValue); + if (function) (*function)((void *)&flValue); + RETURN_META(MRES_IGNORED); +} +void WriteString_Post(const char *sz) { + g_events.parseValue(sz); + if (function) (*function)((void *)sz); + RETURN_META(MRES_IGNORED); +} +void WriteEntity_Post(int iValue) { + g_events.parseValue(iValue); + if (function) (*function)((void *)&iValue); + RETURN_META(MRES_IGNORED); +} +void MessageEnd_Post(void) { + g_events.executeEvents(); + +#if 0 // ######### this is done by call above + EventsMngr::iterator a = g_events.begin(); + int err; +#ifdef ENABLEEXEPTIONS + try + { +#endif + + while ( a ) + { + + if ((err = amx_Exec((*a).getPlugin()->getAMX(), NULL , (*a).getFunction() , 1, mPlayerIndex /*g_events.getArgInteger(0)*/ )) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n",err,(*a).getPlugin()->getAMX()->curline,(*a).getPlugin()->getName()); + + + ++a; + + } + +#ifdef ENABLEEXEPTIONS + } + catch( ... ) + { + print_srvconsole( "[AMX] fatal error at event execution\n"); + } +#endif +#endif + + if (endfunction) (*endfunction)(NULL); + RETURN_META(MRES_IGNORED); +} +const char *Cmd_Args( void ) { + if (g_fakecmd.fake) RETURN_META_VALUE(MRES_SUPERCEDE, (g_fakecmd.argc>1)?g_fakecmd.args:NULL); + RETURN_META_VALUE(MRES_IGNORED, NULL); +} + +const char *Cmd_Argv( int argc ) { + if (g_fakecmd.fake) RETURN_META_VALUE(MRES_SUPERCEDE, (argc<3)?g_fakecmd.argv[argc]:""); + RETURN_META_VALUE(MRES_IGNORED, NULL); +} + +int Cmd_Argc( void ) { + if (g_fakecmd.fake) RETURN_META_VALUE(MRES_SUPERCEDE, g_fakecmd.argc ); + RETURN_META_VALUE(MRES_IGNORED, 0); +} + +// Grenade has been thrown. +// Only here we may find out who is an owner. +void SetModel(edict_t *e, const char *m){ + if(e->v.owner&&m[7]=='w'&&m[8]=='_'&&m[9]=='h') + g_grenades.put( e , 1.75, 4, GET_PLAYER_POINTER(e->v.owner) ); + RETURN_META(MRES_IGNORED); +} + +// Save at what part of body a player is aiming +void TraceLine_Post(const float *v1, const float *v2, int fNoMonsters, edict_t *e, TraceResult *ptr) { + if ( e && ( e->v.flags & (FL_CLIENT | FL_FAKECLIENT) ) ) { + CPlayer* pPlayer = GET_PLAYER_POINTER(e); + if (ptr->pHit&&(ptr->pHit->v.flags& (FL_CLIENT | FL_FAKECLIENT) )) + pPlayer->aiming = ptr->iHitgroup; + pPlayer->lastTrace = pPlayer->thisTrace; + pPlayer->thisTrace = ptr->vecEndPos; + } + RETURN_META(MRES_IGNORED); +} + +void AlertMessage_Post(ALERT_TYPE atype, char *szFmt, ...) { + + if ( atype != at_logged ) RETURN_META(MRES_IGNORED); + + /* There are also more messages but we want only logs + at_notice, + at_console, // same as at_notice, but forces a ConPrintf, not a message box + at_aiconsole, // same as at_console, but only shown if developer level is 2! + at_warning, + at_error, + at_logged // Server print to console ( only in multiplayer games ). + */ + + if ( g_logevents.logEventsExist() ) + { + va_list logArgPtr; + va_start ( logArgPtr , szFmt ); + g_logevents.setLogString( szFmt , logArgPtr ); + va_end ( logArgPtr ); + g_logevents.parseLogString( ); + g_logevents.executeLogEvents( ); + + +#if 0 // ######### this is done by call above + LogEventsMngr::iterator a = g_logevents.begin(); + int err; +#ifdef ENABLEEXEPTIONS + try + { +#endif + while ( a ) + { + if ((err = amx_Exec((*a).getPlugin()->getAMX(), NULL , (*a).getFunction() , 1,mPlayerIndex)) != AMX_ERR_NONE) + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n",err,(*a).getPlugin()->getAMX()->curline,(*a).getPlugin()->getName()); + + ++a; + + } + +#ifdef ENABLEEXEPTIONS + } + catch( ... ) + { + print_srvconsole( "[AMX] fatal error at log event execution\n"); + } +#endif +#endif + + g_forwards.executeForwards(FF_PluginLog); + } + else if (g_forwards.forwardsExist( FF_PluginLog )) + { + va_list logArgPtr; + va_start ( logArgPtr , szFmt ); + g_logevents.setLogString( szFmt , logArgPtr ); + va_end ( logArgPtr ); + g_logevents.parseLogString( ); + g_forwards.executeForwards(FF_PluginLog); + } + RETURN_META(MRES_IGNORED); +} + +C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) { + gpMetaUtilFuncs=pMetaUtilFuncs; + *pPlugInfo=&Plugin_info; + if(strcmp(ifvers, Plugin_info.ifvers)) { + int mmajor=0, mminor=0, pmajor=0, pminor=0; + LOG_MESSAGE(PLID, "WARNING: meta-interface version mismatch; requested=%s ours=%s", Plugin_info.logtag, ifvers); + sscanf(ifvers, "%d:%d", &mmajor, &mminor); + sscanf(META_INTERFACE_VERSION, "%d:%d", &pmajor, &pminor); + if(pmajor > 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.pfnGetEntityAPI2_Post = GetEntityAPI2_Post; + gMetaFunctionTable.pfnGetEngineFunctions = GetEngineFunctions; + gMetaFunctionTable.pfnGetEngineFunctions_Post = GetEngineFunctions_Post; + memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS)); + gpGamedllFuncs=pGamedllFuncs; + CVAR_REGISTER (&init_amx_version); + amx_version = CVAR_GET_POINTER(init_amx_version.name ); + REG_SVR_COMMAND("amx",amx_command); + + char gameDir[512]; + GET_GAME_DIR(gameDir); + char *a = gameDir; + int i = 0; + while ( gameDir[i] ) + if (gameDir[i++] == '/') + a = &gameDir[i]; + g_mod_name.set(a); + + // ###### Now attach metamod modules + attachMetaModModules( get_localinfo("amx_modules" , + "addons/amx/modules.ini" ) ); + + 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); + } + g_auth.clear(); + g_forwards.clear(); + g_commands.clear(); + g_forcemodels.clear(); + g_forcesounds.clear(); + g_forcegeneric.clear(); + g_grenades.clear(); + g_tasksMngr.clear(); + g_logevents.clearLogEvents(); + g_events.clearEvents(); + g_menucmds.clear(); + g_vault.clear(); + g_xvars.clear(); + g_plugins.clear(); + g_cvars.clear(); + + dettachModules(); + + // ###### Now dettach metamod modules + dettachMetaModModules( get_localinfo("amx_modules" , + "addons/amx/modules.ini" ) ); + + return(TRUE); +} + +C_DLLEXPORT void WINAPI GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) { + memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); + gpGlobals = pGlobals; +} + +DLL_FUNCTIONS gFunctionTable; +C_DLLEXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ){ + gFunctionTable.pfnSpawn = Spawn; + gFunctionTable.pfnClientCommand = ClientCommand; + gFunctionTable.pfnServerDeactivate = ServerDeactivate; + gFunctionTable.pfnClientDisconnect = ClientDisconnect; + gFunctionTable.pfnInconsistentFile = InconsistentFile; + gFunctionTable.pfnServerActivate = ServerActivate; + + 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); +} + +DLL_FUNCTIONS gFunctionTable_Post; +C_DLLEXPORT int GetEntityAPI2_Post( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) { + gFunctionTable_Post.pfnClientPutInServer = ClientPutInServer_Post; + gFunctionTable_Post.pfnClientUserInfoChanged = ClientUserInfoChanged_Post; + gFunctionTable_Post.pfnServerActivate = ServerActivate_Post; + gFunctionTable_Post.pfnClientConnect = ClientConnect_Post; + gFunctionTable_Post.pfnStartFrame = StartFrame_Post; + gFunctionTable_Post.pfnServerDeactivate = ServerDeactivate_Post; + + if(*interfaceVersion!=INTERFACE_VERSION) { + LOG_ERROR(PLID, "GetEntityAPI2_Post version mismatch; requested=%d ours=%d", *interfaceVersion, INTERFACE_VERSION); + *interfaceVersion = INTERFACE_VERSION; + return(FALSE); + } + memcpy( pFunctionTable, &gFunctionTable_Post, sizeof( DLL_FUNCTIONS ) ); + return(TRUE); +} + +enginefuncs_t meta_engfuncs; +C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion ) { + + if ( stricmp(g_mod_name.str(),"cstrike") == 0 ) + { + meta_engfuncs.pfnSetModel = SetModel; + g_bmod_cstrike = true; + } + else + { + g_bmod_cstrike = false; + g_bmod_dod = !stricmp(g_mod_name.str(),"dod"); + } + + meta_engfuncs.pfnCmd_Argc = Cmd_Argc; + meta_engfuncs.pfnCmd_Argv = Cmd_Argv; + meta_engfuncs.pfnCmd_Args = Cmd_Args; + meta_engfuncs.pfnPrecacheModel = PrecacheModel; + meta_engfuncs.pfnPrecacheSound = PrecacheSound; + + 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 ) { + meta_engfuncs_post.pfnTraceLine = TraceLine_Post; + meta_engfuncs_post.pfnMessageBegin = MessageBegin_Post; + meta_engfuncs_post.pfnMessageEnd = MessageEnd_Post; + meta_engfuncs_post.pfnWriteByte = WriteByte_Post; + meta_engfuncs_post.pfnWriteChar = WriteChar_Post; + meta_engfuncs_post.pfnWriteShort = WriteShort_Post; + meta_engfuncs_post.pfnWriteLong = WriteLong_Post; + meta_engfuncs_post.pfnWriteAngle = WriteAngle_Post; + meta_engfuncs_post.pfnWriteCoord = WriteCoord_Post; + meta_engfuncs_post.pfnWriteString = WriteString_Post; + meta_engfuncs_post.pfnWriteEntity = WriteEntity_Post; + meta_engfuncs_post.pfnAlertMessage = AlertMessage_Post; + meta_engfuncs_post.pfnRegUserMsg = RegUserMsg_Post; + + + 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); +} diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp new file mode 100755 index 00000000..e2ae84b5 --- /dev/null +++ b/amxmodx/modules.cpp @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" +#include "osdep.h" // sleep, etc +#include "CFile.h" + +CList g_modules; +CList g_loadedscripts; + +#ifdef __cplusplus +extern "C" { +#endif +extern const char* no_function; // stupid work around +#ifdef __cplusplus +} +#endif + +void report_error( int code, char* fmt, ... ) +{ + va_list argptr; + char string[256]; + *string = 0; + va_start (argptr, fmt); + vsnprintf (string, 255, fmt,argptr); + string[255] = 0; + va_end (argptr); + if ( *string ) { + //File fp( "error_amx.log","a" ); + //fp << string; + print_srvconsole( string ); + print_srvconsole("[AMX] Make sure that modules are compatible with AMX %s\n" , AMX_VERSION ); + print_srvconsole("[AMX] Please fix the problem then start the server again\n" ); + } + sleep( 5 ); + exit( code ); +} + +void print_srvconsole( char *fmt, ... ) +{ + va_list argptr; + char string[256]; + va_start (argptr, fmt); + vsnprintf (string, 255, fmt,argptr); + string[255] = 0; + va_end (argptr); + SERVER_PRINT(string); +} + +void* alloc_amxmemory(void** p, int size) +{ + *p = new unsigned char[ size ]; + return *p; +} + +void free_amxmemory(void **ptr) +{ + delete[] *ptr; + *ptr = 0; +} + +int load_amxscript(AMX *amx, void **program, const char *filename, char error[64]){ + + AMX_HEADER hdr; + int err; + FILE *fp; + + memset(amx, 0, sizeof(*amx)); + *program = 0; + *error = 0; + + if ( (fp = fopen( filename, "rb" )) == NULL) + { + strcpy(error,"Plugin file open error"); + return (amx->error = AMX_ERR_NOTFOUND); + } + + fread(&hdr, sizeof(hdr), 1, fp); + + amx_Align16(&hdr.magic); + + if (hdr.magic!=AMX_MAGIC) + { + strcpy(error,"Invalid plugin"); + return (amx->error = AMX_ERR_FORMAT); + } + + amx_Align32((uint32_t *)&hdr.stp); + amx_Align32((uint32_t *)&hdr.size); + + if ( (*program = new unsigned char[ (int)hdr.stp ]) == 0 ) + //if ( (*program = malloc( (int)hdr.stp )) == 0 ) + { + strcpy(error,"Failed to allocate memory"); + return (amx->error = AMX_ERR_MEMORY); + } + + rewind(fp); + fread(*program, 1, (size_t)hdr.size, fp); + fclose(fp); + + if ((err = amx_Init( amx, *program )) != AMX_ERR_NONE) + { + sprintf(error,"Load error %d (invalid file format or version)", err); + return (amx->error = AMX_ERR_INIT); + } + + +#ifdef JIT + void *np = new unsigned char[ amx->code_size ]; + void *rt = new unsigned char[ amx->reloc_size ]; + if ( !np || (!rt && amx->reloc_size > 0) ) + { + delete[] np; + delete[] rt; + strcpy(error,"Failed to initialize plugin"); + return (amx->error = AMX_ERR_INIT); + } + + if (amx_InitJIT(amx, rt, np) == AMX_ERR_NONE) + { + //amx->base = (unsigned char FAR *)realloc( np, amx->code_size ); + amx->base = new unsigned char FAR[ amx->code_size ]; + if ( amx->base ) + memcpy( amx->base , np , amx->code_size ); + delete[] np; + delete[] rt; + delete[] *program; + (*program) = amx->base; + if ( *program == 0 ){ + strcpy(error,"Failed to allocate memory"); + return (amx->error = AMX_ERR_MEMORY); + } + } + else + { + delete[] np; + delete[] rt; + strcpy(error,"Failed to initialize plugin"); + return (amx->error = AMX_ERR_INIT_JIT); + } + +#endif + + CScript* aa = new CScript(amx,*program,filename); + + if ( aa == 0 ) + { + strcpy(error,"Failed to allocate memory"); + return (amx->error = AMX_ERR_MEMORY); + } + + g_loadedscripts.put( aa ); + return set_amxnatives(amx,error); +} + +int set_amxnatives(AMX* amx,char error[64]) +{ + for ( CList::iterator a = g_modules.begin(); a ; ++a ) + { + for( CList::iterator cc = + (*a).natives.begin(); cc; ++cc ) + amx_Register(amx, *cc , -1); + } + + amx_Register(amx, string_Natives, -1); + amx_Register(amx, float_Natives, -1); + amx_Register(amx, file_Natives, -1); + amx_Register(amx, amxmod_Natives, -1); + amx_Register(amx, power_Natives, -1); + amx_Register(amx, time_Natives, -1); + amx_Register(amx, vault_Natives, -1); + + if ( amx_Register(amx, core_Natives, -1) != AMX_ERR_NONE ) + { + sprintf(error,"Function not found (name \"%s\")",no_function); + return (amx->error = AMX_ERR_NATIVE); + } + + return AMX_ERR_NONE; +} + + +int unload_amxscript(AMX* amx, void** program) +{ + CList::iterator a = g_loadedscripts.find( amx ); + if ( a ) a.remove(); + delete[] *program; + //free( *program ); + *program = 0; + return AMX_ERR_NONE; +} + + +AMX* get_amxscript(int id , void** code, const char** filename) +{ + CList::iterator a = g_loadedscripts.begin(); + while ( a && id-- ) + ++a; + if ( a ){ + *filename = (*a).getName(); + *code = (*a).getCode(); + return (*a).getAMX(); + } + return 0; +} + +const char* get_amxscriptname(AMX* amx) +{ + CList::iterator a = g_loadedscripts.find( amx ); + return a ? (*a).getName() : ""; +} + +void get_modname(char* buffer ) +{ + strcpy( buffer , g_mod_name.str() ); +} + +char* build_pathname(char *fmt, ... ) +{ + static char string[256]; + + int b; + + int a = b = snprintf(string , 255 , + +#ifndef __linux__ + "%s\\", +#else + "%s/", +#endif + g_mod_name.str()); + + va_list argptr; + va_start (argptr, fmt); + a += vsnprintf (&string[a], 255 - a , fmt,argptr); + string[ a ] = 0; + va_end (argptr); + + char* path = &string[b]; + + while (*path) + { +#ifndef __linux__ + if (*path == '/') *path = '\\'; +#else + if (*path == '\\') *path = '/'; +#endif + ++path; + } + + return string; +} + +int add_amxnatives(module_info_s* info,AMX_NATIVE_INFO*natives) +{ + CList::iterator a = g_modules.begin(); + + while ( a ) + { + if ( (*a).getInfo() == info ) + { + AMX_NATIVE_INFO** aa = new AMX_NATIVE_INFO*(natives); + if ( aa == 0 ) return AMX_ERR_NATIVE; + (*a).natives.put( aa ); + return AMX_ERR_NONE; + } + + ++a; + } + + return AMX_ERR_NATIVE; +} + + +bool validFile(const char* file) +{ + const char* a = 0; + while(*file) + if (*file++=='.') + a = file; +#ifndef __linux__ + return (a && !strcmp(a,"dll")); +#else + return (a && !strcmp(a,"so")); +#endif +} + +int loadModules(const char* filename) +{ + File fp( build_pathname("%s",filename), "r" ); + + if ( !fp ) + { + print_srvconsole( "[AMX] Modules list not found (file \"%s\")\n",filename); + return 0; + } + + char line[256], moduleName[256]; + int loaded = 0; + + while ( fp.getline( line , 255 ) ) + { + *moduleName = 0; + sscanf(line,"%s",moduleName); + + if (!isalnum(*moduleName) || !validFile(moduleName) ) + continue; + + char* pathname = build_pathname("%s",moduleName); + + CList::iterator a = g_modules.find( pathname ); + + if ( a ) continue; // already loaded + + CModule* cc = new CModule( pathname ); + + if ( cc == 0 ) return loaded; + + cc->queryModule(); + + switch( cc->getStatusValue() ) { + case MODULE_BADLOAD: + report_error( 1 , "[AMX] Module is not a valid library (file \"%s\")\n",pathname ); + break; + case MODULE_NOINFO: + report_error( 1 ,"[AMX] Couldn't find info. about module (file \"%s\")\n",pathname ); + break; + case MODULE_NOQUERY: + report_error( 1 , "[AMX] Couldn't find \"AMX_Query\" (file \"%s\")\n", pathname ); + break; + case MODULE_NOATTACH: + report_error( 1 , "[AMX] Couldn't find \"AMX_Attach\" (file \"%s\")\n", pathname ); + break; + case MODULE_OLD: + report_error( 1 , "[AMX] Module has a different interface version (file \"%s\")\n",pathname ); + break; + default: + ++loaded; + } + + + g_modules.put( cc ); + } + + return loaded; +} + +void dettachModules() +{ + CList::iterator a = g_modules.begin(); + + while ( a ) + { + (*a).detachModule(); + a.remove(); + } +} + +void dettachReloadModules() +{ + CList::iterator a = g_modules.begin(); + + while ( a ) + { + if ( (*a).isReloadable() ) + { + (*a).detachModule(); + a.remove(); + continue; + } + + ++a; + } + +} + +void attachModules() +{ + CList::iterator a = g_modules.begin(); + + while ( a ) + { + (*a).attachModule(); + + ++a; + } +} + +const char* strip_name( const char* a ) +{ + const char* ret = a; + while(*a){ + if ( *a== '/' || *a=='\\' ){ + ret = ++a; + continue; + } + ++a; + } + return ret; +} + +void dettachMetaModModules( const char* filename ) +{ + File fp( build_pathname("%s",filename), "r" ); + + if ( !fp ) + { + print_srvconsole( "[AMX] Modules list not found (file \"%s\")\n",filename); + return; + } + + char line[256], moduleName[256], cmdline[256]; + DLHANDLE module; + + while ( fp.getline( line , 255 ) ) + { + *moduleName = 0; + sscanf(line,"%s",moduleName); + + if (!isalnum(*moduleName) || !validFile(moduleName) ) + continue; + + char* pathname = build_pathname("%s",moduleName); + + module = DLLOAD( pathname ); // link dll + + if ( module ) + { + int a = (int)DLPROC(module,"Meta_Attach"); + + if ( a ) + { + snprintf(cmdline,255, "meta unload %s\n", strip_name(moduleName) ); + cmdline[255] = 0; + SERVER_COMMAND( cmdline ); + } + + DLFREE(module); + } + } +} + +void attachMetaModModules( const char* filename ) +{ + File fp( build_pathname("%s",filename), "r" ); + + if ( !fp ) + { + print_srvconsole( "[AMX] Modules list not found (file \"%s\")\n",filename); + return; + } + + char line[256], moduleName[256], cmdline[256]; + DLHANDLE module; + + int loaded = 0; + + while ( fp.getline( line , 255 ) ) + { + *moduleName = 0; + sscanf(line,"%s",moduleName); + + if (!isalnum(*moduleName) || !validFile(moduleName) ) + continue; + + char* pathname = build_pathname("%s",moduleName); + + module = DLLOAD( pathname ); // link dll + + if ( module ) + { + int a = (int)DLPROC(module,"Meta_Attach"); + + if ( a ) + { + snprintf(cmdline,255, "meta load %s\n", moduleName ); + cmdline[255] = 0; + SERVER_COMMAND( cmdline ); + ++loaded; + } + + DLFREE(module); + } + } + + if ( loaded ) + { + SERVER_COMMAND( "restart\n" ); + /* must be or modules can cause crash + since they were not initialized with all routines (spawn, server active + players think, etc.) and metamod calls other routines + like nothing has never happened. */ + } +} + diff --git a/amxmodx/modules.h b/amxmodx/modules.h new file mode 100755 index 00000000..cd9f2052 --- /dev/null +++ b/amxmodx/modules.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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. + * + */ + +#ifndef __MODULES_H__ +#define __MODULES_H__ + +#include "amx.h" + +#undef DLLEXPORT +#ifndef __linux__ + #define DLLEXPORT __declspec(dllexport) +#else + #define DLLEXPORT + #define WINAPI +#endif + +#undef C_DLLEXPORT +#define C_DLLEXPORT extern "C" DLLEXPORT + +#define AMX_INTERFACE_VERSION 6 + +#define RELOAD_MODULE 0 +#define STATIC_MODULE 1 + +struct module_info_s { + const char* name; + const char* author; + const char* version; + int ivers; + int type; + long int serial; +}; + +// Small scripting language +struct pfnamx_engine_g { + uint16_t* (*pfnamx_Align16)(uint16_t *); // value + uint32_t* (*pfnamx_Align32)(uint32_t *); // value + int (*pfnamx_Allot)(AMX*, int, cell*, cell**); // amx, length, amx_addr, phys_addr + int (*pfnamx_Callback)(AMX*, cell , cell*, cell*); // amx, index,result,params + int (*pfnamx_Clone)(AMX*, AMX*, void*); // amxClone, amxSrc, data + int (*pfnamx_Debug)(AMX*); // default debug procedure, does nothing // amx + int (*pfnamx_Exec)(AMX*, cell*, int , int , ...); // amx, return val, index, num_params, ... + int (*pfnamx_Execv)(AMX*, cell*, int , int, cell[]); // amx, return val, index, num_params, param[] + int (*pfnamx_FindPublic)(AMX*, char*, int*); // amx, func name, index + int (*pfnamx_FindPubVar)(AMX*, char*, cell*); // anx, var name, amx_addr + int (*pfnamx_FindTagId)(AMX*, cell , char*); // amx. tag_id, tagname + int (*pfnamx_Flags)(AMX*,uint16_t *); // amx, flags + int (*pfnamx_GetAddr)(AMX*,cell ,cell**); // amx, amx_addr, phys_addr + int (*pfnamx_GetPublic)(AMX*, int , char*); // amx, index, funcname + int (*pfnamx_GetPubVar)(AMX*, int , char*, cell*); // amx, index, varname, amx_addr + int (*pfnamx_GetString)(char*dest,cell*); // dest, source + int (*pfnamx_GetTag)(AMX*, int , char*, cell*); // amx, index, tagname, tag_id + int (*pfnamx_GetUserData)(AMX*, long , void **); // amx, tag, ptr + int (*pfnamx_Init)(AMX*, void *); // amx, program + int (*pfnamx_InitJIT)(AMX*, void *, void *); // amx, reloc_table, native_code + int (*pfnamx_MemInfo)(AMX*, long*, long*, long*); // amx, codesize, datasize, stackheap + int (*pfnamx_NameLength)(AMX*, int*); // amx, length + AMX_NATIVE_INFO * (*pfnamx_NativeInfo)(char*,AMX_NATIVE ); // name, func + int (*pfnamx_NumPublics)(AMX*, int*); // amx, number + int (*pfnamx_NumPubVars)(AMX*, int*); // amx, number + int (*pfnamx_NumTags)(AMX*, int*); // amx, number + int (*pfnamx_RaiseError)(AMX*, int ); // amx, error + int (*pfnamx_Register)(AMX*, AMX_NATIVE_INFO*, int ); // amx, nativelist, number + int (*pfnamx_Release)(AMX*, cell ); // amx, amx_addr + int (*pfnamx_SetCallback)(AMX*, AMX_CALLBACK ); // amx, callback + int (*pfnamx_SetDebugHook)(AMX*, AMX_DEBUG ); // amx, debug + int (*pfnamx_SetString)(cell*, char*, int ); // dest, source, pack + int (*pfnamx_SetUserData)(AMX*, long , void*); // amx, tag, prt + int (*pfnamx_StrLen)(cell*, int*); // amx, cstring, length +}; +extern pfnamx_engine_g* g_engAmxFunc; + +#define AMX_ALIGN16 (*g_engAmxFunc->pfnamx_Align16) +#define AMX_ALIGN32 (*g_engAmxFunc->pfnamx_Align32) +#define AMX_ALLOT (*g_engAmxFunc->pfnamx_Allot) +#define AMX_CALLBACK (*g_engAmxFunc->pfnamx_Callback) +#define AMX_CLONE (*g_engAmxFunc->pfnamx_Clone) +#define AMX_DEBUG (*g_engAmxFunc->pfnamx_Debug) +#define AMX_EXEC (*g_engAmxFunc->pfnamx_Exec) +#define AMX_EXECV (*g_engAmxFunc->pfnamx_Execv) +#define AMX_FINDPUBLIC (*g_engAmxFunc->pfnamx_FindPublic) +#define AMX_FINDPUBVAR (*g_engAmxFunc->pfnamx_FindPubVar) +#define AMX_FINDTAGID (*g_engAmxFunc->pfnamx_FindTagId) +#define AMX_FLAGS (*g_engAmxFunc->pfnamx_Flags) +#define AMX_GETADDR (*g_engAmxFunc->pfnamx_GetAddr) +#define AMX_GETPUBLIC (*g_engAmxFunc->pfnamx_GetPublic) +#define AMX_GETPUBVAR (*g_engAmxFunc->pfnamx_GetPubVar) +#define AMX_GETSTRING (*g_engAmxFunc->pfnamx_GetString) +#define AMX_GETTAG (*g_engAmxFunc->pfnamx_GetTag) +#define AMX_GETUSERDATA (*g_engAmxFunc->pfnamx_GetUserData) +#define AMX_INIT (*g_engAmxFunc->pfnamx_Init) +#define AMX_INITJIT (*g_engAmxFunc->pfnamx_InitJIT) +#define AMX_MEMINFO (*g_engAmxFunc->pfnamx_MemInfo) +#define AMX_NAMELENGTH (*g_engAmxFunc->pfnamx_NameLength) +#define AMX_NATIVEINFO (*g_engAmxFunc->pfnamx_NativeInfo) +#define AMX_NUMPUBLICS (*g_engAmxFunc->pfnamx_NumPublics) +#define AMX_NUMPUBVARS (*g_engAmxFunc->pfnamx_NumPubVars) +#define AMX_NUMTAGS (*g_engAmxFunc->pfnamx_NumTags) +#define AMX_RAISEERROR (*g_engAmxFunc->pfnamx_RaiseError) +#define AMX_REGISTER (*g_engAmxFunc->pfnamx_Register) +#define AMX_RELEASE (*g_engAmxFunc->pfnamx_Release) +#define AMX_SETCALLBACK (*g_engAmxFunc->pfnamx_SetCallback) +#define AMX_SETDEBUGHOOK (*g_engAmxFunc->pfnamx_SetDebugHook) +#define AMX_SETSTRING (*g_engAmxFunc->pfnamx_SetString) +#define AMX_SETUSERDATA (*g_engAmxFunc->pfnamx_SetUserData) +#define AMX_STRLEN (*g_engAmxFunc->pfnamx_StrLen) + +// Modules API +struct pfnmodule_engine_g { + int (*pfnadd_amxnatives)(module_info_s*,AMX_NATIVE_INFO*); // list + char* (*pfnbuild_pathname)(char*, ...); // format, .... + void (*pfncopy_amxmemory)(cell*,cell*,int); // dest, src, len + char* (*pfnformat_amxstring)(AMX*, cell*, int ,int& ); // amx, format, start pos, len + cell* (*pfnget_amxaddr)(AMX*,cell ); // amx, cell + AMX* (*pfnget_amxscript)(int, void**,const char**); // id, code, name + const char* (*pfnget_amxscriptname)(AMX* amx); // amx + char* (*pfnget_amxstring)(AMX*,cell,int, int&); // amx, src, buffer (0-3), len + void (*pfnget_modname)(char*); // modname + int (*pfnload_amxscript)(AMX*, void**, const char*, char[64]); // amx, code, path, error info + void (*pfnprint_console)(char*, ...); // format, .... + void (*pfnreport_error)(int code, char*, ... ); + int (*pfnset_amxnatives)(AMX*,char[64]); // amx, error info + int (*pfnset_amxstring)(AMX*,cell ,const char*,int); // amx, dest, string, maxlen + int (*pfnamxstring_length)(cell*); // src + int (*pfnunload_amxscript)(AMX* amx,void**); // amx, code + void* (*pfnalloc_amxmemory)(void**,int size); + void (*pfnfree_amxmemory)(void**); +}; +extern pfnmodule_engine_g* g_engModuleFunc; + +#define ADD_AMXNATIVES (*g_engModuleFunc->pfnadd_amxnatives) +#define AMXSTRING_LENGTH (*g_engModuleFunc->pfnamxstring_length) +#define BUILD_PATHNAME (*g_engModuleFunc->pfnbuild_pathname) +#define COPY_AMXMEMORY (*g_engModuleFunc->pfncopy_amxmemory) +#define FORMAT_AMXSTRING (*g_engModuleFunc->pfnformat_amxstring) +#define GET_AMXADDR (*g_engModuleFunc->pfnget_amxaddr) +#define GET_AMXSCRIPT (*g_engModuleFunc->pfnget_amxscript) +#define GET_AMXSCRIPTNAME (*g_engModuleFunc->pfnget_amxscriptname) +#define GET_AMXSTRING (*g_engModuleFunc->pfnget_amxstring) +#define GET_MODNAME (*g_engModuleFunc->pfnget_modname) +#define LOAD_AMXSCRIPT (*g_engModuleFunc->pfnload_amxscript) +#define PRINT_CONSOLE (*g_engModuleFunc->pfnprint_console) +#define REPORT_ERROR (*g_engModuleFunc->pfnreport_error) +#define SET_AMXNATIVES (*g_engModuleFunc->pfnset_amxnatives) +#define SET_AMXSTRING (*g_engModuleFunc->pfnset_amxstring) +#define UNLOAD_AMXSCRIPT (*g_engModuleFunc->pfnunload_amxscript) +#define ALLOC_AMXMEMORY (*g_engModuleFunc->pfnalloc_amxmemory) +#define FREE_AMXMEMORY (*g_engModuleFunc->pfnfree_amxmemory) + + +#endif // __MODULES_H__ diff --git a/amxmodx/msvc/amxmod_mm.def b/amxmodx/msvc/amxmod_mm.def new file mode 100755 index 00000000..110c5633 --- /dev/null +++ b/amxmodx/msvc/amxmod_mm.def @@ -0,0 +1,6 @@ +LIBRARY amx_mm +EXPORTS + GiveFnptrsToDll @1 + +SECTIONS + .data READ WRITE diff --git a/amxmodx/msvc/amxmod_mm.dsp b/amxmodx/msvc/amxmod_mm.dsp new file mode 100755 index 00000000..9e318b10 --- /dev/null +++ b/amxmodx/msvc/amxmod_mm.dsp @@ -0,0 +1,288 @@ +# Microsoft Developer Studio Project File - Name="amxmod_mm" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=amxmod_mm - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "amxmod_mm.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "amxmod_mm.mak" CFG="amxmod_mm - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "amxmod_mm - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "amxmod_mm - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "amxmod_mm - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "release" +# PROP Intermediate_Dir "release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "amxmod_mm_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\metamod\metamod" /I "..\..\hlsdk\sourcecode\common" /I "..\..\hlsdk\sourcecode\engine" /I "..\..\hlsdk\sourcecode\dlls" /I "..\..\hlsdk\sourcecode\pm_shared" /I "..\extra\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "amxmod_mm_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /def:".\amxmod_mm.def" /out:"release/amx_mm.dll" /libpath:"..\extra\lib_win32" +# Begin Custom Build +TargetPath=.\release\amx_mm.dll +TargetName=amx_mm +InputPath=.\release\amx_mm.dll +SOURCE="$(InputPath)" + +"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetPath) D:\SIERRA\Half-Life\cstrike\addons\amx\dlls + +# End Custom Build + +!ELSEIF "$(CFG)" == "amxmod_mm - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "debug" +# PROP Intermediate_Dir "debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "amxmod_mm_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /Zp4 /MTd /W3 /Gm /GX /ZI /Od /I "..\..\metamod\metamod" /I "..\...\hlsdk\sourcecode\common" /I "..\...\hlsdk\sourcecode\engine" /I "..\...\hlsdk\sourcecode\dlls" /I "..\...\hlsdk\sourcecode\pm_shared" /I "..\extra\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "amxmod_mm_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /def:".\amxmod_mm.def" /out:"debug/amx_mm.dll" /pdbtype:sept /libpath:"..\extra\lib_win32" +# SUBTRACT LINK32 /incremental:no /nodefaultlib +# Begin Custom Build +TargetPath=.\debug\amx_mm.dll +TargetName=amx_mm +InputPath=.\debug\amx_mm.dll +SOURCE="$(InputPath)" + +"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetPath) D:\SIERRA\Half-Life\cstrike\addons\amx\dlls + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "amxmod_mm - Win32 Release" +# Name "amxmod_mm - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\amx.c +# End Source File +# Begin Source File + +SOURCE=..\amxcore.c +# End Source File +# Begin Source File + +SOURCE=..\amxmod.cpp +# End Source File +# Begin Source File + +SOURCE=..\amxtime.c +# End Source File +# Begin Source File + +SOURCE=..\CCmd.cpp +# End Source File +# Begin Source File + +SOURCE=..\CEvent.cpp +# End Source File +# Begin Source File + +SOURCE=..\CFile.cpp +# End Source File +# Begin Source File + +SOURCE=..\CForward.cpp +# End Source File +# Begin Source File + +SOURCE=..\CLogEvent.cpp +# End Source File +# Begin Source File + +SOURCE=..\CMenu.cpp +# End Source File +# Begin Source File + +SOURCE=..\CMisc.cpp +# End Source File +# Begin Source File + +SOURCE=..\CModule.cpp +# End Source File +# Begin Source File + +SOURCE=..\CPlugin.cpp +# End Source File +# Begin Source File + +SOURCE=..\CString.cpp +# End Source File +# Begin Source File + +SOURCE=..\CTask.cpp +# End Source File +# Begin Source File + +SOURCE=..\CVault.cpp +# End Source File +# Begin Source File + +SOURCE=..\emsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\file.cpp +# End Source File +# Begin Source File + +SOURCE=..\float.cpp +# End Source File +# Begin Source File + +SOURCE=..\meta_api.cpp +# End Source File +# Begin Source File + +SOURCE=..\modules.cpp +# End Source File +# Begin Source File + +SOURCE=..\power.c +# End Source File +# Begin Source File + +SOURCE=..\srvcmd.cpp +# End Source File +# Begin Source File + +SOURCE=..\string.cpp +# End Source File +# Begin Source File + +SOURCE=..\strptime.cpp +# End Source File +# Begin Source File + +SOURCE=..\util.cpp +# End Source File +# Begin Source File + +SOURCE=..\vault.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\amxmod.h +# End Source File +# Begin Source File + +SOURCE=..\CCmd.h +# End Source File +# Begin Source File + +SOURCE=..\CEvent.h +# End Source File +# Begin Source File + +SOURCE=..\CFile.h +# End Source File +# Begin Source File + +SOURCE=..\CForward.h +# End Source File +# Begin Source File + +SOURCE=..\CList.h +# End Source File +# Begin Source File + +SOURCE=..\CLogEvent.h +# End Source File +# Begin Source File + +SOURCE=..\CMenu.h +# End Source File +# Begin Source File + +SOURCE=..\CMisc.h +# End Source File +# Begin Source File + +SOURCE=..\CModule.h +# End Source File +# Begin Source File + +SOURCE=..\CPlugin.h +# End Source File +# Begin Source File + +SOURCE=..\CString.h +# End Source File +# Begin Source File + +SOURCE=..\CTask.h +# End Source File +# Begin Source File + +SOURCE=..\CVault.h +# End Source File +# Begin Source File + +SOURCE=..\modules.h +# End Source File +# End Group +# End Target +# End Project diff --git a/amxmodx/msvc/amxmod_mm.dsw b/amxmodx/msvc/amxmod_mm.dsw new file mode 100755 index 00000000..39106712 --- /dev/null +++ b/amxmodx/msvc/amxmod_mm.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "amxmod_mm"=.\amxmod_mm.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/amxmodx/osdefs.h b/amxmodx/osdefs.h new file mode 100755 index 00000000..60d61e68 --- /dev/null +++ b/amxmodx/osdefs.h @@ -0,0 +1,60 @@ +/* __MSDOS__ set when compiling for DOS (not Windows) + * _Windows set when compiling for any version of Microsoft Windows + * __WIN32__ set when compiling for Windows95 or WindowsNT (32 bit mode) + * __32BIT__ set when compiling in 32-bit "flat" mode (DOS or Windows) + * + * Copyright 1998-2002, ITB CompuPhase, The Netherlands. + * info@compuphase.com. + */ + +#ifndef _OSDEFS_H +#define _OSDEFS_H + +/* Every compiler uses different "default" macros to indicate the mode + * it is in. Throughout the source, we use the Borland C++ macros, so + * the macros of Watcom C/C++ and Microsoft Visual C/C++ are mapped to + * those of Borland C++. + */ +#if defined(__WATCOMC__) +# if defined(__WINDOWS__) || defined(__NT__) +# define _Windows 1 +# endif +# ifdef __386__ +# define __32BIT__ 1 +# endif +# if defined(_Windows) && defined(__32BIT__) +# define __WIN32__ 1 +# endif +#elif defined(_MSC_VER) +# if defined(_WINDOWS) || defined(_WIN32) +# define _Windows 1 +# endif +# ifdef _WIN32 +# define __WIN32__ 1 +# define __32BIT__ 1 +# endif +#endif + +#if defined __linux__ + #include +#endif + +/* Linux NOW has these */ +#if !defined BIG_ENDIAN + #define BIG_ENDIAN 4321 +#endif +#if !defined LITTLE_ENDIAN + #define LITTLE_ENDIAN 1234 +#endif + +/* educated guess, BYTE_ORDER is undefined, i386 is common => little endian */ +#if !defined BYTE_ORDER + #if defined UCLINUX + #define BYTE_ORDER BIG_ENDIAN + #else + #define BYTE_ORDER LITTLE_ENDIAN + #endif +#endif + +#endif /* _OSDEFS_H */ + diff --git a/amxmodx/power.c b/amxmodx/power.c new file mode 100755 index 00000000..f01fcdf0 --- /dev/null +++ b/amxmodx/power.c @@ -0,0 +1,42 @@ +/* This file implements two native functions. It is provided as + * an example to show how to add native functions. See the manual + * for more information. + * + * Copyright (c) ITB CompuPhase, 1998, 1999 + * This file may be freely used. No warranties of any kind. + */ +#include "amx.h" + +static cell power(AMX *amx, cell *params) +{ + /* power(value, exponent); + * params[1] = value + * params[2] = exponent + */ + cell result = 1; + while (params[2]-- > 0) + result *= params[1]; + return result; +} + +static cell sqroot(AMX *amx, cell *params) +{ + /* sqroot(value); + * params[1] = value + * This routine uses a simple successice approximation algorithm. + */ + cell div = params[1]; + cell result = 1; + while (div > result) { /* end when div == result, or just below */ + div = (div + result) / 2; /* take mean value as new divisor */ + result = params[1] / div; + } /* while */ + return div; +} + +AMX_NATIVE_INFO power_Natives[] = { + { "power", power }, + { "sqroot", sqroot }, + { 0, 0 } /* terminator */ +}; + diff --git a/amxmodx/sclinux.h b/amxmodx/sclinux.h new file mode 100755 index 00000000..a395c0ce --- /dev/null +++ b/amxmodx/sclinux.h @@ -0,0 +1,48 @@ +/* + * Things needed to compile under linux. + * + * Should be reworked totally to use GNU's 'configure' + */ + +/* + * Getchar is not a 'cool' replacement for MSDOS getch: Linux/unix depends on the features activated or not about the + * controlling terminal's tty. This means that ioctl(2) calls must be performed, for instance to have the controlling terminal tty's + * in 'raw' mode, if we want to be able to fetch a single character. This also means that everything must be put back + * correctly when the program ends. + * + * For interactive use of SRUN/SDBG if would be much better to use GNU's readline package: the user would be able to have + * a complete emacs/vi like line editing system. + * + * So we stick to getchar at the moment... (one needs to key ctrl-d to terminate input if getch is called with a controlling + * terminal driven by a tty having -raw) + */ +#define getch getchar +#define stricmp(a,b) strcasecmp(a,b) +#define strnicmp(a,b,c) strncasecmp(a,b,c) + +/* + * WinWorld wants '\'. Unices do not. + */ +#define DIRECTORY_SEP_CHAR '/' +#define DIRECTORY_SEP_STR "/" + +/* + * SC assumes that a computer is Little Endian unless told otherwise. It uses + * (and defines) the macros BYTE_ORDER and BIG_ENDIAN. + * For Linux, we must overrule these settings with those defined in glibc. + */ +#if !defined __BYTE_ORDER +# include +#endif + +#if defined __OpenBSD__ +# define __BYTE_ORDER BYTE_ORDER +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __BIG_ENDIAN BIG_ENDIAN +#endif + +#if !defined __BYTE_ORDER +# error "Can't figure computer byte order (__BYTE_ORDER macro not found)" +#endif + + diff --git a/amxmodx/srvcmd.cpp b/amxmodx/srvcmd.cpp new file mode 100755 index 00000000..99d56504 --- /dev/null +++ b/amxmodx/srvcmd.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" + +void amx_command(){ + + const char* cmd = CMD_ARGV(1); + + if (!strcmp(cmd,"plugins") || !strcmp(cmd,"list")) + { + + print_srvconsole( "Currently loaded plugins:\n"); + print_srvconsole( " %-18.17s %-8.7s %-17.16s %-16.15s %-9.8s\n", + "name","version","author","file","status"); + + int plugins = 0; + int running = 0; + + + CPluginMngr::iterator a = g_plugins.begin(); + + while (a) + { + ++plugins; + + if ( (*a).isValid() && !(*a).isPaused() ) + ++running; + + print_srvconsole( " [%3d] %-18.17s %-8.7s %-17.16s %-16.15s %-9.8s\n", + plugins,(*a).getTitle(),(*a).getVersion(), + (*a).getAuthor(), (*a).getName(), (*a).getStatus() ); + + ++a; + } + + print_srvconsole( "%d plugins, %d running\n",plugins,running ); + + } + else if (!strcmp(cmd,"pause") && CMD_ARGC() > 2) + { + const char* sPlugin = CMD_ARGV(2); + + CPluginMngr::CPlugin *plugin = g_plugins.findPlugin(sPlugin); + + if ( plugin && plugin->isValid() ) + { + plugin->pausePlugin(); + print_srvconsole("Paused plugin \"%s\"\n",plugin->getName() ); + } + else print_srvconsole("Couldn't find plugin matching \"%s\"\n",sPlugin); + + } + else if (!strcmp(cmd,"unpause") && CMD_ARGC() > 2) + { + const char* sPlugin = CMD_ARGV(2); + + CPluginMngr::CPlugin *plugin = g_plugins.findPlugin(sPlugin); + + if ( plugin && plugin->isValid() ) + { + plugin->unpausePlugin(); + print_srvconsole("Unpaused plugin \"%s\"\n",plugin->getName() ); + } + else print_srvconsole("Couldn't find plugin matching \"%s\"\n",sPlugin); + + } + else if (!strcmp(cmd,"cvars")) + { + print_srvconsole( "Registered cvars:\n"); + print_srvconsole( " %-24.23s %-24.23s %-16.15s\n", + "name","value","plugin"); + + int ammount = 0; + + for( CList::iterator a = g_cvars.begin(); a ; ++a ) + { + print_srvconsole( " [%3d] %-24.23s %-24.23s %-16.15s\n",++ammount, + (*a).getName() ,CVAR_GET_STRING( (*a).getName() ),(*a).getPluginName() ); + } + + print_srvconsole( "%d cvars\n",ammount); + } + else if ( !strcmp(cmd,"cmds") ) + { + + print_srvconsole( "Registered commands:\n"); + print_srvconsole( " %-24.23s %-16.15s %-8.7s %-16.15s\n", + "name","access" ,"type" ,"plugin"); + + int ammount = 0; + + char access[32]; + + CmdMngr::iterator a = g_commands.begin( CMD_ConsoleCommand ); + + while( a ) + { + UTIL_GetFlags( access , (*a).getFlags() ); + print_srvconsole( " [%3d] %-24.23s %-16.15s %-8.7s %-16.15s\n", + ++ammount,(*a).getCmdLine() , access , (*a).getCmdType() , (*a).getPlugin()->getName()); + ++a; + } + + print_srvconsole( "%d commands\n",ammount); + } + else if (!strcmp(cmd,"version")) + { + + print_srvconsole( "%s %s\n", Plugin_info.name, Plugin_info.version); + print_srvconsole( "author: %s (%s)\n", Plugin_info.author, Plugin_info.url); + print_srvconsole( "compiled: %s\n", __DATE__ ", " __TIME__); + + } + else if (!strcmp(cmd,"modules")) + { + print_srvconsole( "Currently loaded modules:\n"); + print_srvconsole( " %-23.22s %-7.8s %-8.7s %-20.19s %-11.10s\n", + "name","type","version", "author", "status"); + + int running = 0; + int modules = 0; + + CList::iterator a = g_modules.begin(); + + while ( a ) + { + if ( (*a).getStatusValue() == MODULE_LOADED ) + ++running; + + ++modules; + + print_srvconsole( " [%2d] %-23.22s %-7.6s %-8.7s %-20.19s %-11.10s\n",modules, + (*a).getName(), (*a).getType(), (*a).getVersion(), (*a).getAuthor() , (*a).getStatus() ); + + ++a; + } + + print_srvconsole( "%d modules, %d correct\n",modules,running); + } + else + { + + + print_srvconsole("Usage: amx < command > [ argument ]\n"); + print_srvconsole("Commands:\n"); + print_srvconsole(" version - display amx version info\n"); + print_srvconsole(" plugins - list plugins currently loaded\n"); + print_srvconsole(" modules - list modules currently loaded\n"); + print_srvconsole(" cvars - list cvars registered by plugins\n"); + print_srvconsole(" cmds - list commands registered by plugins\n"); + print_srvconsole(" pause < plugin > - pause a running plugin\n"); + print_srvconsole(" unpause < plugin > - unpause a previously paused plugin\n"); + + + } +} + + +void plugin_srvcmd() +{ + + cell ret = 0; + int err; + const char* cmd = CMD_ARGV(0); + +#ifdef ENABLEEXEPTIONS + try{ +#endif + + CmdMngr::iterator a = g_commands.srvcmdbegin(); + + while ( a ) + { + if ( (*a).matchCommand( cmd ) && + (*a).getPlugin()->isExecutable( (*a).getFunction() ) ) + { + + if ((err = amx_Exec( (*a).getPlugin()->getAMX(), &ret , (*a).getFunction() + , 3 , g_srvindex , (*a).getFlags() , (*a).getId() )) != AMX_ERR_NONE) + + print_srvconsole("[AMX] Run time error %d on line %ld (plugin \"%s\")\n", + err,(*a).getPlugin()->getAMX()->curline,(*a).getPlugin()->getName()); + + if ( ret ) break; + } + + ++a; + } + +#ifdef ENABLEEXEPTIONS + }catch( ... ) + { + print_srvconsole( "[AMX] fatal error at forward function execution\n"); + } +#endif + +} diff --git a/amxmodx/string.cpp b/amxmodx/string.cpp new file mode 100755 index 00000000..05f17518 --- /dev/null +++ b/amxmodx/string.cpp @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" + +const char* stristr(const char* str,const char* substr) +{ + register char *needle = (char *)substr; + register char *prevloc = (char *)str; + register char *haystack = (char *)str; + + while (*haystack) { + if (tolower(*haystack) == tolower(*needle)) { + haystack++; + if (!*++needle) + return prevloc; + } + else { + haystack = ++prevloc; + needle = (char *)substr; + } + } + + return NULL; +} + +char* format_amxstring(AMX *amx, cell *params, int parm,int& len) +{ + static char buffer[2][3072]; + static char format[16]; + char *ptr,*arg; + char *dest = *buffer; + cell *src = get_amxaddr(amx, params[parm++]); + int numparam = *params/sizeof(cell); + while(*src) { + if (*src=='%'&&*(src+1)) { + ptr = format; + *ptr++ = *src++; + if (*src=='%'){ + *dest++=*src++; + continue; + } + while (!isalpha(*ptr++=*src++)) + ; + *ptr=0; + if (numparam < parm) continue; + arg = buffer[1]; + switch(*(ptr-1)){ + case 's': sprintf(arg,format,get_amxstring(amx, params[parm++],2,len)); break; + case 'f': case 'g': sprintf(arg,format,*(float*)get_amxaddr(amx, params[parm++])); break; + default: sprintf(arg,format,(int)*get_amxaddr(amx, params[parm++])); + } + while(*arg) *dest++=*arg++; + continue; + } + *dest++=*src++; + + } + *dest=0; + len = dest - *buffer; + return *buffer; +} + +int amxstring_len(cell* a) +{ + register int c = 0; + + while( a[ c ] ) + ++c; + + return c; +} + +cell* get_amxaddr(AMX *amx,cell amx_addr) +{ + return (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); +} + +int set_amxstring(AMX *amx,cell amx_addr,const char *source,int max) +{ + cell* dest = (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); + cell* start = dest; + while (max--&&*source) + *dest++=(cell)*source++; + *dest = 0; + return dest-start; +} + +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; +} + +void copy_amxmemory(cell* dest,cell* src,int len) +{ + while (len--) + *dest++=*src++; +} + + +char* parse_arg(char** line,int& state) +{ + static char arg[3072]; + char* dest = arg; + state = 0; + while(**line) { + if ( isspace(**line) ) { + if (state == 1) + break; + else if (!state) { + (*line)++; + continue; + } + } + else if (state != 2) + state = 1; + if (**line=='"') { + (*line)++; + if (state == 2) + break; + state = 2; + continue; + } + *dest++ = *(*line)++; + } + *dest = '\0'; + return arg; +} + +static cell AMX_NATIVE_CALL replace(AMX *amx, cell *params) /* 4 param */ +{ + static char buffor[3072]; + cell *a = get_amxaddr(amx,params[1]); + cell *b = get_amxaddr(amx,params[3]); + cell *c = get_amxaddr(amx,params[4]); + int iMain = amxstring_len(a); + int iWhat = amxstring_len(b); + int iWith = amxstring_len(c); + int iPot = iMain + iWith - iWhat; + if (iPot>=params[2]){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + char *d = buffor; + cell *x, *y, *z = a, *l = a; + int p = 0; + while(*a){ + if (*a==*b){ + x=a+1; + y=b+1; + p=1; + if (!*y) break; + while(*x==*y){ + x++; y++; p++; + if (!*y) break; + } + if (!*y) break; + p = 0; + *d++=(char)*a++; + continue; + } + *d++=(char)*a++; + } + if (p){ + while(*c) *d++=(char)*c++; + a+=p; + while(*a) *d++=(char)*a++; + *d=0; + d = buffor; + while(*d) *z++=*d++; + *z=0; + return (z-l); + } + return 0; +} + +static cell AMX_NATIVE_CALL contain(AMX *amx, cell *params) /* 2 param */ +{ + register cell *a = get_amxaddr(amx,params[2]); + register cell *b = get_amxaddr(amx,params[1]); + register cell *c = b; + cell* str = b; + cell* substr = a; + while (*c) { + if (*c == *a) { + c++; + if (!*++a) + return b - str; + } + else { + c = ++b; + a = substr; + } + } + return -1; +} + +static cell AMX_NATIVE_CALL containi(AMX *amx, cell *params) /* 2 param */ +{ + register cell *a = get_amxaddr(amx,params[2]); + register cell *b = get_amxaddr(amx,params[1]); + register cell *c = b; + cell* str = b; + cell* substr = a; + while (*c) { + if (tolower(*c) == tolower(*a)) { + c++; + if (!*++a) + return b - str; + } + else { + c = ++b; + a = substr; + } + } + return -1; +} + +static cell AMX_NATIVE_CALL strtonum(AMX *amx, cell *params) /* 1 param */ +{ + int iLen; + return atoi(get_amxstring(amx,params[1],0,iLen)); +} + +static cell AMX_NATIVE_CALL numtostr(AMX *amx, cell *params) /* 3 param */ +{ + char szTemp[32]; + sprintf(szTemp,"%d",(int)params[1]); + return set_amxstring(amx,params[2],szTemp,params[3]); +} + +static cell AMX_NATIVE_CALL add(AMX *amx, cell *params) /* 4 param */ +{ + cell *src = get_amxaddr(amx,params[3]); + cell *dest = get_amxaddr(amx,params[1]); + cell *start = dest; + int c = params[2], d = params[4]; + while(*dest&&c--) + ++dest; + if (d){ + while(c--&&d--&&*src) + *dest++=*src++; + *dest=0; + return (dest-start); + } + while(c--&&*src) + *dest++=*src++; + *dest=0; + return (dest-start); +} + +static cell AMX_NATIVE_CALL copy(AMX *amx, cell *params) /* 4 param */ +{ + cell *src = get_amxaddr(amx,params[3]); + cell *dest = get_amxaddr(amx,params[1]); + cell *start = dest; + int c = params[2]; + while(c--&&*src) + *dest++=*src++; + *dest=0; + return (dest-start); +} + +static cell AMX_NATIVE_CALL copyc(AMX *amx, cell *params) /* 4 param */ +{ + cell *src = get_amxaddr(amx,params[3]); + cell *dest = get_amxaddr(amx,params[1]); + cell *start = dest; + int c = params[2]; + cell ch = params[4]; + while(c--&&*src&&*src!=ch) + *dest++=*src++; + *dest=0; + return (dest-start); +} + +static cell AMX_NATIVE_CALL setc(AMX *amx, cell *params) /* 4 param */ +{ + cell *src = get_amxaddr(amx,params[1]); + int c = params[2]; + cell ch = params[3]; + while(c--) + *src++=ch; + return 1; +} + +static cell AMX_NATIVE_CALL equal(AMX *amx, cell *params) /* 3 param */ +{ + cell *a = get_amxaddr(amx,params[1]); + cell *b = get_amxaddr(amx,params[2]); + int c = params[3]; + if (c) { + while (--c&&*a&&(*a==*b)) + ++a, ++b; + return (*a-*b)?0:1; + } + int ret; + while(!(ret=*a-*b)&&*b) + ++a, ++b; + return ret?0:1; +} + +static cell AMX_NATIVE_CALL equali(AMX *amx, cell *params) /* 3 param */ +{ + cell *a = get_amxaddr(amx,params[1]); + cell *b = get_amxaddr(amx,params[2]); + int f,l, c = params[3]; + if (c) { + do { + f = tolower(*a++); + l = tolower(*b++); + } + while (--c &&l&&f&& f==l); + return(f - l)?0:1; + } + do { + f = tolower(*a++); + l = tolower(*b++); + } while (f && f == l); + return (f - l)?0:1; +} + +static cell AMX_NATIVE_CALL format(AMX *amx, cell *params) /* 3 param */ +{ + int len; + return set_amxstring(amx,params[1],format_amxstring(amx,params,3,len),params[2]); +} + +static cell AMX_NATIVE_CALL parse(AMX *amx, cell *params) /* 3 param */ +{ + int inum = *params/sizeof(cell), iarg = 2, c; + char* arg, *parse = get_amxstring(amx,params[1],0,c); + cell *cptr; + int state; + while(*parse){ + arg = parse_arg(&parse,state); + if (state){ + if (inum <= iarg) + return( (iarg-2)>>1 ); + cptr = get_amxaddr(amx,params[iarg++]); + c = *get_amxaddr(amx,params[iarg++]); + while(c--&&*arg) + *cptr++=(cell)*arg++; + *cptr=0; + } + } + + return( (iarg-2)>>1 ); +} + +static cell AMX_NATIVE_CALL strtolower(AMX *amx, cell *params) /* 1 param */ +{ + cell *cptr = get_amxaddr(amx,params[1]); + cell *begin = cptr; + while(*cptr){ + *cptr = tolower(*cptr); + cptr++; + } + return cptr - begin; +} + +static cell AMX_NATIVE_CALL strtoupper(AMX *amx, cell *params) /* 1 param */ +{ + cell *cptr = get_amxaddr(amx,params[1]); + cell *begin = cptr; + while(*cptr){ + *cptr = toupper(*cptr); + cptr++; + } + return cptr - begin; +} + +int fo_numargs(AMX *amx) +{ + unsigned char *data =amx->base+(int)((AMX_HEADER *)amx->base)->dat; + cell bytes= * (cell *)(data+(int)amx->frm+2*sizeof(cell)); + return (int)(bytes/sizeof(cell)); +} + +int fo_getargnum(AMX *amx, int pos) +{ + unsigned char *data =amx->base+(int)((AMX_HEADER *)amx->base)->dat; + cell value = * (cell *)(data+(int)amx->frm+(pos+3)*sizeof(cell)); + return *(cell *)(data+(int)value); +} + +float fo_getargfloat(AMX *amx, int pos) +{ + unsigned char *data =amx->base+(int)((AMX_HEADER *)amx->base)->dat; + cell value = * (cell *)(data+(int)amx->frm+(pos+3)*sizeof(cell)); + cell number = *(cell *)(data+(int)value); + return *(float *)((void *)&number); +} + +char* fo_getargstr(AMX *amx, int swap, int pos) +{ + unsigned char *data =amx->base+(int)((AMX_HEADER *)amx->base)->dat; + cell src_value= * (cell *)(data+(int)amx->frm+(pos+3)*sizeof(cell)); + cell value; + static char buffer[2][3072]; + char* b = buffer[swap]; + int a = 0; + do { + value = src_value + a++ * sizeof(cell); + value = *(cell *)(data+(int)value); + *b++ = value; + } while (value); + + return buffer[swap]; +} + +char* format_arguments(AMX *amx, int parm,int& len) +{ + static char buffer[2][3072]; + static char format[16]; + char *ptr,*arg, *dest = *buffer; + char *src = fo_getargstr(amx, 0,parm++); + int numparam = fo_numargs(amx); + while(*src) { + if (*src=='%'&&*(src+1)) { + ptr = format; + *ptr++ = *src++; + if (*src=='%'){ + *dest++=*src++; + continue; + } + while (!isalpha(*ptr++=*src++)) + ; + *ptr='\0'; + if (numparam < parm) continue; + arg = buffer[1]; + switch(*(ptr-1)){ + case 's': sprintf(arg,format,fo_getargstr(amx,1, parm++)); break; + case 'f': case 'g': sprintf(arg,format,fo_getargfloat(amx, parm++)); break; + default: sprintf(arg,format,fo_getargnum(amx, parm++)); + } + while(*arg) *dest++=*arg++; + continue; + } + *dest++=*src++; + } + *dest='\0'; + len = dest - *buffer; + return *buffer; +} + +static cell AMX_NATIVE_CALL format_args(AMX *amx, cell *params) +{ + int len; + int pos = params[3]; + if (pos < 0){ + amx_RaiseError(amx,AMX_ERR_NATIVE); + return 0; + } + char* string = format_arguments(amx, pos ,len); // indexed from 0 + return set_amxstring(amx,params[1],string,params[2]); +} + +static cell AMX_NATIVE_CALL is_digit(AMX *amx, cell *params) +{ + return isdigit( params[1] ); +} + +static cell AMX_NATIVE_CALL is_alnum(AMX *amx, cell *params) +{ + return isalnum( params[1] ); +} + +static cell AMX_NATIVE_CALL is_space(AMX *amx, cell *params) +{ + return isspace( params[1] ); +} + +static cell AMX_NATIVE_CALL is_alpha(AMX *amx, cell *params) +{ + return isalpha( params[1] ); +} + +AMX_NATIVE_INFO string_Natives[] = { + { "add", add }, + { "contain", contain }, + { "containi", containi }, + { "copy", copy }, + { "copyc", copyc }, + { "equal", equal }, + { "equali", equali }, + { "format", format }, + { "format_args", format_args }, + { "isdigit", is_digit }, + { "isalnum", is_alnum }, + { "isspace", is_space }, + { "isalpha", is_alpha }, + { "numtostr", numtostr }, + { "num_to_str", numtostr }, + { "parse", parse }, + { "replace", replace }, + { "setc", setc }, + { "strtolower", strtolower }, + { "strtonum", strtonum }, + { "strtoupper", strtoupper }, + { "str_to_num", strtonum }, + { NULL, NULL } +}; \ No newline at end of file diff --git a/amxmodx/strptime.cpp b/amxmodx/strptime.cpp new file mode 100755 index 00000000..3f93a7c8 --- /dev/null +++ b/amxmodx/strptime.cpp @@ -0,0 +1,398 @@ +/** strptime.c ********************************************************** + + Locales' support for DOS / Win31 / Win32. + Copyright (c) 1995-1997 by Timofei Bondarenko + + Localized strptime(). + *-----------------------------------------------------------------------*/ +//#include "config.h" +#include +#include +#include + +#ifdef __linux__ +#define strnicmp strncasecmp +#endif + +const char *_lc_Wday_ [2][ 7], + *_lc_Month_[2][12], + *_lc_AmPm_ [2][ 2]; + +const char *_lc_fmt_c_[2], + *_lc_fmt_xD[2], + *_lc_fmt_XT[2]; + +int _lc_Txt_, /* 0="C", 1="Local Win"/"Rus DOS" Wday, Months, AmPm */ + _lc_Fmt_; /* 0="C", 1="Local", for formats %c %x %X */ + +//#include "_locale.h" + +struct tm_int + { + int qS, /* Seconds (0...61) */ + qM, /* Minutes (0...59) */ + qH, /* Hour (0...23) */ + qI, /* Hour (1...12) */ + qp, /* 0 = AM, 1 = PM */ + qd, /* Day of month (1...31)=>[0...30] */ + qm, /* Month (1...12)=>[0...11] */ + qY, /* Year (0...9999) */ + qy, /* year (0...99) */ + qC, /* Century (0...99) */ + qw, /* Weekday (0...6; Sunday = 0) */ + qj, /* Day of year (1..366)=>[0...365] */ + qZ, /* 0 = STD, 1 = DST */ + qU, /* week in year (0...53) */ + qV; /* week in year mode: 'U', 'W', 'V' */ + }; + +/* skips spaces in `strp`. Returns 0 if no spaces skipped */ + +static void skip_sp(const unsigned char **strp) +{ + while(isspace(**strp)) (*strp)++; +} + +/* scans no more decimal digits than contained in `max` as an integer, + sign isn't allowed. Returns -1 if 0 digits scanned or + if the scanned number is greater than `max`. */ + +static int scan_int(const unsigned char **strp, int max) +{ + int cc, val, pos; + skip_sp(strp); + for(val = pos = 0; pos < max && isdigit(cc = **strp); (*strp)++) + { + pos = pos * 10 + 9; + if ((val = val * 10 + (cc - '0')) > max) return -1; + /*val = val * 10 + (cc - '0');*/ + } + return pos? val: -1; +} + +static int scan_int2(const unsigned char **strp) +{ + int cc, val, pos; + skip_sp(strp); + for(val = pos = 0; isdigit(cc = **strp); (*strp)++) + { + pos = pos * 10 + 9; + val = val * 10 + (cc - '0'); + } + return pos? val: -1; +} + +/* scans one word which is equivalence (case insensitive) to a + word from list `n_full` or from list `n_short` or when + n_short is NULL to first 3 characters from a word from `n_full`. + `max` is number of words in each list `n_full` or `n_short`. + Returns the index in a list >= 0 and < `max`, or -1 if no word found. */ + +static int scan_word_(const unsigned char **strp, + int max, const char *const *n_full +#if USE_ABBR_NAMES + , const char *const *n_short +#endif + ) +{ + int ix, l_max = 100; + int found, found_len; + const char *const *word_list; + + found = found_len = -1; + skip_sp(strp); /* Required? Or Not? */ +Scan0: + word_list = n_full; +/*Scan1:*/ + for(ix = 0; ix < max; word_list++, ix++) + { + int len; + const char *word = *word_list; + skip_sp((const unsigned char**)&word); + if (l_max < (len = strlen(word))) len = l_max; + if (found_len < len && /* search for maximal lenth */ + (!len || /* at least "" always founded */ + !strnicmp((const char*)*strp, word, len))) /* found */ + found_len = len, found = ix; + } + if (l_max >= 100) /* first pass: full names */ + { /* go to second pass: short names */ +#if USE_ABBR_NAMES + if (n_short) + { + l_max--; word_list = n_short; goto Scan1; + } +#endif + l_max = 3; goto Scan0; + } + if (found_len > 0) (*strp) += found_len; + return found; /* -1 or index or first "" */ +} + +#if USE_ABBR_NAMES +#define scan_word scan_word_ /* pass all arguments as is */ +#else +#define scan_word(str,max,n_full,n_short) scan_word_(str,max,n_full) +#endif + +static int time_int(struct tm_int *ti, + const unsigned char **buf, const char *fmt, short addthem) +{ + int ii; + + for(; (ii = (unsigned char)*fmt); fmt++) + if (ii != '%') + { +Other: + if (isspace(ii)) + { +/*SkipSp:*/ fmt++; skip_sp((const unsigned char **)&fmt); + fmt--; skip_sp(buf); + } /* toupper(ii) != toupper(**buf) */ + /*else if (_lc_igncase[ii] != _lc_igncase[**buf]) return -1;*/ + else (*buf)++; + } + else + { + const char *fs; +/*Fmt:*/ switch(ii = (unsigned char)*++fmt) + { + case 0 : goto FmtEnd; + case 'a': + case 'A': + ti->qw = ii = scan_word(buf, 7, + _lc_Wday_[_lc_Txt_], + _lc_Txt_? _lc_WdayS: NULL); break; + case 'h': /* STRFTIME_EXT */ + case 'b': + case 'B': + ti->qm = ii = scan_word(buf, 12, + _lc_Month_[_lc_Txt_], + _lc_Txt_? _lc_MonthS: NULL); break; + case 'c': + fs = _lc_fmt_c_[_lc_Fmt_]; +strpt: ii = time_int(ti, buf, fs, addthem); break; +#if STRFTIME_EXT + case 'C': /* STRFTIME_EXT */ + ti->qC = ii = addthem ? scan_int2(buf) : scan_int(buf,99); + if (ti->qy >= 0) goto SetYear; + else if (ti->qY >= 0) + { + ti->qY = ti->qY % 100 + ii * 100; + goto CleanCy; + } + break; + case 'e': /* STRFTIME_EXT */ +#endif + case 'd': + ti->qd = ii = (addthem ? scan_int2(buf) : scan_int(buf, 31)) - 1; break; +#if STRFTIME_EXT + case 'D': /* STRFTIME_EXT */ + fs = _lc_fmt_xD[0]; goto strpt; +/* case 'E': STRFTIME_EXT "Era specefic" see %'O' */ +/* case 'h': STRFTIME_EXT see %'b' */ +#endif + case 'H': + ti->qH = ii = addthem ? scan_int2(buf) : scan_int(buf, 23); +CleanIp: ti->qI = ti->qp = -1; break; + case 'I': + ti->qI = + ti->qH = ii = addthem ? scan_int2(buf) : scan_int(buf, 23); + if (ii == 0 || ii > 12) goto CleanIp; + else ti->qH = -1; + break; + case 'j': + ti->qj = ii = (addthem ? scan_int2(buf) : scan_int(buf, 366)) - 1; + ti->qU = -1; break; + case 'm': + ti->qm = ii = (addthem ? scan_int2(buf) : scan_int(buf, 12)) - 1; break; + case 'M': + ti->qM = ii = addthem ? scan_int2(buf) : scan_int(buf, 59); break; +#if STRFTIME_EXT + case 'n': /* STRFTIME_EXT */ + case 't': /* STRFTIME_EXT */ goto SkipSp; + case 'N': /* STRFTIME_EXT */ + fs = _lc_fmt_N_; goto strpt; + case 'E': /* STRFTIME_EXT "Era specefic" */ +#endif +#if STRFTIME_EXT | STRFTIME_WIN + case 'O': /* STRFTIME_EXT "Alternate digits" */ + goto Fmt; +#endif + case 'p': + ti->qp = /*ii =*/ scan_word(buf, 2, _lc_AmPm_[_lc_Txt_], NULL); + break; +#if STRFTIME_EXT + case 'r': /* STRFTIME_EXT */ + fs = _lc_fmt_rI; goto strpt; + case 'R': /* STRFTIME_EXT */ + fs = _lc_fmt_RH; goto strpt; +#endif + case 'S': + ti->qS = ii = addthem ? scan_int2(buf) : scan_int(buf, 61); break; +#if STRFTIME_EXT + case 'T': /* STRFTIME_EXT */ + fs = _lc_fmt_XT[0]; goto strpt; + case 'u': /* STRFTIME_EXT */ + ti->qw = ii = addthem ? scan_int2(buf) : scan_int(buf, 7); + if (ii == 7) ti->qw = 0; + else if (!ii) ii--; + break; +#endif +#if STRFTIME_EXT && 0 + case 'V': /* STRFTIME_EXT 0 = Wednesday ?(Thursday) */ +#endif + case 'U': + case 'W': + ti->qV = ii; + ti->qU = ii = addthem ? scan_int2(buf) : scan_int(buf, 53); break; + case 'w': + ti->qw = ii = addthem ? scan_int2(buf) : scan_int(buf, 6); break; + case 'x': + fs = _lc_fmt_xD[_lc_Fmt_]; goto strpt; + case 'X': + fs = _lc_fmt_XT[_lc_Fmt_]; goto strpt; + case 'y': + ti->qy = ii = addthem ? scan_int2(buf) : scan_int(buf, 99); +#if STRFTIME_EXT + if (ti->qC >= 0) + { +SetYear: ti->qY = ti->qC * 100 + ti->qy; + goto CleanCy; + } +#endif + if (ti->qY >= 0) + { + ti->qY = ti->qY - ti->qY % 100 + ii; + goto CleanCy; + } + break; + case 'Y': + ti->qY = ii = addthem ? scan_int2(buf) : scan_int(buf, 9999); +CleanCy: ti->qC = ti->qy = -1; break; +#if STRFTIME_EXT + case 'Z': /* STRFTIME_EXT */ + ti->qZ = ii = scan_word(buf, /*!daylight? 1:*/ 2, tzname, NULL) +1; + if (!ii) + while((ii = **buf) && !isspace(ii) + /*&& !isdigit(ii) && !strchr("+-,", ii)*/ + ) (*buf)++; + break; +#endif +/* case '%': */ + default: /**************************/ goto Other; + } /* end of switch() */ + if (ii < 0) return -1; + } /* end of else, for() */ +FmtEnd: + return 0; +} + +typedef void (*specoper)(int* one, int two); +void justreplace(int* one, int two){ + *one = two; +} +void justadd(int* one, int two){ + *one += two; +} + +char *strptime(const char *buf, const char *fmt, struct tm *tm, short addthem) +{ + specoper defoper = addthem ? justadd : justreplace; + + struct tm_int ti; + ti.qS = /* Seconds (0...61) */ + ti.qM = /* Minutes (0...59) */ + ti.qH = /* Hour (0...23) */ + ti.qI = /* Hour (1...12) */ + ti.qp = /* 0 = AM, 1 = PM */ + ti.qd = /* Day of month (1...31)=>[0...30] */ + ti.qm = /* Month (1...12)=>[0...11] */ + ti.qY = /* Year (0...9999) */ + ti.qy = /* year (0...99) */ + ti.qC = /* Century (0...99) */ + ti.qw = /* Weekday (0...6; Sunday = 0) */ + ti.qj = /* Day of year (1..366)=>[0...365] */ + ti.qZ = /* 0 = STD, 1 = DST */ + ti.qU = /* week in year (0...53) */ + ti.qV = -1; /* week in year mode: 0=U, 1=W, 2=V */ + + if (0 > time_int(&ti, (const unsigned char **)&buf, fmt, addthem)) buf = NULL; + if (0 <= ti.qS) (*defoper) ( &tm->tm_sec , ti.qS ); + if (0 <= ti.qM) (*defoper) ( &tm->tm_min , ti.qM ); //tm->tm_min = ti.qM; + if (0 <= ti.qI) + if (0 <= ti.qp) ti.qH = ti.qI % 12 + ti.qp * 12; + else (*defoper) ( &tm->tm_hour , ti.qI ); //tm->tm_hour = ti.qI; + if (0 <= ti.qH) (*defoper) ( &tm->tm_hour , ti.qH ); //tm->tm_hour = ti.qH; + if (0 <= ti.qZ) (*defoper) ( &tm->tm_isdst , ti.qZ - 1 ); //tm->tm_isdst = ti.qZ - 1; + if (0 <= ti.qy) ti.qY = ti.qy; + if (0 <= ti.qY) (*defoper) ( &tm->tm_year , + ti.qY += + (ti.qY > 99? -1900: + (ti.qY < 70? 100: 0)) ); + /*tm->tm_year = ti.qY += + (ti.qY > 99? -1900: + (ti.qY < 70? 100: 0));*/ +/* ti.qC = %C = Century without an Year - ignored */ + + if (70 <= ti.qY && ti.qY < 200) /* a representable year */ + { + /* 01-01-70 was Thursday, 1968 was leap */ + int day = (((ti.qY - 69) >> 2) + ti.qY - 70 + 4) % 7; + /* 2100 wrongly assumed as leap! + if (ti.qY > 200 && --day < 0) day = 6; */ + + if (0 <= ti.qU && 0 <= ti.qw && 0 > ti.qj) + { + ti.qj = ti.qU * 7; + switch(ti.qV) + { + case 'U': /* %U Sun first */ + ti.qj += ti.qw - (day == 0 ? 7: day); + break; + case 'W': /* %W Mon first */ + ti.qj += (ti.qw + 6) % 7 + - (day == 1 ? 7: (day + 6) % 7); + break; +#if STRFTIME_EXT && 0 + case 'V': /* %V >= 4 day */ + if (ti.qU == 53) ti.qj = 0; + /* Sun first: */ + ti.qj += ti.qw - (day < 4 ? 7: 0) - day; + /* Mon first: + ti.qj += (ti.qw + 6) % 7 + - ((day + 6) % 7 < 5 ? 7: 0) + - (day + 6) % 7; */ + break; +#endif + default: break; + } + } +#if 0 /* Advanced validating for yday<>m/d/y */ + if (0 <= ti.qj) + { + static int m_days[12] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + int mon = (ti.qj + day) % 7; + + if (0 > ti.qw) ti.qw = mon; + else if (ti.qw != mon) return NULL; + + for(mon = 11; 0 > (day = /* not for 2100: && ti.qY != 200 */ + ti.qj - (m_days[mon] + (mon > 1 && !(ti.qY & 3)))) + ; mon--); + if (0 > ti.qd) ti.qd = day; + else if (ti.qd != day) return NULL; + if (0 > ti.qm) ti.qm = mon; + else if (ti.qm != mon) return NULL; + } +#endif + } + if (0 <= ti.qd) (*defoper) ( &tm->tm_mday , ti.qd + 1 ); //tm->tm_mday = ti.qd + 1; + if (0 <= ti.qm) (*defoper) ( &tm->tm_mon , ti.qm ); //tm->tm_mon = ti.qm; + if (0 <= ti.qw) (*defoper) ( &tm->tm_wday , ti.qw ); //tm->tm_wday = ti.qw; + if (0 <= ti.qj) (*defoper) ( &tm->tm_yday , ti.qj ); //tm->tm_yday = ti.qj; + + return (char*)buf; +} +/* end of strftime.c */ diff --git a/amxmodx/util.cpp b/amxmodx/util.cpp new file mode 100755 index 00000000..4c8b8de1 --- /dev/null +++ b/amxmodx/util.cpp @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "amxmod.h" + +int UTIL_ReadFlags(const char* c) +{ + int flags = 0; + while (*c) flags |= ( 1 << ( *c++ - 'a' ) ); + return flags; +} + +void UTIL_GetFlags(char* f,int a) +{ + for(int i='a';i<='z';++i){ + if ( a & 1 ) *f++ = i; + a >>= 1; + } + *f = 0; +} + +/* warning - don't pass here const string */ +void UTIL_ShowMenu( edict_t* pEdict, int slots, int time, char *menu, int mlen ) +{ + char *n = menu; + char c = 0; + int a; + + while ( *n ) { + a = mlen; + if ( a > 175 ) a = 175; + mlen -= a; + c = *(n+=a); + *n = 0; + MESSAGE_BEGIN( MSG_ONE , gmsgShowMenu, NULL, pEdict ); + WRITE_SHORT( slots ); + WRITE_CHAR( time ); + WRITE_BYTE( c ? TRUE : FALSE); + WRITE_STRING( menu ); + MESSAGE_END(); + *n = c; + menu = n; + } +} + +/* warning - don't pass here const string */ +void UTIL_ShowMOTD( edict_t *client , char *motd, int mlen, const char *name) +{ + MESSAGE_BEGIN( MSG_ONE , gmsgServerName, NULL, client ); + WRITE_STRING(name); + MESSAGE_END(); + + char *n = motd; + char c = 0; + int a; + + while ( *n ) { + a = mlen; + if ( a > 175 ) a = 175; + mlen -= a; + c = *(n+=a); + *n = 0; + MESSAGE_BEGIN( MSG_ONE , gmsgMOTD, NULL, client ); + WRITE_BYTE( c ? FALSE : TRUE ); + WRITE_STRING( motd ); + MESSAGE_END(); + *n = c; + motd = n; + } + + MESSAGE_BEGIN( MSG_ONE , gmsgServerName, NULL, client ); + WRITE_STRING( hostname->string ); + MESSAGE_END(); +} + +void UTIL_IntToString(int value, char *output) +{ + static const char *words[] = {"zero ","one ","two ","three ","four ", + "five ", "six ","seven ","eight ","nine ","ten ", + "eleven ","twelve ","thirteen ","fourteen ","fifteen ", + "sixteen ","seventeen ","eighteen ","nineteen ", + "twenty ","thirty ","fourty ", "fifty ","sixty ", + "seventy ","eighty ","ninety ", + "hundred ","thousand "}; + *output = 0; + if (value < 0) value = -value; + int tho = value / 1000; + int aaa = 0; + if (tho){ + aaa += sprintf(&output[aaa], words[ tho ] ); + aaa += sprintf(&output[aaa], words[29] ); + value = value % 1000; + } + int hun = value / 100; + if (hun) { + aaa += sprintf(&output[aaa], words[ hun ] ); + aaa += sprintf(&output[aaa], words[28] ); + value = value % 100; + } + int ten = value / 10; + int unit = value % 10; + if ( ten ) + aaa += sprintf(&output[aaa], words[ ( ten > 1 ) ? ( ten + 18 ) : ( unit + 10 ) ] ); + if ( ten != 1 && ( unit || (!value && !hun && !tho) ) ) + sprintf(&output[aaa], words[ unit ] ); +} + +char* UTIL_SplitHudMessage(const char *src) +{ + static char message[512]; + short b = 0, d = 0, e = 0, c = -1; + + while ( src[ d ] && e < 480 ) { + if ( src[ d ] == ' ' ) { + c = e; + } + else if ( src[ d ] == '\n' ) { + c = -1; + b = 0; + } + message[ e++ ] = src[ d++ ]; + if ( ++b == 69 ) { + if ( c == -1 ) { + message[ e++ ] = '\n'; + b = 0; + } + else { + message[ c ] = '\n'; + b = e - c - 1; + c = -1; + } + } + } + message[ e ] = 0; + return message; +} + +unsigned short FixedUnsigned16( float value, float scale ) +{ + int output = value * scale; + + if ( output < 0 ) + output = 0; + else if ( output > 0xFFFF ) + output = 0xFFFF; + + return (unsigned short)output; +} + +short FixedSigned16( float value, float scale ) +{ + int output = value * scale; + + if ( output > 32767 ) + output = 32767; + else if ( output < -32768 ) + output = -32768; + + return (short)output; +} + +void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, char *pMessage) +{ + if ( pEntity ) + MESSAGE_BEGIN( MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, NULL, pEntity ); + else + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + + WRITE_BYTE(29); + WRITE_BYTE(textparms.channel & 0xFF); + WRITE_SHORT(FixedSigned16(textparms.x, (1<<13) )); + WRITE_SHORT(FixedSigned16(textparms.y, (1<<13) )); + WRITE_BYTE(textparms.effect); + WRITE_BYTE(textparms.r1); + WRITE_BYTE(textparms.g1); + WRITE_BYTE(textparms.b1); + WRITE_BYTE(0); + WRITE_BYTE(255); + WRITE_BYTE(255); + WRITE_BYTE(250); + WRITE_BYTE(0); + WRITE_SHORT(FixedUnsigned16(textparms.fadeinTime, (1<<8) )); + WRITE_SHORT(FixedUnsigned16(textparms.fadeoutTime, (1<<8) )); + WRITE_SHORT(FixedUnsigned16(textparms.holdTime, (1<<8) )); + if (textparms.effect==2) + WRITE_SHORT(FixedUnsigned16(textparms.fxTime, (1<<8) ) ); + WRITE_STRING(pMessage); + MESSAGE_END(); +} + +/* warning - buffer of msg must be longer than 190 chars! + (here in AMX it is always longer) */ +void UTIL_ClientPrint( edict_t *pEntity, int msg_dest, char *msg ) +{ + char c = msg[190]; + msg[190] = 0; // truncate without checking with strlen() + if ( pEntity ) + MESSAGE_BEGIN( MSG_ONE, gmsgTextMsg, NULL, pEntity ); + else + MESSAGE_BEGIN( MSG_BROADCAST , gmsgTextMsg); + WRITE_BYTE( msg_dest ); + WRITE_STRING( msg ); + MESSAGE_END(); + msg[190] = c; +} + +void UTIL_FakeClientCommand(edict_t *pEdict, const char *cmd, const char *arg1, const char *arg2) { + if (!cmd) return; + //strncpy(g_fakecmd.argv[0], cmd, 127 ); + //g_fakecmd.argv[0][ 127 ] = 0; + g_fakecmd.argv[0] = cmd; + if (arg2){ + g_fakecmd.argc = 3; + g_fakecmd.argv[1] = arg1; + g_fakecmd.argv[2] = arg2; + snprintf( g_fakecmd.args ,255 , "%s %s",arg1,arg2 ); + g_fakecmd.args[255] = 0; + //strncpy(g_fakecmd.argv[1], arg1 , 127 ); + //g_fakecmd.argv[1][ 127 ] = 0; + //strncpy(g_fakecmd.argv[2], arg2 , 127 ); + //g_fakecmd.argv[2][ 127 ] = 0; + //snprintf(g_fakecmd.args, 255 , "%s %s",arg1,arg2); + //g_fakecmd.args[255] = 0; + } + else if (arg1){ + g_fakecmd.argc = 2; + g_fakecmd.argv[1] = arg1; + snprintf( g_fakecmd.args ,255 , "%s" , arg1 ); + g_fakecmd.args[255] = 0; + //strncpy(g_fakecmd.argv[1], arg1, 127 ); + //g_fakecmd.argv[1][ 127 ] = 0; + //*g_fakecmd.argv[2] = 0; + //snprintf(g_fakecmd.args, 255 ,"%s",arg1); + //g_fakecmd.args[255] = 0; + } + else + g_fakecmd.argc = 1; + g_fakecmd.fake = true; + MDLL_ClientCommand(pEdict); + g_fakecmd.fake = false; +} \ No newline at end of file diff --git a/amxmodx/vault.cpp b/amxmodx/vault.cpp new file mode 100755 index 00000000..54bc2a08 --- /dev/null +++ b/amxmodx/vault.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002-2003 Aleksander Naszko + * + * This file is part of AMX Mod. + * + * AMX Mod 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. + * + * AMX Mod 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 AMX Mod; 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 "CVault.h" +#include "amxmod.h" + +Vault g_vault; + +static cell AMX_NATIVE_CALL set_vaultdata(AMX *amx,cell *params) +{ + int iLen; + + g_vault.put( get_amxstring(amx,params[1],0,iLen) , get_amxstring(amx,params[2],1,iLen) ); + g_vault.saveVault(); + + return 1; +} + +static cell AMX_NATIVE_CALL get_vaultdata(AMX *amx,cell *params) +{ + int iLen; + + const char* key = get_amxstring(amx,params[1],0,iLen); + + if ( params[3] ) + return set_amxstring( amx , params[2] , g_vault.get( key ) , params[3] ); + + return g_vault.get_number( key ); +} + +static cell AMX_NATIVE_CALL remove_vaultdata(AMX *amx,cell *params) +{ + int iLen; + + g_vault.remove( get_amxstring(amx,params[1],0,iLen) ); + g_vault.saveVault(); + + return 1; +} + +static cell AMX_NATIVE_CALL vaultdata_exists(AMX *amx,cell *params) +{ + int iLen; + + return g_vault.exists( get_amxstring(amx,params[1],0,iLen) ) ? 1 : 0; +} + +AMX_NATIVE_INFO vault_Natives[] = { + { "set_vaultdata", set_vaultdata }, + { "get_vaultdata", get_vaultdata }, + { "remove_vaultdata", remove_vaultdata }, + { "delete_vaultdata", remove_vaultdata }, + { "vaultdata_exists", vaultdata_exists }, + { 0, 0 } +}; \ No newline at end of file diff --git a/configs/amx.cfg b/configs/amx.cfg new file mode 100755 index 00000000..a52ab3b1 --- /dev/null +++ b/configs/amx.cfg @@ -0,0 +1,70 @@ +// AMX Configuration File +echo Executing AMX Configuration File + +// Default access for all non admin players (see users.ini for access details) +amx_default_access "" + +// Name of setinfo which should store a password on a client +// (Example: setinfo _pw "password") +amx_password_field "_pw" + +// Mode of logging to a server +// 0 - disable logging, players won't be checked (and access won't be set) +// 1 - normal mode which obey flags set in accounts +// 2 - kick all players not on list +amx_mode 1 + +// Show admins activity +// 0 - disabled +// 1 - show without admin name +// 2 - show with name +amx_show_activity 2 + +// Frequency in seconds and text of scrolling message +amx_scrollmsg "Welcome to %hostname% -- This server is using AMX" 600 + +// Center typed colored messages (last parameter is a color in RRRGGGBBB format) +amx_imessage "Welcome to %hostname%" "000255100" +amx_imessage "This server is using AMX\nVisit http://amxmod.net" "000100255" + +// Frequency in seconds of colored messages +amx_freq_imessage 180 + +// Set in seconds how fast players can chat (chat-flood protection) +amx_flood_time 0.75 + +// Amount of reserved slots (for more details see comments in a plugin source) +amx_reservation 2 + +// Displaying of time remaining +// a - display white text on bottom +// b - use voice +// c - don't add "remaining" (only in voice) +// d - don't add "hours/minutes/seconds" (only in voice) +// e - show/speak if current time is less than this set in parameter +amx_time_display "ab 1200" "ab 600" "ab 300" "ab 180" "ab 60" "bcde 11" + +// Announce "say thetime" and "say timeleft" with voice +amx_time_voice 1 + +// Minimum delay in seconds between two voting sessions +amx_vote_delay 10 + +// How long voting session goes on +amx_vote_time 10 + +// Display who votes for what option +amx_vote_answers 1 + +// Some ratios for voting success +amx_votekick_ratio 0.40 +amx_voteban_ratio 0.40 +amx_votemap_ratio 0.40 +amx_vote_ratio 0.02 + +// Max. time to which map can be extended +amx_extendmap_max 90 + +// Step for each extending +amx_extendmap_step 15 + diff --git a/configs/clcmds.ini b/configs/clcmds.ini new file mode 100755 index 00000000..8ef27c75 --- /dev/null +++ b/configs/clcmds.ini @@ -0,0 +1,18 @@ +; Client commands configuration file +; File location: $moddir/addons/amx/clcmds.ini +; To use with Players Menu plugin + +; NOTE: By default in all settings the access level is set to "u". +; However you can change that, to limit the access to some settings. + +; Client Commands Menu: +; < description > < command > < flags > < access level > +; "a" - execute from server console +; "b" - execute from admin console +; "c" - execute on selected player +; "d" - back to menu when executed + +"Kick player" "amx_kick #%userid%" "b" "u" +"Slay player" "amx_slay #%userid%" "bd" "u" +"Slap with 1 dmg." "amx_slap #%userid% 1" "b" "u" +"Ban on 5 minutes" "amx_banip 5 #%userid%" "b" "u" \ No newline at end of file diff --git a/configs/cmds.ini b/configs/cmds.ini new file mode 100755 index 00000000..39f9deb1 --- /dev/null +++ b/configs/cmds.ini @@ -0,0 +1,17 @@ +; Menu configuration file +; File location: $moddir/addons/amx/cmds.ini +; To use with Commands Menu plugin + +; NOTE: By default in all settings the access level is set to "u". +; However you can change that, to limit the access to some settings. + +; Commands Menu: +; < description > < command > < flags > < access level > +; "a" - execute from server console +; "b" - execute from admin console +; "c" - execute on all clients +; "d" - back to menu when executed + +"Pause" "amx_pause" "ad" "u" +" " "-" "" "u" +"Restart Round" "sv_restartround 1" "a" "u" diff --git a/configs/configs.ini b/configs/configs.ini new file mode 100755 index 00000000..83959498 --- /dev/null +++ b/configs/configs.ini @@ -0,0 +1,22 @@ +; Menu configuration file +; File location: $moddir/addons/amx/configs.ini +; To use with Commands Menu plugin + +; NOTE: By default in all settings the access level is set to "u". +; However you can change that, to limit the access to some settings. + +; Commands Menu: +; < description > < command > < flags > < access level > +; "a" - execute from server console +; "b" - execute from admin console +; "c" - execute on all clients +; "d" - back to menu when executed + +"PUBLIC Settings" "servercfgfile server.cfg;exec server.cfg" "a" "u" +"Clanbase" "exec clanbase.cfg;servercfgfile \'\'" "a" "u" +"Clanbase Charges Only" "exec clanbase_co.cfg;servercfgfile \'\'" "a" "u" +"Official CAL Match" "exec cal.cfg;servercfgfile \'\'" "a" "u" +"ProvingGrounds Server Config" "exec leagues/pg.cfg;servercfgfile \'\'" "a" "u" +"OGL CS Server Config" "exec ogl.cfg;servercfgfile \'\'" "a" "u" +"OGL CS FF Server Config" "exec ogl_ff.cfg;servercfgfile \'\'" "a" "u" +"OGL CS Advanced Server Config" "exec ogl_adv.cfg;servercfgfile \'\'" "a" "u" diff --git a/configs/conmotd.txt b/configs/conmotd.txt new file mode 100755 index 00000000..7f2b61bd --- /dev/null +++ b/configs/conmotd.txt @@ -0,0 +1 @@ +For newest AMX Mod and many plugins visit http://amxmod.net diff --git a/configs/core.ini b/configs/core.ini new file mode 100755 index 00000000..88d32b97 --- /dev/null +++ b/configs/core.ini @@ -0,0 +1,7 @@ +; Configuration file for AMX +amx_logdir addons/amx/logs +amx_modules addons/amx/modules.ini +amx_plugins addons/amx/plugins/plugins.ini +amx_vault addons/amx/vault.ini +csstats_score addons/amx/csstats.amx +csstats addons/amx/csstats.dat \ No newline at end of file diff --git a/configs/cvars.ini b/configs/cvars.ini new file mode 100755 index 00000000..102a09df --- /dev/null +++ b/configs/cvars.ini @@ -0,0 +1,23 @@ +; Menu configuration file +; File location: $moddir/addons/amx/cvars.ini +; To use with Commands Menu plugin + +; Cvars Menu: +; < cvar > < values > ... < access level > + +"mp_timelimit" "0" "30" "45" "u" +"mp_friendlyfire" "0" "1" "u" +"mp_autoteambalance" "0" "1" "2" "u" +"sv_password" "" roxor "clanwar" "u" +"mp_limitteams" "0" "1" "2" "u" +"mp_freezetime" 0 "6" "u" +"mp_buytime" "1" "0.5" "u" +"mp_startmoney" "800" "1800" "3600" "u" +"mp_c4timer" "35" "45" "15" "u" +"mp_forcechasecam" "0" "1" "2" "u" +"pausable" 0 1 "u" +"sv_minrate" "2000" "3000" "u" +"sv_maxrate" "7000" "6500" "u" +"allow_spectators" "0" "1" "u" +"sv_voiceenable" "0" "1" "u" +"mp_logmessages" "0" "1" "u" \ No newline at end of file diff --git a/configs/maps.ini b/configs/maps.ini new file mode 100755 index 00000000..9bae8959 --- /dev/null +++ b/configs/maps.ini @@ -0,0 +1,30 @@ +; Maps configuration file +; File location: $moddir/addons/amx/maps.ini +; To use with Maps Menu plugin + + +as_oilrig "OilRig - Assassination" +as_tundra "Tundra - Assassination" +de_aztec "Aztec - Bomb/Defuse" +de_cbble "Cobble - Bomb/Defuse" +de_chateau "Chateau - Bomb/Defuse" +de_dust "Dust - Bomb/Defuse" +de_dust2 "Dust II - Bomb/Defuse" +de_inferno "Inferno - Bomb/Defuse" +de_nuke "Nuke - Bomb/Defuse" +de_prodigy "Prodigy - Bomb/Defuse" +de_storm "Storm - Bomb/Defuse" +de_survivor "Survivor - Bomb/Defuse" +de_train "Trainyard - Bomb/Defuse" +de_torn "Torn - Bomb/Defuse" +de_vegas "Vegas - Bomb/Defuse" +de_vertigo "Vertigo - Bomb/Defuse" +cs_747 "747 Hijack - Hostage Rescue" +cs_assault "Assault - Hostage Rescue" +cs_backalley "Alleyway - Hostage Rescue" +cs_estate "Zaphod's Estate - Hostage Rescue" +cs_havana "Havana - Hostage Rescue" +cs_italy "Italy - Hostage Rescue" +cs_militia "Militia - Hostage Rescue" +cs_office "The Office Complex - Hostage Rescue" +cs_siege "Canyon Siege - Hostage Rescue" \ No newline at end of file diff --git a/configs/modules.ini b/configs/modules.ini new file mode 100755 index 00000000..549f6dea --- /dev/null +++ b/configs/modules.ini @@ -0,0 +1,14 @@ +; AMX Modules +; You can specify both linux & win32 modules here + +; CS Stats +addons/amx/dlls/csstats_mm.dll +addons/amx/dlls/csstats_mm_i386.so + +; More functions for modifications in HL +addons/amx/dlls/fun_mm.dll +addons/amx/dlls/fun_mm_i386.so + +; MySQL access +;addons/amx/dlls/mysql.dll +;addons/amx/dlls/mysql_i386.so diff --git a/configs/mysql.cfg b/configs/mysql.cfg new file mode 100755 index 00000000..f3267376 --- /dev/null +++ b/configs/mysql.cfg @@ -0,0 +1,10 @@ +// MySQL access configuration file +// File location: $moddir/addons/amx + +// *NOTE* Linux users may encounter problems if they specify "localhost" instead of "127.0.0.1" +// We recommend using your server IP address instead of its name + +amx_mysql_host "127.0.0.1" +amx_mysql_user "root" +amx_mysql_pass "" +amx_mysql_db "amx" diff --git a/configs/plugins.ini b/configs/plugins.ini new file mode 100755 index 00000000..27f550b9 --- /dev/null +++ b/configs/plugins.ini @@ -0,0 +1,26 @@ +; AMX Mod plugins + +admin.amx ; admin base (required for any admin-related) +;admin_mysql.amx ; admin base - MySQL version (comment admin.amx) +admincmd.amx ; basic admin console commands +adminhelp.amx ; help command for admin console commands +adminslots.amx ; slot reservation +menufront.amx ; front-end for admin menus +cmdmenu.amx ; command menu (speech, settings) +plmenu.amx ; players menu (kick, ban, client cmds.) +restmenu.amx ; restrict weapons menu +mapsmenu.amx ; maps menu (vote, changelevel) +antiflood.amx ; prevent clients from chat-flooding the server +adminchat.amx ; console chat commands +adminvote.amx ; vote commands +nextmap.amx ; displays next map in mapcycle +timeleft.amx ; displays time left on map +mapchooser.amx ; allows to vote for next map +scrollmsg.amx ; displays a scrolling message +imessage.amx ; displays information messages +pausecfg.amx ; allows to pause and unpause some plugins +;telemenu.amx ; teleport menu (Fun Module required!) +stats.amx ; stats on death or round end (CSStats Module required!) +stats_logging.amx ; weapons stats logging (CSStats Module required!) +miscstats.amx ; bunch of events announcement for Counter-Strike +statscfg.amx ; allows to manage stats plugins via menu and commands diff --git a/configs/speech.ini b/configs/speech.ini new file mode 100755 index 00000000..7ad8a6fb --- /dev/null +++ b/configs/speech.ini @@ -0,0 +1,35 @@ +; Menu configuration file +; File location: $moddir/addons/amx/speech.ini +; To use with Commands Menu plugin + +; NOTE: By default in all settings the access level is set to "u". +; However you can change that, to limit the access to some settings. + +; Commands Menu: +; < description > < command > < flags > < access level > +; "a" - execute from server console +; "b" - execute from admin console +; "c" - execute on all clients +; "d" - back to menu when executed + +"Hello!" "spk \'vox/hello\'" "cd" "u" +"Don't think so" "spk \'barney/dontguess\'" "cd" "u" +"Don't ask me" "spk \'barney/dontaskme\'" "cd" "u" +"Hey! Stop that!" "spk \'barney/donthurtem\'" "cd" "u" +"Yup" "spk \'barney/yup\'" "cd" "u" +"Nope" "spk \'barney/nope\'" "cd" "u" +"Maybe" "spk \'barney/maybe\'" "cd" "u" +"Seeya" "spk \'barney/seeya\'" "cd" "u" +"Man that sounded bad" "spk \'barney/soundsbad\'" "cd" "u" +"Hello and die" "spk \'vox/hello and die\'" "cd" "u" +"Move!" "spk \'hgrunt/move! _comma yessir!\'" "cd" "u" +"You will definitely pay!" "spk \'hgrunt/c2a2_hg_chat5a\'" "cd" "u" +"Laughter" "spk \'hgrunt/c2a3_hg_laugh\'" "cd" "u" +"Silence!" "spk \'hgrunt/silence!\'" "cd" "u" +"You talk too much" "spk \'barney/youtalkmuch\'" "cd" "u" +"You thinkin?" "spk \'barney/thinking\'" "cd" "u" +"Open fire Gordon!" "spk \'barney/openfire\'" "cd" "u" +"Couldnt make a bigger mess" "spk \'barney/bigmess\'" "cd" "u" +"I have a Bad feeling" "spk \'barney/badfeeling\'" "cd" "u" +"Yes sir!" "spk \'hgrunt/yessir!\'" "cd" "u" +"No sir" "spk \'barney/nosir\'" "cd" "u" \ No newline at end of file diff --git a/configs/users.ini b/configs/users.ini new file mode 100755 index 00000000..00eccaec --- /dev/null +++ b/configs/users.ini @@ -0,0 +1,42 @@ +; Line starting with ; is a comment + +; Access flags: +; a - immunity (can't be kicked/baned/slayed/slaped and affected by other commmands) +; b - reservation (can join on reserved slots) +; c - amx_kick command +; d - amx_ban and amx_unban commands +; e - amx_slay and amx_slap commands +; f - amx_map command +; g - amx_cvar command (not all cvars will be available) +; h - amx_cfg command +; i - amx_chat and other chat commands +; j - amx_vote and other vote commands +; k - access to sv_password cvar (by amx_cvar command) +; l - access to amx_rcon command and rcon_password cvar (by amx_cvar command) +; m - custom level A (for additional plugins) +; n - custom level B +; o - custom level C +; p - custom level D +; q - custom level E +; r - custom level F +; s - custom level G +; t - custom level H +; u - menu access +; z - user + +; Account flags: +; a - disconnect player on invalid password +; b - clan tag +; c - this is steamid +; d - this is ip +; e - password is not checked (only name/ip/steamid needed) + +; Format of admin account: +; + +; Examples of admin accounts: +; "123.43.43.53" "" "abcdefghijklmnopqrstu" "de" +; "STEAM_0:0:14332" "my_password" "abcdefgnstu" "c" +; "My Name" "my_password" "abcdefghijklmnopqrstu" "a" + +"loopback" "" "abcdefghijklmnopqrstu" "de" diff --git a/plugins/admin.sma b/plugins/admin.sma new file mode 100755 index 00000000..7504a326 --- /dev/null +++ b/plugins/admin.sma @@ -0,0 +1,202 @@ +/* AMX Mod script. +* +* (c) 2003, OLO +* This file is provided as is (no warranties). +*/ + +#include +#include + +#define MAX_ADMINS 64 + +new g_aPassword[MAX_ADMINS][32] +new g_aName[MAX_ADMINS][32] +new g_aFlags[MAX_ADMINS] +new g_aAccess[MAX_ADMINS] +new g_aNum +new g_logFile[16] +#if !defined NO_STEAM +new g_cmdLoopback[16] +#endif + +public plugin_init() +{ + register_plugin("Admin Base","0.9","default") + register_cvar("amx_mode","2.0") + register_cvar("amx_password_field","_pw") + register_cvar("amx_default_access","") + + get_logfile(g_logFile,15) + +#if !defined NO_STEAM + format( g_cmdLoopback, 15, "amxauth%c%c%c%c" , + random_num('A','Z') , random_num('A','Z') ,random_num('A','Z'),random_num('A','Z') ) + + register_clcmd( g_cmdLoopback, "ackSignal" ) +#endif + + remove_user_flags(0,read_flags("z")) // Remove 'user' flag from server rights + + new filename[64] + get_basedir( filename , 31 ) + server_cmd("exec %s/amx.cfg" , filename ) // Execute main configuration file + format( filename, 63 , "%s/users.ini" , filename ) + loadSettings( filename ) // Load admins accounts + +} + +loadSettings(szFilename[]) +{ + if (!file_exists(szFilename)) return 0 + + new szText[256], szFlags[32], szAccess[32] + new a, pos = 0 + + while ( g_aNum < MAX_ADMINS && read_file(szFilename,pos++,szText,255,a) ) + { + if ( szText[0] == ';' ) continue + + if ( parse(szText, g_aName[ g_aNum ] ,31, + g_aPassword[ g_aNum ], 31, szAccess,31,szFlags,31 ) < 2 ) continue + + g_aAccess[ g_aNum ] = read_flags( szAccess ) + g_aFlags[ g_aNum ] = read_flags( szFlags ) + ++g_aNum + } + + return 1 +} + +getAccess(id,name[],authid[],ip[], password[]) +{ + new index = -1 + new result = 0 + for(new i = 0; i < g_aNum; ++i) { + if (g_aFlags[i] & FLAG_AUTHID) { + if (equal(authid,g_aName[i])) { + index = i + break + } + } + else if (g_aFlags[i] & FLAG_IP) { + new c = strlen( g_aName[i] ) + if ( g_aName[i][ c - 1 ] == '.' ) { /* check if this is not a xxx.xxx. format */ + if ( equal( g_aName[i] , ip , c ) ) { + index = i + break + } + } /* in other case an IP must just match */ + else if ( equal(ip,g_aName[i]) ){ + index = i + break + } + } + else { + if (g_aFlags[i] & FLAG_TAG) { + if (contain(name,g_aName[i])!=-1){ + index = i + break + } + } + else if (equal(name,g_aName[i])) { + index = i + break + } + } + } + if (index != -1) { + if (g_aFlags[index] & FLAG_NOPASS){ + result |= 8 + new sflags[32] + get_flags(g_aAccess[index],sflags,31) + set_user_flags(id,g_aAccess[index]) + log_to_file(g_logFile,"Login: ^"%s<%d><%s><>^" become an admin (account ^"%s^") (access ^"%s^") (address ^"%s^")", + name,get_user_userid(id),authid,g_aName[index] ,sflags,ip) + } + else if (equal(password,g_aPassword[index])) { + result |= 12 + set_user_flags(id,g_aAccess[index]) + new sflags[32] + get_flags(g_aAccess[index],sflags,31) + log_to_file(g_logFile,"Login: ^"%s<%d><%s><>^" become an admin (account ^"%s^") (access ^"%s^") (address ^"%s^")", + name,get_user_userid(id),authid,g_aName[index] ,sflags,ip) + } + else { + result |= 1 + if (g_aFlags[index] & FLAG_KICK){ + result |= 2 + log_to_file(g_logFile,"Login: ^"%s<%d><%s><>^" kicked due to invalid password (account ^"%s^") (address ^"%s^")", + name,get_user_userid(id),authid,g_aName[index],ip) + } + } + } + else if (get_cvar_float("amx_mode")==2.0) { + result |= 2 + } + else { + new defaccess[32] + get_cvar_string("amx_default_access",defaccess,31) + new idefaccess = read_flags(defaccess) + if (idefaccess){ + result |= 8 + set_user_flags(id,idefaccess) + } + } + + return result +} + +accessUser( id, name[] = "" ) +{ + remove_user_flags(id) + new userip[32],userauthid[32],password[32],passfield[32],username[32] + get_user_ip(id,userip,31,1) + get_user_authid(id,userauthid,31) + if ( name[0] ) copy( username , 31, name) + else get_user_name(id,username,31 ) + get_cvar_string("amx_password_field",passfield,31) + get_user_info(id,passfield,password,31) + new result = getAccess(id,username,userauthid,userip,password) + if (result & 1) client_cmd(id,"echo ^"* Invalid Password!^"") + if (result & 2) { + +#if !defined NO_STEAM + client_cmd(id,"echo ^"* You have no entry to the server...^";%s",g_cmdLoopback) + +#else + client_cmd(id,"echo ^"* You have no entry to the server...^";disconnect") +#endif + + return PLUGIN_HANDLED + } + if (result & 4) client_cmd(id,"echo ^"* Password accepted^"") + if (result & 8) client_cmd(id,"echo ^"* Privileges set^"") + return PLUGIN_CONTINUE +} + +public client_infochanged(id) +{ + if ( !is_user_connected(id) || !get_cvar_num("amx_mode") ) + return PLUGIN_CONTINUE + + new newname[32], oldname[32] + get_user_name(id,oldname,31) + get_user_info(id,"name",newname,31) + + if ( !equal(newname,oldname) ) + accessUser( id, newname ) + + return PLUGIN_CONTINUE +} + +#if !defined NO_STEAM + +public ackSignal(id) + server_cmd("kick #%d", get_user_userid(id) ) + +public client_authorized(id) +#else +public client_connect(id) +#endif + + return get_cvar_num( "amx_mode" ) ? accessUser( id ) : PLUGIN_CONTINUE diff --git a/plugins/admin_mysql.sma b/plugins/admin_mysql.sma new file mode 100755 index 00000000..75b47ec4 --- /dev/null +++ b/plugins/admin_mysql.sma @@ -0,0 +1,234 @@ +/* AMX Mod script. +* +* (c) 2003, dJeyL +* This file is provided as is (no warranties). +* +* This AMX plugin requires MySQL module. +* +* For this to work, you might create your MySQL admins table with this SQL query : + + CREATE TABLE admins ( + auth varchar(32) NOT NULL default '', + password varchar(32) NOT NULL default '', + access varchar(32) NOT NULL default '', + flags varchar(32) NOT NULL default '' + ) TYPE=MyISAM; + +* IMPORTANT: +* o Check $moddir/addons/amx/mysql.cfg for MySQL access configuration +* o Disable admin.amx plugin if you use admin_mysql.amx +* +*/ + +#include +#include +#include + +#define MAX_ADMINS 64 + +new g_aPassword[MAX_ADMINS][32] +new g_aName[MAX_ADMINS][32] +new g_aFlags[MAX_ADMINS] +new g_aAccess[MAX_ADMINS] +new g_aNum +new g_logFile[16] +#if !defined NO_STEAM +new g_cmdLoopback[16] +#endif + +public plugin_init() +{ + register_plugin("Admin Base for MySQL","0.9","default") + + register_cvar("amx_mode","2.0") + register_cvar("amx_password_field","_pw") + register_cvar("amx_default_access","") + register_srvcmd("amx_sqladmins","adminSql") + register_cvar("amx_mysql_host","127.0.0.1") + register_cvar("amx_mysql_user","root") + register_cvar("amx_mysql_pass","") + register_cvar("amx_mysql_db","amx") + +#if !defined NO_STEAM + format( g_cmdLoopback, 15, "amxauth%c%c%c%c" , + random_num('A','Z') , random_num('A','Z') ,random_num('A','Z'),random_num('A','Z') ) + register_clcmd( g_cmdLoopback, "ackSignal" ) +#endif + + + remove_user_flags(0,read_flags("z")) // remove 'user' flag from server rights + + get_logfile(g_logFile,15) + + new filename[32] + get_basedir( filename , 31 ) + server_cmd("exec %s/amx.cfg" , filename) + server_cmd("exec %s/mysql.cfg;amx_sqladmins" , filename) +} + +public adminSql(){ + new host[64],user[32],pass[32],db[32],error[128] + get_cvar_string("amx_mysql_host",host,63) + get_cvar_string("amx_mysql_user",user,31) + get_cvar_string("amx_mysql_pass",pass,31) + get_cvar_string("amx_mysql_db",db,31) + + new mysql = mysql_connect(host,user,pass,db,error,127) + if(mysql < 1){ + server_print("MySQL error: can't connect: '%s'",error) + return PLUGIN_HANDLED + } + + if(mysql_query(mysql,"SELECT auth,password,access,flags FROM admins") < 1) { + mysql_error(mysql,error,127) + server_print("MySQL error: can't load admins: '%s'",error) + return PLUGIN_HANDLED + } + + new szFlags[32], szAccess[32] + g_aNum = 0 /* reset admins settings */ + while( mysql_nextrow(mysql) > 0 ) + { + mysql_getfield(mysql, 1, g_aName[ g_aNum ] ,31) + mysql_getfield(mysql, 2, g_aPassword[ g_aNum ] ,31) + mysql_getfield(mysql, 3, szAccess,31) + mysql_getfield(mysql, 4, szFlags,31) + g_aAccess[ g_aNum ] = read_flags( szAccess ) + g_aFlags[ g_aNum ] = read_flags( szFlags ) + ++g_aNum + } + + server_print("Loaded %d admin%s from database",g_aNum, (g_aNum == 1) ? "" : "s" ) + mysql_close(mysql) + return PLUGIN_HANDLED +} + +getAccess(id,name[],authid[],ip[], password[]){ + new index = -1 + new result = 0 + for(new i = 0; i < g_aNum; ++i) { + if (g_aFlags[i] & FLAG_AUTHID) { + if (equal(authid,g_aName[i])) { + index = i + break + } + } + else if (g_aFlags[i] & FLAG_IP) { + new c = strlen( g_aName[i] ) + if ( g_aName[i][ c - 1 ] == '.' ) { /* check if this is not a xxx.xxx. format */ + if ( equal( g_aName[i] , ip , c ) ) { + index = i + break + } + } /* in other case an IP must just match */ + else if ( equal(ip,g_aName[i]) ){ + index = i + break + } + } + else { + if (g_aFlags[i] & FLAG_TAG) { + if (contain(name,g_aName[i])!=-1){ + index = i + break + } + } + else if (equal(name,g_aName[i])) { + index = i + break + } + } + } + if (index != -1) { + if (g_aFlags[index] & FLAG_NOPASS){ + result |= 8 + new sflags[32] + get_flags(g_aAccess[index],sflags,31) + set_user_flags(id,g_aAccess[index]) + log_to_file(g_logFile,"Login: ^"%s<%d><%s><>^" become an admin (account ^"%s^") (access ^"%s^") (address ^"%s^")", + name,get_user_userid(id),authid,g_aName[index] ,sflags,ip) + } + else if (equal(password,g_aPassword[index])) { + result |= 12 + set_user_flags(id,g_aAccess[index]) + new sflags[32] + get_flags(g_aAccess[index],sflags,31) + log_to_file(g_logFile,"Login: ^"%s<%d><%s><>^" become an admin (account ^"%s^") (access ^"%s^") (address ^"%s^")", + name,get_user_userid(id),authid,g_aName[index] ,sflags,ip) + } + else { + result |= 1 + if (g_aFlags[index] & FLAG_KICK){ + result |= 2 + log_to_file(g_logFile,"Login: ^"%s<%d><%s><>^" kicked due to invalid password (account ^"%s^") (address ^"%s^")", + name,get_user_userid(id),authid,g_aName[index],ip) + } + } + } + else if (get_cvar_float("amx_mode")==2.0) { + result |= 2 + } + else { + new defaccess[32] + get_cvar_string("amx_default_access",defaccess,31) + new idefaccess = read_flags(defaccess) + if (idefaccess){ + result |= 8 + set_user_flags(id,idefaccess) + } + } + + return result +} + +accessUser( id, name[]="" ) +{ + remove_user_flags(id) + new userip[32],userauthid[32],password[32],passfield[32],username[32] + get_user_ip(id,userip,31,1) + get_user_authid(id,userauthid,31) + if ( name[0] ) copy( username , 31, name) + else get_user_name(id,username,31 ) + get_cvar_string("amx_password_field",passfield,31) + get_user_info(id,passfield,password,31) + new result = getAccess(id,username,userauthid,userip,password) + if (result & 1) client_cmd(id,"echo ^"* Invalid Password!^"") + if (result & 2) { +#if !defined NO_STEAM + client_cmd(id,"echo ^"* You have no entry to the server...^";%s",g_cmdLoopback) +#else + client_cmd(id,"echo ^"* You have no entry to the server...^";disconnect") +#endif + return PLUGIN_HANDLED + } + if (result & 4) client_cmd(id,"echo ^"* Password accepted^"") + if (result & 8) client_cmd(id,"echo ^"* Privileges set^"") + return PLUGIN_CONTINUE +} + +public client_infochanged(id) +{ + if ( !is_user_connected(id) || !get_cvar_num("amx_mode") ) + return PLUGIN_CONTINUE + + new newname[32], oldname[32] + get_user_name(id,oldname,31) + get_user_info(id,"name",newname,31) + + if ( !equal(newname,oldname) ) + accessUser( id , newname ) + + return PLUGIN_CONTINUE +} + +#if !defined NO_STEAM + +public ackSignal(id) + server_cmd("kick #%d", get_user_userid(id) ) + +public client_authorized(id) +#else +public client_connect(id) +#endif + + return get_cvar_num( "amx_mode" ) ? accessUser( id ) : PLUGIN_CONTINUE diff --git a/plugins/adminchat.sma b/plugins/adminchat.sma new file mode 100755 index 00000000..b674df70 --- /dev/null +++ b/plugins/adminchat.sma @@ -0,0 +1,204 @@ +/* AMX Mod script. +* +* (c) 2003, OLO +* This file is provided as is (no warranties). +*/ + +#include +#include + +// Uncomment if you want to display +// names with hud messages +//#define SHOW_NAMES + +new g_logFile[16] +new g_msgChannel + +#define MAX_CLR 7 +new g_Colors[MAX_CLR][] = {"white","red","green","blue","yellow","magenta","cyan"} +new g_Values[MAX_CLR][] = {{255,255,255},{255,0,0},{0,255,0},{0,0,255},{255,255,0},{255,0,255},{0,255,255}} +new Float:g_Pos[4][] = {{0.0,0.0},{0.05,0.55},{-1.0,0.2},{-1.0,0.7}} + +public plugin_init(){ + register_plugin("Admin Chat","0.9","default") + register_clcmd("say_team","cmdSayAdmin",0,"@ - displays message to admins") + register_clcmd("say","cmdSayChat",ADMIN_CHAT,"@[@|@|@][w|r|g|b|y|m|c] - displays hud message") + register_concmd("amx_say","cmdSay",ADMIN_CHAT," - sends message to all players") + register_concmd("amx_chat","cmdChat",ADMIN_CHAT," - sends message to admins") + register_concmd("amx_psay","cmdPsay",ADMIN_CHAT," - sends private message") + register_concmd("amx_tsay","cmdTsay",ADMIN_CHAT," - sends left side hud message to all players") + register_concmd("amx_csay","cmdTsay",ADMIN_CHAT," - sends center hud message to all players") + get_logfile(g_logFile,15) +} + +public cmdSayChat(id) { + if (!(get_user_flags(id)&ADMIN_CHAT)) return PLUGIN_CONTINUE + new said[6], i=0 + read_argv(1,said,5) + while (said[i]=='@') + i++ + if ( !i || i > 3 ) return PLUGIN_CONTINUE + new message[192], a = 0 + read_argv(1,message,191) + switch(said[i]){ + case 'r': a = 1 + case 'g': a = 2 + case 'b': a = 3 + case 'y': a = 4 + case 'm': a = 5 + case 'c': a = 6 + } + new name[32], authid[32], userid + get_user_authid(id,authid,31) + get_user_name(id,name,31) + userid = get_user_userid(id) + log_to_file(g_logFile,"Chat: ^"%s<%d><%s><>^" tsay ^"%s^"",name,userid,authid,message[i+1]) + log_message("^"%s<%d><%s><>^" triggered ^"amx_tsay^" (text ^"%s^") (color ^"%s^")", + name,userid,authid,message[ i+1 ],g_Colors[a]) + if (++g_msgChannel>6||g_msgChannel<3) + g_msgChannel = 3 + new Float:verpos = g_Pos[i][1] + float(g_msgChannel) / 35.0 + set_hudmessage(g_Values[a][0], g_Values[a][1], g_Values[a][2], + g_Pos[i][0], verpos , 0, 6.0, 6.0, 0.5, 0.15, g_msgChannel ) + +#if defined SHOW_NAMES + show_hudmessage(0,"%s : %s",name,message[i+1]) + client_print(0,print_notify,"%s : %s",name,message[i+1]) +#else + show_hudmessage(0,message[i+1]) + client_print(0,print_notify,message[i+1]) +#endif + + return PLUGIN_HANDLED +} + +public cmdSayAdmin(id) { + new said[2] + read_argv(1,said,1) + if (said[0]!='@') return PLUGIN_CONTINUE + new message[192], name[32],authid[32], userid + new players[32], inum + read_argv(1,message,191) + get_user_authid(id,authid,31) + get_user_name(id,name,31) + userid = get_user_userid(id) + log_to_file(g_logFile,"Chat: ^"%s<%d><%s><>^" chat ^"%s^"",name,userid,authid,message[1]) + log_message("^"%s<%d><%s><>^" triggered ^"amx_chat^" (text ^"%s^")",name,userid,authid,message[1]) + format(message,191,"(ADMINS) %s : %s",name,message[1]) + get_players(players,inum) + for(new i=0; i<%s><>^" chat ^"%s^"",name,userid,authid,message) + log_message("^"%s<%d><%s><>^" triggered ^"amx_chat^" (text ^"%s^")",name,userid,authid,message) + format(message,191,"(ADMINS) %s : %s",name,message) + console_print(id,message) + for(new i = 0; i < inum; ++i){ + if ( get_user_flags(players[i]) & ADMIN_CHAT ) + client_print(players[i],print_chat,message) + } + return PLUGIN_HANDLED +} + +public cmdSay(id,level,cid){ + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new message[192], name[32],authid[32], userid + read_args(message,191) + remove_quotes(message) + get_user_authid(id,authid,31) + get_user_name(id,name,31) + userid = get_user_userid(id) + client_print(0,print_chat,"(ALL) %s : %s",name,message) + console_print(id,"(ALL) %s : %s",name,message) + log_to_file(g_logFile,"Chat: ^"%s<%d><%s><>^" say ^"%s^"", name,userid,authid,message) + log_message("^"%s<%d><%s><>^" triggered ^"amx_say^" (text ^"%s^")",name,userid,authid,message) + return PLUGIN_HANDLED +} + +public cmdPsay(id,level,cid){ + if (!cmd_access(id,level,cid,3)) + return PLUGIN_HANDLED + new name[32] + read_argv(1,name,31) + new priv = cmd_target(id,name,0) + if (!priv) return PLUGIN_HANDLED + new length = strlen(name)+1 + new message[192], name2[32],authid[32],authid2[32], userid, userid2 + get_user_authid(id,authid,31) + get_user_name(id,name2,31) + userid = get_user_userid(id) + read_args(message,191) + if (message[0]=='"' && message[length]=='"'){// HLSW fix + message[0]=message[length]=' ' + length+=2 + } + remove_quotes(message[length]) + get_user_name(priv,name,31) + if (id&&id!=priv) client_print(id,print_chat,"(%s) %s : %s",name,name2,message[length]) + client_print(priv,print_chat,"(%s) %s : %s",name,name2,message[length]) + console_print(id,"(%s) %s : %s",name,name2,message[length]) + get_user_authid(priv,authid2,31) + userid2 = get_user_userid(priv) + log_to_file(g_logFile,"Chat: ^"%s<%d><%s><>^" psay ^"%s<%d><%s><>^" ^"%s^"", + name2,userid,authid,name,userid2,authid2,message[length]) + log_message("^"%s<%d><%s><>^" triggered ^"amx_psay^" against ^"%s<%d><%s><>^" (text ^"%s^")", + name2,userid,authid,name,userid2,authid2,message[length]) + return PLUGIN_HANDLED +} + +public cmdTsay(id,level,cid){ + if (!cmd_access(id,level,cid,3)) + return PLUGIN_HANDLED + new cmd[16],color[12], message[192], name[32], authid[32], userid = 0 + read_argv(0,cmd,15) + new bool:tsay = (tolower(cmd[4]) == 't') + read_args(message,191) + remove_quotes(message) + parse(message,color,11) + new found = 0,a = 0 + for(new i=0;i6||g_msgChannel<3) + g_msgChannel = 3 + new Float:verpos = ( tsay ? 0.55 : 0.1 ) + float(g_msgChannel) / 35.0 + get_user_authid(id,authid,31) + get_user_name(id,name,31) + userid = get_user_userid(id) + set_hudmessage(g_Values[a][0], g_Values[a][1], g_Values[a][2], tsay ? 0.05 : -1.0, verpos, 0, 6.0, 6.0, 0.5, 0.15, g_msgChannel) + +#if defined SHOW_NAMES + show_hudmessage(0,"%s : %s",name,message[length]) + client_print(0,print_notify,"%s : %s",name,message[length]) + console_print(id,"%s : %s",name,message[length]) +#else + show_hudmessage(0,message[length]) + client_print(0,print_notify,message[length]) + console_print(id,message[length]) +#endif + + log_to_file(g_logFile,"Chat: ^"%s<%d><%s><>^" %s ^"%s^"",name,userid,authid,cmd[4],message[length]) + log_message("^"%s<%d><%s><>^" triggered ^"%s^" (text ^"%s^") (color ^"%s^")", + name,userid,authid,cmd,message[length],g_Colors[a]) + return PLUGIN_HANDLED +} \ No newline at end of file diff --git a/plugins/admincmd.sma b/plugins/admincmd.sma new file mode 100755 index 00000000..5c7504f7 --- /dev/null +++ b/plugins/admincmd.sma @@ -0,0 +1,459 @@ +/* AMX Mod script. +* +* (c) 2003, OLO +* This file is provided as is (no warranties). +*/ + +#include +#include + +#define MAXRCONCVARS 16 +new g_cvarRcon[ MAXRCONCVARS ][32] +new g_cvarRconNum +new g_logFile[16] +new g_pauseCon +new Float:g_pausAble +new bool:g_Paused +new g_addCvar[] = "amx_cvar add %s" + +public plugin_init(){ + register_plugin("Admin Commands","0.9","default") + register_concmd("amx_kick","cmdKick",ADMIN_KICK," [reason]") + register_concmd("amx_ban","cmdAddBan",ADMIN_BAN," [reason]") + register_concmd("amx_banid","cmdBan",ADMIN_BAN," [reason]") + register_concmd("amx_banip","cmdBan",ADMIN_BAN," [reason]") + register_concmd("amx_unban","cmdUnban",ADMIN_BAN,"") + register_concmd("amx_slay","cmdSlay",ADMIN_SLAY,"") + register_concmd("amx_slap","cmdSlap",ADMIN_SLAY," [power]") + register_concmd("amx_leave","cmdLeave",ADMIN_KICK," [tag] [tag] [tag]") + register_concmd("amx_pause","cmdPause",ADMIN_CVAR,"- pause or unpause the game") + register_concmd("amx_who","cmdWho",0,"- displays who is on server") + register_concmd("amx_cvar","cmdCvar",ADMIN_CVAR," [value]") + register_clcmd("amx_map","cmdMap",ADMIN_MAP,"") + register_clcmd("pauseAck","cmdLBack") + register_clcmd("amx_cfg","cmdCfg",ADMIN_CFG,"") + register_clcmd("amx_rcon","cmdRcon",ADMIN_RCON,"") + register_cvar("amx_show_activity","2") + register_cvar("amx_vote_delay","") + register_cvar("amx_vote_time","") + register_cvar("amx_vote_answers","") + register_cvar("amx_vote_ratio","") + register_cvar("amx_show_activity","") + get_logfile(g_logFile,15) +} + +public plugin_cfg(){ + // Cvars which can be changed only with rcon access + server_cmd( g_addCvar ,"rcon_password") + server_cmd( g_addCvar ,"amx_show_activity") + server_cmd( g_addCvar ,"amx_mode") + server_cmd( g_addCvar ,"amx_password_field") + server_cmd( g_addCvar ,"amx_default_access") + server_cmd( g_addCvar ,"amx_reserved_slots") + server_cmd( g_addCvar ,"amx_reservation") + server_cmd( g_addCvar ,"amx_conmotd_file") +} + +public cmdKick(id,level,cid){ + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new arg[32] + read_argv(1,arg,31) + new player = cmd_target(id,arg,1) + if (!player) return PLUGIN_HANDLED + new authid[32],authid2[32],name2[32],name[32],userid2, arg2[32] + get_user_authid(id,authid,31) + get_user_authid(player,authid2,31) + get_user_name(player,name2,31) + get_user_name(id,name,31) + userid2 = get_user_userid(player) + read_argv(2,arg2,31) + log_to_file(g_logFile,"Kick: ^"%s<%d><%s><>^" kick ^"%s<%d><%s><>^" (reason ^"%s^")", + name,get_user_userid(id),authid, name2,userid2,authid2,arg2 ) + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"ADMIN %s: kick %s",name,name2) + case 1: client_print(0,print_chat,"ADMIN: kick %s",name2) + } + server_cmd("kick #%d",userid2) + console_print(id,"Client ^"%s^" kicked",name2) + return PLUGIN_HANDLED +} + +public cmdUnban(id,level,cid){ + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new arg[32],authid[32],name[32] + read_argv(1,arg,31) + if (contain(arg,".")!=-1) { + server_cmd("removeip ^"%s^";writeip",arg) + console_print(id,"Ip ^"%s^" removed from ban list", arg ) + } + else { + server_cmd("removeid ^"%s^";writeid",arg) + console_print(id,"Authid ^"%s^" removed from ban list", arg ) + } + get_user_name(id,name,31) + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"ADMIN %s: unban %s",name,arg) + case 1: client_print(0,print_chat,"ADMIN: unban %s",arg) + } + get_user_authid(id,authid,31) + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" unban ^"%s^"", + name,get_user_userid(id),authid, arg ) + return PLUGIN_HANDLED +} + +public cmdAddBan(id,level,cid){ + if (!cmd_access(id,level,cid,3)) + return PLUGIN_HANDLED + new arg[32],authid[32],name[32],minutes[32],reason[32] + read_argv(1,minutes,31) + read_argv(2,arg,31) + read_argv(3,reason,31) + if (contain(arg,".")!=-1) { + server_cmd("addip ^"%s^" ^"%s^";wait;writeip",minutes,arg) + console_print(id,"Ip ^"%s^" added to ban list", arg ) + } + else { + server_cmd("banid ^"%s^" ^"%s^" kick;wait;writeid",minutes,arg) + console_print(id,"Authid ^"%s^" added to ban list", arg ) + } + get_user_name(id,name,31) + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"ADMIN %s: ban %s",name,arg) + case 1: client_print(0,print_chat,"ADMIN: ban %s",arg) + } + get_user_authid(id,authid,31) + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" ban ^"%s^" (minutes ^"%s^") (reason ^"%s^")", + name,get_user_userid(id),authid, arg, minutes, reason ) + return PLUGIN_HANDLED +} + +public cmdBan(id,level,cid){ + if (!cmd_access(id,level,cid,3)) + return PLUGIN_HANDLED + new arg[32], cmd[32] + read_argv(0,cmd,31) + read_argv(2,arg,31) + new player = cmd_target(id,arg,9) + if (!player) return PLUGIN_HANDLED + new minutes[32],authid[32],name2[32],authid2[32],name[32], arg3[32] + new userid2 = get_user_userid(player) + read_argv(1,minutes,31) + get_user_authid(player,authid2,31) + get_user_authid(id,authid,31) + get_user_name(player,name2,31) + get_user_name(id,name,31) + read_argv(3,arg3,31) + log_to_file(g_logFile,"Ban: ^"%s<%d><%s><>^" ban and kick ^"%s<%d><%s><>^" (minutes ^"%s^") (reason ^"%s^")", + name,get_user_userid(id),authid, name2,userid2,authid2,minutes,arg3 ) + + if ( equal(cmd[7],"ip") || (!equal(cmd[7],"id") && get_cvar_num("sv_lan")) ){ + new address[32] + get_user_ip(player,address,31,1) + server_cmd("addip ^"%s^" ^"%s^";wait;writeip",minutes,address) + } + else + server_cmd("banid ^"%s^" ^"%s^" kick;wait;writeid",minutes,authid2) + + new activity = get_cvar_num("amx_show_activity") + if (activity) { + new temp[64], temp2[64] + if (activity == 1) + temp = "ADMIN:" + else + format(temp,63,"ADMIN %s:",name) + if (strtonum(minutes)) + format(temp2,63,"for %s min.",minutes) + else + temp2 = "permanently" + client_print(0,print_chat,"%s ban %s %s",temp,name2,temp2) + } + + console_print(id,"Client ^"%s^" banned",name2) + return PLUGIN_HANDLED +} + +public cmdSlay(id,level,cid){ + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new arg[32] + read_argv(1,arg,31) + new player = cmd_target(id,arg,5) + if (!player) return PLUGIN_HANDLED + user_kill(player) + new authid[32],name2[32],authid2[32],name[32] + get_user_authid(id,authid,31) + get_user_name(id,name,31) + get_user_authid(player,authid2,31) + get_user_name(player,name2,31) + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" slay ^"%s<%d><%s><>^"", + name,get_user_userid(id),authid, name2,get_user_userid(player),authid2 ) + + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"ADMIN %s: slay %s",name,name2) + case 1: client_print(0,print_chat,"ADMIN: slay %s",name2) + } + + console_print(id,"Client ^"%s^" slayed",name2) + return PLUGIN_HANDLED +} + +public cmdSlap(id,level,cid){ + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new arg[32] + read_argv(1,arg,31) + new player = cmd_target(id,arg,5) + if (!player) return PLUGIN_HANDLED + new spower[32],authid[32],name2[32],authid2[32],name[32] + read_argv(2,spower,31) + new damage = strtonum(spower) + user_slap(player,damage) + get_user_authid(id,authid,31) + get_user_name(id,name,31) + get_user_authid(player,authid2,31) + get_user_name(player,name2,31) + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" slap with %d damage ^"%s<%d><%s><>^"", + name,get_user_userid(id),authid, damage,name2,get_user_userid(player),authid2 ) + + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"ADMIN %s: slap %s with %d damage",name,name2,damage) + case 1: client_print(0,print_chat,"ADMIN: slap %s with %d damage",name2,damage) + } + + console_print(id,"Client ^"%s^" slaped with %d damage",name2,damage) + return PLUGIN_HANDLED +} + +public chMap(map[]) + server_cmd("changelevel %s",map) + +public cmdMap(id,level,cid){ + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new arg[32] + new arglen = read_argv(1,arg,31) + if ( !is_map_valid(arg) ){ + console_print(id,"Map with that name not found or map is invalid") + return PLUGIN_HANDLED + } + new authid[32],name[32] + get_user_authid(id,authid,31) + get_user_name(id,name,31) + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"ADMIN %s: changelevel %s",name,arg) + case 1: client_print(0,print_chat,"ADMIN: changelevel %s",arg) + } + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" changelevel ^"%s^"", name,get_user_userid(id),authid, arg) + set_task(1.0,"chMap",0,arg,arglen+1) + return PLUGIN_HANDLED +} + +onlyRcon( name[] ) { + for(new a = 0; a < g_cvarRconNum; ++a) + if ( equal( g_cvarRcon[a] , name) ) + return 1 + return 0 +} + +public cmdCvar(id,level,cid){ + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new arg[32], arg2[64] + read_argv(1,arg,31) + read_argv(2,arg2,63) + if ( equal(arg,"add") && (get_user_flags(id) & ADMIN_RCON) ) { + if ( cvar_exists(arg2) ){ + if ( g_cvarRconNum < MAXRCONCVARS ) + copy( g_cvarRcon[ g_cvarRconNum++ ] , 31, arg2 ) + else + console_print(id,"Can't add more cvars for rcon access!") + } + return PLUGIN_HANDLED + } + if (!cvar_exists(arg)){ + console_print(id,"Unknown cvar: %s",arg) + return PLUGIN_HANDLED + } + if ( onlyRcon(arg) && !(get_user_flags(id) & ADMIN_RCON)){ + console_print(id,"You have no access to that cvar") + return PLUGIN_HANDLED + } + else if (equal(arg,"sv_password") && !(get_user_flags(id) & ADMIN_PASSWORD)){ + console_print(id,"You have no access to that cvar") + return PLUGIN_HANDLED + } + if (read_argc() < 3){ + get_cvar_string(arg,arg2,63) + console_print(id,"Cvar ^"%s^" is ^"%s^"",arg,arg2) + return PLUGIN_HANDLED + } + new authid[32],name[32] + get_user_authid(id,authid,31) + get_user_name(id,name,31) + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" set cvar (name ^"%s^") (value ^"%s^")", + name,get_user_userid(id),authid, arg,arg2) + set_cvar_string(arg,arg2) + + new activity = get_cvar_num("amx_show_activity") + if (activity) { + new temp[64] + if (activity == 1) + temp = "ADMIN:" + else + format(temp,63,"ADMIN %s:",name) + client_print(0,print_chat,"%s set cvar %s to ^"%s^"",temp,arg,equal(arg,"rcon_password") ? "*** PROTECTED ***" : arg2) + } + + console_print(id,"Cvar ^"%s^" changed to ^"%s^"",arg,arg2) + return PLUGIN_HANDLED +} + +public cmdCfg(id,level,cid){ + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new arg[128] + read_argv(1,arg,127) + if (!file_exists(arg)){ + console_print(id,"File ^"%s^" not found",arg) + return PLUGIN_HANDLED + } + new authid[32],name[32] + get_user_authid(id,authid,31) + get_user_name(id,name,31) + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" execute cfg (file ^"%s^")", + name,get_user_userid(id),authid, arg) + console_print(id,"Executing file ^"%s^"",arg) + server_cmd("exec %s",arg) + + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"ADMIN %s: execute config %s",name,arg) + case 1: client_print(0,print_chat,"ADMIN: execute config %s",arg) + } + + return PLUGIN_HANDLED +} + +public cmdLBack(){ + set_cvar_float("pausable",g_pausAble) + console_print(g_pauseCon,"Server %s", g_Paused ? "unpaused" : "paused") + g_Paused = !g_Paused + return PLUGIN_HANDLED +} + +public cmdPause(id,level,cid){ + if (!cmd_access(id,level,cid,1)) + return PLUGIN_HANDLED + new authid[32],name[32],slayer = id + get_user_authid(id,authid,31) + get_user_name(id,name,31) + g_pausAble = get_cvar_float("pausable") + if (!slayer) slayer = find_player("h") + if (!slayer){ + console_print(id,"Server was unable to pause the game. Real players on server are needed") + return PLUGIN_HANDLED + } + set_cvar_float("pausable",1.0) + client_cmd(slayer,"pause;pauseAck") + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" %s server", + name,get_user_userid(id),authid, g_Paused ? "unpause" : "pause" ) + console_print(id,"Server proceed %s", g_Paused ? "unpausing" : "pausing") + + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"ADMIN %s: %s server",name,g_Paused ? "unpause" : "pause") + case 1: client_print(0,print_chat,"ADMIN: %s server",g_Paused ? "unpause" : "pause") + } + + g_pauseCon = id + return PLUGIN_HANDLED +} + +public cmdRcon(id,level,cid){ + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new arg[128],authid[32],name[32] + read_args(arg,127) + get_user_authid(id,authid,31) + get_user_name(id,name,31) + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" server console (cmdline ^"%s^")", + name,get_user_userid(id),authid, arg) + console_print(id,"Commmand line ^"%s^" sent to server console",arg) + server_cmd(arg) + return PLUGIN_HANDLED +} + +public cmdWho(id,level,cid){ + new players[32], inum, authid[32],name[32], flags, sflags[32] + get_players(players,inum) + console_print(id,"^nClients on server:^n # %-16.15s %-12s %-8s %-4.3s %-4.3s %s", + "nick","authid","userid","imm","res","access") + for(new a = 0; a < inum; ++a) { + get_user_authid(players[a],authid,31) + get_user_name(players[a],name,31) + flags = get_user_flags(players[a]) + get_flags(flags,sflags,31) + console_print(id,"%2d %-16.15s %-12s %-8d %-4.3s %-4.3s %s", players[a],name,authid, + get_user_userid(players[a]),(flags&ADMIN_IMMUNITY)?"yes":"no", + (flags&ADMIN_RESERVATION)?"yes":"no",sflags) + } + console_print(id,"Total %d",inum) + get_user_authid(id,authid,31) + get_user_name(id,name,31) + log_to_file(g_logFile,"Cmd: ^"%s<%d><%s><>^" ask for players list",name,get_user_userid(id),authid) + return PLUGIN_HANDLED +} + +hasTag(name[],tags[4][32],tagsNum){ + for(new a=0;a<%s><>^" leave some group (tag1 ^"%s^") (tag2 ^"%s^") (tag3 ^"%s^") (tag4 ^"%s^")", + name,get_user_userid(id),authid,ltags[0],ltags[1],ltags[2],ltags[3] ) + + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"ADMIN %s: leave %s %s %s %s",name,ltags[0],ltags[1],ltags[2],ltags[3]) + case 1: client_print(0,print_chat,"ADMIN: leave %s %s %s %s",ltags[0],ltags[1],ltags[2],ltags[3]) + } + + return PLUGIN_HANDLED +} diff --git a/plugins/adminhelp.sma b/plugins/adminhelp.sma new file mode 100755 index 00000000..a5fc679d --- /dev/null +++ b/plugins/adminhelp.sma @@ -0,0 +1,66 @@ +/* AMX Mod script. +* +* (c) 2003, tcquest78 +* This file is provided as is (no warranties). +* +* Provides help for admin commands with amx_help command +*/ + +#include + +#define HELPAMOUNT 10 // Number of commands per page + +new g_typeHelp[] = "Type 'amx_help' in the console to see available commands" +new g_timeInfo1[] = "Time Left: %d:%02d min. Next Map: %s" +new g_timeInfo2[] = "No Time Limit. Next Map: %s" + +public plugin_init() { + register_plugin("Admin Help","0.9","tcquest78") + register_concmd("amx_help","cmdHelp",0,"- displays this help") + setHelp(0) +} + +public client_putinserver(id) + setHelp(id) + +public cmdHelp(id,level,cid){ + new arg1[8],flags = get_user_flags(id) + new start = read_argv(1,arg1,7) ? strtonum(arg1) : 1 + if (--start < 0) start = 0 + new clcmdsnum = get_concmdsnum(flags,id) + if (start >= clcmdsnum) start = clcmdsnum - 1 + console_print(id,"^n----- AMX Help: Commands -----") + new info[128], cmd[32], eflags + new end = start + HELPAMOUNT + if (end > clcmdsnum) end = clcmdsnum + for (new i = start; i < end; i++){ + get_concmd(i,cmd,31,eflags,info,127,flags,id) + console_print(id,"%3d: %s %s",i+1,cmd,info) + } + console_print(id,"----- Entries %d - %d of %d -----",start+1,end,clcmdsnum) + if (end < clcmdsnum) + console_print(id,"----- Use 'amx_help %d' for more -----",end+1) + else + console_print(id,"----- Use 'amx_help 1' for begin -----") + return PLUGIN_HANDLED +} + +public dispInfo(id){ + if (id) client_print(id,print_chat, g_typeHelp ) + else server_print( g_typeHelp ) + new nextmap[32] + get_cvar_string("amx_nextmap",nextmap,31) + if (get_cvar_float("mp_timelimit")){ + new timeleft = get_timeleft() + if (timeleft > 0){ + if (id) client_print(id,print_chat, g_timeInfo1 , timeleft / 60, timeleft % 60,nextmap) + else server_print( g_timeInfo1 , timeleft / 60, timeleft % 60,nextmap) + } + } + else if (id) client_print(id,print_chat, g_timeInfo2 ,nextmap) + else server_print( g_timeInfo2 ,nextmap) +} + +setHelp(id) + set_task(15.0,"dispInfo",id) + diff --git a/plugins/adminslots.sma b/plugins/adminslots.sma new file mode 100755 index 00000000..6eb2f24c --- /dev/null +++ b/plugins/adminslots.sma @@ -0,0 +1,88 @@ +/* AMX Mod script. + * + * (c) 2003, OLO + * This file is provided as is (no warranties). + * + * Kick a player without reservation who tries + * to enter to one of the reservered slots set + * by amx_reservation cvar. + * + * Cvar: + * amx_reservation - sets amount of reserved slots. + */ + +#include +#include + +// Comment if you don't want to hide not used reserved slots +#define HIDE_RESERVED_SLOTS + +new g_cmdLoopback[16] + +public plugin_init() +{ + register_plugin("Slots Reservation","0.9.7","default") + register_cvar("amx_reservation","1") + + format( g_cmdLoopback, 15, "amxres%c%c%c%c" , + random_num('A','Z') , random_num('A','Z') ,random_num('A','Z'),random_num('A','Z') ) + + register_clcmd( g_cmdLoopback, "ackSignal" ) +} + +#if !defined NO_STEAM + +public ackSignal(id) + server_cmd("kick #%d", get_user_userid(id) ) + +public client_authorized(id) +#else +public client_connect(id) +#endif +{ + new maxplayers = get_maxplayers( ) + new players = get_playersnum( 1 ) + new limit = maxplayers - get_cvar_num( "amx_reservation" ) + + if ( (get_user_flags(id) & ADMIN_RESERVATION) || (players <= limit) ) + { +#if defined HIDE_RESERVED_SLOTS + setVisibleSlots( players , maxplayers, limit ) +#endif + return PLUGIN_CONTINUE + } + +#if !defined NO_STEAM + client_cmd(id,"echo ^"Dropped due to slot reservation^";%s" , g_cmdLoopback) +#else + if ( is_user_bot(id) ) + server_cmd("kick #%d", get_user_userid(id) ) + else + client_cmd(id,"echo ^"Dropped due to slot reservation^";disconnect") +#endif + + return PLUGIN_HANDLED +} + +#if defined HIDE_RESERVED_SLOTS +public client_disconnect(id) +{ + new maxplayers = get_maxplayers( ) + setVisibleSlots( get_playersnum(1) - 1 , maxplayers , + maxplayers - get_cvar_num( "amx_reservation" ) ) + return PLUGIN_CONTINUE +} + +setVisibleSlots( players , maxplayers , limit ) +{ + new num = players + 1 + + if ( players == maxplayers ) + num = maxplayers + else if ( players < limit ) + num = limit + + set_cvar_num( "sv_visiblemaxplayers" , num ) +} +#endif + diff --git a/plugins/adminvote.sma b/plugins/adminvote.sma new file mode 100755 index 00000000..9c48a8eb --- /dev/null +++ b/plugins/adminvote.sma @@ -0,0 +1,370 @@ +/* AMX Mod script. +* +* (c) 2003, OLO +* This file is provided as is (no warranties). +* +* I. Vote for changing the level: +* amx_votemap < map > [ map ] [ map ] [ map ] +* +* Examples: +* amx_votemap "de_dust" +* amx_votemap "de_dust" "de_dust2" "cs_italy" +* +* II. Vote for kicking the player: +* amx_votekick +* +* Examples: +* amx_votekick "Player" +* +* III. Vote for banning and kicking the player for 30 minutes: +* amx_voteban +* +* Examples: +* amx_voteban "Player" +* +* IV. Custom voting: +* amx_vote < question > < g_Answer1 > < g_Answer2 > +* +* Examples: +* amx_vote "sv_restart" "5" "0" +* amx_vote "mp_timelimit" "20" "45" +* amx_vote "are you hungry?" "yes" "no" +* +*/ + +#include +#include + +new g_Answer[128] +new g_optionName[4][32] +new g_voteCount[4] +new g_validMaps +new g_yesNoVote +new g_logFile[16] +new g_cstrikeRunning +new g_voteCaller +new g_Execute[256] +new g_execLen +new g_alredyVoting[]= "There is already one voting..." +new g_notAllowed[] = "Voting not allowed at this time" +new g_votingStarted[] = "Voting has started..." +new g_playerTag[] = "PLAYER" +new g_adminTag[] = "ADMIN" + +new bool:g_execResult +new Float:g_voteRatio + +public plugin_init() { + register_plugin("Admin Votes","0.9","default") + register_menucmd(register_menuid("Change map to ") ,(1<<0)|(1<<1),"voteCount") + register_menucmd(register_menuid("Choose map: ") ,(1<<0)|(1<<1)|(1<<2)|(1<<3),"voteCount") + register_menucmd(register_menuid("Kick ") ,(1<<0)|(1<<1),"voteCount") + register_menucmd(register_menuid("Ban ") ,(1<<0)|(1<<1),"voteCount") + register_menucmd(register_menuid("Vote: ") ,(1<<0)|(1<<1),"voteCount") + register_menucmd(register_menuid("The result: ") ,(1<<0)|(1<<1),"actionResult") + register_concmd("amx_votemap","cmdVoteMap",ADMIN_VOTE," [map] [map] [map]") + register_concmd("amx_votekick","cmdVoteKickBan",ADMIN_VOTE,"") + register_concmd("amx_voteban","cmdVoteKickBan",ADMIN_VOTE,"") + register_concmd("amx_vote","cmdVote",ADMIN_VOTE," ") + register_concmd("amx_cancelvote","cmdCancelVote",ADMIN_VOTE,"- cancels last vote") + register_cvar("amx_votekick_ratio","0.40") + register_cvar("amx_voteban_ratio","0.40") + register_cvar("amx_votemap_ratio","0.40") + register_cvar("amx_vote_ratio","0.02") + register_cvar("amx_vote_time","10") + register_cvar("amx_vote_answers","1") + register_cvar("amx_vote_delay","60") + register_cvar("amx_last_voting","0") + set_cvar_float("amx_last_voting",0.0) + register_cvar("amx_show_activity","2") + g_cstrikeRunning = is_running("cstrike") + get_logfile(g_logFile,15) +} + +public cmdCancelVote(id,level,cid){ + if (!cmd_access(id,level,cid,0)) + return PLUGIN_HANDLED + if ( task_exists( 99889988 , 1 ) ) { + new authid[32],name[32] + get_user_authid(id,authid,31) + get_user_name(id,name,31) + log_to_file(g_logFile,"Vote: ^"%s<%d><%s><>^" cancel vote session", name,get_user_userid(id),authid) + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"%s %s: cancel vote", (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag, name) + case 1: client_print(0,print_chat,"%s: cancel vote", (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag) + } + console_print(id, "Voting canceled" ) + client_print(0,print_chat,"Voting canceled") + remove_task( 99889988 , 1 ) + set_cvar_float( "amx_last_voting" , get_gametime() ) + } + else + console_print(id, "There is no voting to cancel or the vote session can't be canceled with that command" ) + return PLUGIN_HANDLED +} + +public delayedExec(cmd[]) + server_cmd(cmd) + +new g_resultRef[] = "Result refused" +new g_resultAcpt[] = "Result accepted" +new g_votingFailed[] = "Voting failed" +new g_votingSuccess[] = "Voting successful" + +public autoRefuse(){ + log_to_file(g_logFile,"Vote: %s" , g_resultRef) + client_print(0,print_chat,g_resultRef ) +} + +public actionResult(id,key) { + remove_task( 4545454 ) + switch(key){ + case 0: { + set_task(2.0,"delayedExec",0,g_Execute,g_execLen) + log_to_file(g_logFile,"Vote: %s",g_resultAcpt) + client_print(0,print_chat,g_resultAcpt ) + } + case 1: autoRefuse() + } + return PLUGIN_HANDLED +} + +public checkVotes() { + new best = 0 + if ( !g_yesNoVote ) { + for(new a = 0; a < 4; ++a) + if (g_voteCount[a] > g_voteCount[best]) + best = a + } + new votesNum = g_voteCount[0] + g_voteCount[1] + g_voteCount[2] + g_voteCount[3] + new iRatio = votesNum ? floatround( g_voteRatio * float( votesNum ) ,floatround_ceil) : 1 + new iResult = g_voteCount[best] + if ( iResult < iRatio ){ + if (g_yesNoVote) + client_print(0,print_chat,"%s (yes ^"%d^") (no ^"%d^") (needed ^"%d^")",g_votingFailed, g_voteCount[0], g_voteCount[1] , iRatio ) + else + client_print(0,print_chat,"%s (got ^"%d^") (needed ^"%d^")",g_votingFailed,iResult , iRatio ) + log_to_file(g_logFile,"Vote: %s (got ^"%d^") (needed ^"%d^")",g_votingFailed,iResult , iRatio ) + return PLUGIN_CONTINUE + } + g_execLen = format(g_Execute,255,g_Answer,g_optionName[best]) + 1 + if (g_execResult){ + g_execResult = false + if ( is_user_connected(g_voteCaller) ) { + new menuBody[512] + new len = format(menuBody,511,g_cstrikeRunning ? "\yThe result: \w%s^n^n" : "The result: %s^n^n", g_Execute ) + len += copy( menuBody[len] ,511 - len, g_cstrikeRunning ? "\yDo you want to continue?^n\w" : "Do you want to continue?^n" ) + copy( menuBody[len] ,511 - len, "^n1. Yes^n2. No") + show_menu( g_voteCaller ,0x03 ,menuBody, 10 ) + set_task(10.0,"autoRefuse",4545454) + } + else + set_task(2.0,"delayedExec",0,g_Execute,g_execLen) + } + client_print(0,print_chat,"%s (got ^"%d^") (needed ^"%d^"). The result: %s", g_votingSuccess, iResult , iRatio , g_Execute ) + log_to_file(g_logFile,"Vote: %s (got ^"%d^") (needed ^"%d^") (result ^"%s^")", g_votingSuccess, iResult , iRatio , g_Execute ) + return PLUGIN_CONTINUE +} + +public voteCount(id,key){ + if ( get_cvar_num("amx_vote_answers") ) { + new name[32] + get_user_name(id,name,31) + if (g_yesNoVote) + client_print(0,print_chat,"%s voted %s",name,key ? "against" : "for" ) + else + client_print(0,print_chat,"%s voted for option #%d",name,key+1) + } + ++g_voteCount[key] + return PLUGIN_HANDLED +} + +public cmdVoteMap(id,level,cid) { + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new Float:voting = get_cvar_float("amx_last_voting") + if (voting > get_gametime()){ + console_print(id, g_alredyVoting ) + return PLUGIN_HANDLED + } + if (voting && voting + get_cvar_float("amx_vote_delay") > get_gametime()) { + console_print(id, g_notAllowed ) + return PLUGIN_HANDLED + } + new argc = read_argc() + if (argc > 5) argc = 5 + g_validMaps = 0 + g_optionName[0][0] = g_optionName[1][0] = g_optionName[2][0] = g_optionName[3][0] = 0 + for(new i = 1; i < argc; ++i){ + read_argv(i,g_optionName[g_validMaps],31) + if (is_map_valid(g_optionName[g_validMaps])) + g_validMaps++; + } + if (g_validMaps == 0) { + console_print(id,"Given %s not valid",(argc==2)?"map is":"maps are") + return PLUGIN_HANDLED + } + new menu_msg[256] + new keys = 0 + if (g_validMaps > 1){ + keys = (1<<9) + copy(menu_msg,255,g_cstrikeRunning ? "\yChoose map: \w^n^n" : "Choose map: ^n^n") + new temp[128] + for(new a = 0; a < g_validMaps; ++a){ + format(temp,127,"%d. %s^n",a+1,g_optionName[a]) + add(menu_msg,255,temp) + keys |= (1<<%s><>^" vote map (map ^"%s^")", + name,get_user_userid(id),authid,g_optionName[0]) + else + log_to_file(g_logFile,"Vote: ^"%s<%d><%s><>^" vote maps (map#1 ^"%s^") (map#2 ^"%s^") (map#3 ^"%s^") (map#4 ^"%s^")", + name,get_user_userid(id),authid,g_optionName[0],g_optionName[1],g_optionName[2],g_optionName[3]) + + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"%s %s: vote map(s)",name, + (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag) + case 1: client_print(0,print_chat,"%s: vote map(s)", + (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag) + } + + g_execResult = true + new Float:vote_time = get_cvar_float("amx_vote_time") + 2.0 + set_cvar_float("amx_last_voting", get_gametime() + vote_time ) + g_voteRatio = get_cvar_float("amx_votemap_ratio") + g_Answer = "changelevel %s" + show_menu(0,keys,menu_msg,floatround(vote_time)) + set_task(vote_time,"checkVotes" , 99889988 ) + g_voteCaller = id + console_print(id, g_votingStarted ) + g_voteCount = { 0,0, 0,0 } + return PLUGIN_HANDLED +} + +public cmdVote(id,level,cid) { + if (!cmd_access(id,level,cid,4)) + return PLUGIN_HANDLED + new Float:voting = get_cvar_float("amx_last_voting") + if (voting > get_gametime()){ + console_print(id, g_alredyVoting ) + return PLUGIN_HANDLED + } + if (voting && voting + get_cvar_float("amx_vote_delay") > get_gametime()) { + console_print(id, g_notAllowed ) + return PLUGIN_HANDLED + } + new quest[48] + read_argv(1,quest,47) + if ((contain(quest,"sv_password")!=-1)||(contain(quest,"rcon_password")!=-1)|| + (contain(quest,"kick")!=-1)||(contain(quest,"addip")!=-1)||(contain(quest,"ban")!=-1)){ + console_print(id,"Voting for that has been forbidden") + return PLUGIN_HANDLED + } + read_argv(2,g_optionName[0],31) + read_argv(3,g_optionName[1],31) + + new authid[32],name[32] + get_user_authid(id,authid,31) + get_user_name(id,name,31) + log_to_file(g_logFile,"Vote: ^"%s<%d><%s><>^" vote custom (question ^"%s^") (option#1 ^"%s^") (option#2 ^"%s^")", + name,get_user_userid(id),authid,quest,g_optionName[0],g_optionName[1]) + + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"%s %s: vote custom", + (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag,name ) + case 1: client_print(0,print_chat,"%s: vote custom", + (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag) + } + + new menu_msg[256] + new keys = (1<<0)|(1<<1) + format(menu_msg,255, g_cstrikeRunning ? "\yVote: %s\w^n^n1. %s^n2. %s" + : "Vote: %s^n^n1. %s^n2. %s",quest,g_optionName[0],g_optionName[1]) + g_execResult = false + new Float:vote_time = get_cvar_float("amx_vote_time") + 2.0 + set_cvar_float("amx_last_voting", get_gametime() + vote_time ) + g_voteRatio = get_cvar_float("amx_vote_ratio") + format(g_Answer,127,"%s - %%s",quest) + show_menu(0,keys,menu_msg,floatround(vote_time)) + set_task(vote_time,"checkVotes" , 99889988 ) + g_voteCaller = id + console_print(id, g_votingStarted ) + g_voteCount ={ 0,0,0,0} + g_yesNoVote = 0 + return PLUGIN_HANDLED +} + +public cmdVoteKickBan(id,level,cid) { + if (!cmd_access(id,level,cid,2)) + return PLUGIN_HANDLED + new Float:voting = get_cvar_float("amx_last_voting") + if (voting > get_gametime()){ + console_print(id, g_alredyVoting ) + return PLUGIN_HANDLED + } + if (voting && voting + get_cvar_float("amx_vote_delay") > get_gametime()) { + console_print(id, g_notAllowed ) + return PLUGIN_HANDLED + } + new cmd[32] + read_argv(0,cmd,31) + new voteban = equal(cmd,"amx_voteban") + new arg[32] + read_argv(1,arg,31) + new player = cmd_target(id,arg,1) + if (!player) return PLUGIN_HANDLED + if (voteban && is_user_bot(player)) { + new imname[32] + get_user_name(player,imname,31) + console_print(id,"That action can't be performed on bot ^"%s^"",imname) + return PLUGIN_HANDLED + } + + new keys = (1<<0)|(1<<1) + new menu_msg[256] + get_user_name(player,arg,31) + format(menu_msg,255,g_cstrikeRunning ? "\y%s %s?\w^n^n1. Yes^n2. No" + : "%s %s?^n^n1. Yes^n2. No", voteban ? "Ban" : "Kick", arg) + g_yesNoVote = 1 + if (voteban) + get_user_authid(player,g_optionName[0],31) + else + numtostr(get_user_userid(player),g_optionName[0],31) + new authid[32],name[32] + get_user_authid(id,authid,31) + get_user_name(id,name,31) + log_to_file(g_logFile,"Vote: ^"%s<%d><%s><>^" vote %s (target ^"%s^")", + name,get_user_userid(id),authid,voteban ? "ban" : "kick",arg) + + switch(get_cvar_num("amx_show_activity")) { + case 2: client_print(0,print_chat,"%s %s: vote %s for %s", + (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag,name,voteban ? "ban" : "kick",arg ) + case 1: client_print(0,print_chat,"%s: vote %s for %s", + (get_user_flags(id) & ADMIN_USER) ? g_playerTag : g_adminTag,voteban ? "ban" : "kick",arg) + } + + g_execResult = true + new Float:vote_time = get_cvar_float("amx_vote_time") + 2.0 + set_cvar_float("amx_last_voting", get_gametime() + vote_time ) + g_voteRatio = get_cvar_float(voteban ? "amx_voteban_ratio" : "amx_votekick_ratio") + g_Answer = voteban ? "banid 30.0 %s kick" : "kick #%s" + show_menu(0,keys,menu_msg,floatround(vote_time)) + set_task(vote_time,"checkVotes" , 99889988 ) + g_voteCaller = id + console_print(id, g_votingStarted ) + g_voteCount = {0,0,0,0} + return PLUGIN_HANDLED +} diff --git a/plugins/antiflood.sma b/plugins/antiflood.sma new file mode 100755 index 00000000..1c2066ea --- /dev/null +++ b/plugins/antiflood.sma @@ -0,0 +1,41 @@ +/* AMX Mod script. +* +* (c) 2003, OLO +* This file is provided as is (no warranties). +* +* Cvar: +* amx_flood_time