attempted merge at 1.77 back into trunk... Oh MY GOD

This commit is contained in:
David Anderson 2007-03-09 03:04:40 +00:00
parent 7adc49c541
commit 71065a65dd
90 changed files with 16915 additions and 1824 deletions

409
amxmodx/CFlagManager.cpp Normal file
View File

@ -0,0 +1,409 @@
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "sh_list.h"
#include "CString.h"
#include "amxmodx.h"
#include "CFlagManager.h"
void CFlagManager::SetFile(const char *Filename)
{
m_strConfigFile.assign(g_mod_name.c_str());
m_strConfigFile.append("/");
m_strConfigFile.append(get_localinfo("amxx_configsdir","addons/amxmodx/configs"));
m_strConfigFile.append("/");
m_strConfigFile.append(Filename);
CreateIfNotExist();
}
const int CFlagManager::LoadFile(const int force)
{
CheckIfDisabled();
// If we're disabled get the hell out. now.
if (m_iDisabled)
{
return 0;
}
// if we're not forcing this, and NeedToLoad says we dont have to
// then just stop
if (!force && !NeedToLoad())
{
return 0;
};
this->Clear();
// We need to load the file
FILE *File;
File=fopen(m_strConfigFile.c_str(),"r");
if (!File)
{
AMXXLOG_Log("[AMXX] FlagManager: Cannot open file \"%s\" (FILE pointer null!)",m_strConfigFile.c_str());
return -1;
};
// Trying to copy this almost exactly as other configs are read...
String Line;
char Command[256];
char Flags[256];
String TempLine;
while (!feof(File))
{
Line._fread(File);
char *nonconst=const_cast<char *>(Line.c_str());
// Strip out comments
while (*nonconst)
{
if (*nonconst==';') // End the line at comments
{
*nonconst='\0';
}
else
{
nonconst++;
}
};
Command[0]='\0';
Flags[0]='\0';
// Extract the command
TempLine.assign(Line.c_str());
nonconst=const_cast<char *>(TempLine.c_str());
char *start=NULL;
char *end=NULL;
// move up line until the first ", mark this down as the start
// then find the second " and mark it down as the end
while (*nonconst!='\0')
{
if (*nonconst=='"')
{
if (start==NULL)
{
start=nonconst+1;
}
else
{
end=nonconst;
goto done_with_command;
}
}
nonconst++;
}
done_with_command:
// invalid line?
if (start==NULL || end==NULL)
{
// TODO: maybe warn for an invalid non-commented line?
continue;
}
*end='\0';
strncpy(Command,start,sizeof(Command)-1);
// Now do the same thing for the flags
nonconst=++end;
start=NULL;
end=NULL;
// move up line until the first ", mark this down as the start
// then find the second " and mark it down as the end
while (*nonconst!='\0')
{
if (*nonconst=='"')
{
if (start==NULL)
{
start=nonconst+1;
}
else
{
end=nonconst;
goto done_with_flags;
}
}
nonconst++;
}
done_with_flags:
// invalid line?
if (start==NULL || end==NULL)
{
// TODO: maybe warn for an invalid non-commented line?
continue;
}
*end='\0';
strncpy(Flags,start,sizeof(Flags)-1);
if (!isalnum(*Command))
{
continue;
};
// Done sucking the command and flags out of the line
// now insert this command into the linked list
AddFromFile(const_cast<const char*>(&Command[0]),&Flags[0]);
nonconst=const_cast<char *>(Line.c_str());
*nonconst='\0';
};
fclose(File);
return 1;
}
/**
* This gets called from LoadFile
* Do NOT flag the entries as NeedToWrite
* No comment is passed from the file because
* this should never get written
*/
void CFlagManager::AddFromFile(const char *Command, const char *Flags)
{
CFlagEntry *Entry=new CFlagEntry;
Entry->SetName(Command);
Entry->SetFlags(Flags);
// Link it
m_FlagList.push_back(Entry);
};
void CFlagManager::LookupOrAdd(const char *Command, int &Flags, AMX *Plugin)
{
if (m_iDisabled) // if disabled in core.ini stop
{
return;
}
int TempFlags=Flags;
if (TempFlags==-1)
{
TempFlags=0;
}
List<CFlagEntry *>::iterator iter;
List<CFlagEntry *>::iterator end;
iter=m_FlagList.begin();
end=m_FlagList.end();
while (iter!=end)
{
if (strcmp((*iter)->GetName()->c_str(),Command)==0)
{
CFlagEntry *Entry=(*iter);
if (Entry->IsHidden()) // "!" flag, exclude this function
{
return;
}
// Found, byref the new flags
Flags=Entry->Flags();
// Move it to the back of the list for faster lookup for the rest
m_FlagList.erase(iter);
m_FlagList.push_back(Entry);
return;
}
iter++;
}
// was not found, add it
CFlagEntry *Entry=new CFlagEntry;
Entry->SetName(Command);
Entry->SetFlags(TempFlags);
if (Plugin)
{
CPluginMngr::CPlugin* a = g_plugins.findPluginFast(Plugin);
if (a)
{
Entry->SetComment(a->getName());
}
}
// This entry was added from a register_* native
// it needs to be written during map change
Entry->SetNeedWritten(1);
// Link it
m_FlagList.push_back(Entry);
}
void CFlagManager::WriteCommands(void)
{
List<CFlagEntry *>::iterator iter;
List<CFlagEntry *>::iterator end;
FILE *File;
int NeedToRead=0;
// First off check the modified time of this file
// if it matches the stored modified time, then update
// after we write so we do not re-read next map
struct stat TempStat;
stat(m_strConfigFile.c_str(),&TempStat);
if (TempStat.st_mtime != m_Stat.st_mtime)
{
NeedToRead=1;
};
File=fopen(m_strConfigFile.c_str(),"a");
iter=m_FlagList.begin();
end=m_FlagList.end();
while (iter!=end)
{
if ((*iter)->NeedWritten())
{
if ((*iter)->GetComment()->size())
{
fprintf(File,"\"%s\" \t\"%s\" ; %s\n",(*iter)->GetName()->c_str(),(*iter)->GetFlags()->c_str(),(*iter)->GetComment()->c_str());
}
else
{
fprintf(File,"\"%s\" \t\"%s\"\n",(*iter)->GetName()->c_str(),(*iter)->GetFlags()->c_str());
}
(*iter)->SetNeedWritten(0);
}
++iter;
};
fclose(File);
// If NeedToRead was 0, then update the timestamp
// that was saved so we do not re-read this file
// next map
if (!NeedToRead)
{
stat(m_strConfigFile.c_str(),&TempStat);
m_Stat.st_mtime=TempStat.st_mtime;
}
}
int CFlagManager::ShouldIAddThisCommand(const AMX *amx, const cell *params, const char *cmdname) const
{
// If flagmanager is disabled then ignore this
if (m_iDisabled)
{
return 0;
}
// If 5th param exists it was compiled after this change was made
// if it does not exist, try our logic at the end of this function
// 5th param being > 0 means explicit yes
// < 0 means auto detect (default is -1), treat it like there was no 5th param
// 0 means explicit no
if ((params[0] / sizeof(cell)) >= 5)
{
if (params[5]>0) // This command was explicitly told to be included
{
return 1;
}
else if (params[5]==0) // this command was explicitly told to NOT be used
{
return 0;
}
}
// auto detect if we should use this command
// if command access is -1 (default, not set to ADMIN_ALL or any other access), then no
if (params[3]==-1)
{
return 0;
}
// if command is (or starts with) "say", then no
if (strncmp(cmdname,"say",3)==0)
{
return 0;
}
// else use it
return 1;
};
void CFlagManager::Clear(void)
{
List<CFlagEntry *>::iterator iter;
List<CFlagEntry *>::iterator end;
iter=m_FlagList.begin();
end=m_FlagList.end();
while (iter!=end)
{
delete (*iter);
++iter;
}
m_FlagList.clear();
};
void CFlagManager::CheckIfDisabled(void)
{
if (atoi(get_localinfo("disableflagman","0"))==0)
{
m_iDisabled=0;
}
else
{
m_iDisabled=1;
}
};

219
amxmodx/CFlagManager.h Normal file
View File

@ -0,0 +1,219 @@
#ifndef CFLAGMANAGER_H
#define CFLAGMANAGER_H
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "sh_list.h"
#include "CString.h"
#include "amxmodx.h"
class CFlagEntry
{
private:
String m_strName; // command name ("amx_slap")
String m_strFlags; // string flags ("a","b")
String m_strComment; // comment to write ("; admincmd.amxx")
int m_iFlags; // bitmask flags
int m_iNeedWritten; // write this command on map change?
int m_iHidden; // set to 1 when the command is set to "!" access in
// the .ini file: this means do not process this command
public:
CFlagEntry()
{
m_iNeedWritten=0;
m_iFlags=0;
m_iHidden=0;
};
const int NeedWritten(void) const
{
return m_iNeedWritten;
};
void SetNeedWritten(const int i=1)
{
m_iNeedWritten=i;
};
const String *GetName(void) const
{
return &m_strName;
};
const String *GetFlags(void) const
{
return &m_strFlags;
};
const String *GetComment(void) const
{
return &m_strComment;
};
const int Flags(void) const
{
return m_iFlags;
};
void SetName(const char *data)
{
m_strName.assign(data);
};
void SetFlags(const char *flags)
{
// If this is a "!" entry then stop
if (flags && flags[0]=='!')
{
SetHidden(1);
return;
}
m_strFlags.assign(flags);
m_iFlags=UTIL_ReadFlags(flags);
};
void SetFlags(const int flags)
{
m_iFlags=flags;
char FlagsString[32];
UTIL_GetFlags(FlagsString, flags);
m_strFlags.assign(FlagsString);
};
void SetComment(const char *comment)
{
m_strComment.assign(comment);
};
void SetHidden(int i=1)
{
m_iHidden=i;
};
int IsHidden(void) const
{
return m_iHidden;
};
};
class CFlagManager
{
private:
List<CFlagEntry *> m_FlagList;
String m_strConfigFile;
struct stat m_Stat;
int m_iForceRead;
int m_iDisabled;
void CreateIfNotExist(void) const
{
FILE *fp;
fp=fopen(m_strConfigFile.c_str(),"r");
if (!fp)
{
// File does not exist, create the header
fp=fopen(m_strConfigFile.c_str(),"a");
if (fp)
{
fprintf(fp,"; This file will store the commands used by plugins, and their access level\n");
fprintf(fp,"; To change the access of a command, edit the flags beside it and then\n");
fprintf(fp,"; change the server's map.\n;\n");
fprintf(fp,"; Example: If I wanted to change the amx_slap access to require\n");
fprintf(fp,"; RCON access (flag \"l\") I would change this:\n");
fprintf(fp,"; \"amx_slap\" \"e\" ; admincmd.amxx\n");
fprintf(fp,"; To this:\n");
fprintf(fp,"; \"amx_slap\" \"l\" ; admincmd.amxx\n;\n");
fprintf(fp,"; To disable a specific command from being used with the command manager\n");
fprintf(fp,"; and to only use the plugin-specified access set the flag to \"!\"\n;\n");
fprintf(fp,"; NOTE: The plugin name at the end is just for reference to what plugin\n");
fprintf(fp,"; uses what commands. It is ignored.\n\n");
fclose(fp);
};
}
};
/**
* Returns 1 if the timestamp for the file is different than the one we have loaded
* 0 otherwise
*/
inline int NeedToLoad(void)
{
struct stat TempStat;
stat(m_strConfigFile.c_str(),&TempStat);
// If the modified timestamp does not match the stored
// timestamp than we need to re-read this file.
// Otherwise, ignore the file.
if (TempStat.st_mtime != m_Stat.st_mtime)
{
// Save down the modified timestamp
m_Stat.st_mtime=TempStat.st_mtime;
return 1;
};
return 0;
};
public:
CFlagManager()
{
memset(&m_Stat,0x0,sizeof(struct stat));
m_iDisabled=0;
m_iForceRead=0;
};
~CFlagManager()
{
WriteCommands();
};
/**
* Sets the filename in relation to amxmodx/configs
*/
void SetFile(const char *Filename="cmdaccess.ini");
const char *GetFile(void) const { return m_strConfigFile.c_str(); };
/**
* Parse the file, and load all entries
* Returns 1 on success, 0 on refusal (no need to), and -1 on error
*/
const int LoadFile(const int force=0);
/**
* Checks if the command exists in the list
* If it does, it byrefs the flags for it
* If it does not, it adds it to the list
* These are added from register_*cmd calls
*/
void LookupOrAdd(const char *Command, int &Flags, AMX *Plugin);
/**
* Write the commands back to the file
*/
void WriteCommands(void);
/**
* Add this straight from the cmdaccess.ini file
*/
void AddFromFile(const char *Command, const char *Flags);
/**
* Checks if this command should be added to flagman or not
* This is only checked when adding commands from the register_* natives
* If an admin manually adds a command to cmdaccess.ini it will be used
* regardless of whatever this function would say should be done with it
*/
int ShouldIAddThisCommand(const AMX *amx, const cell *params, const char *cmdname) const;
void Clear(void);
void CheckIfDisabled(void);
};
#endif // CFLAGMANAGER_H

View File

@ -304,4 +304,87 @@ public:
inline bool isNewTeam() { return newTeam ? true : false; }
};
class CAdminData
{
private:
cell m_AuthData[44];
cell m_Password[32];
cell m_Flags;
cell m_Access;
public:
CAdminData()
{
m_AuthData[0]=0;
m_Password[0]=0;
m_Flags=0;
m_Access=0;
};
void SetAccess(cell Access)
{
m_Access=Access;
};
cell GetAccess(void) const
{
return m_Access;
};
void SetFlags(cell Flags)
{
m_Flags=Flags;
};
cell GetFlags(void) const
{
return m_Flags;
};
void SetAuthID(const cell *Input)
{
unsigned int i=0;
while (i<sizeof(m_AuthData)-1)
{
if ((m_AuthData[i++]=*Input++)==0)
{
return;
}
}
m_AuthData[sizeof(m_AuthData)-1]=0;
};
const cell *GetAuthID(void) const
{
return &m_AuthData[0];
};
void SetPass(const cell *Input)
{
unsigned int i=0;
while (i<sizeof(m_Password)-1)
{
if ((m_Password[i++]=*Input++)==0)
{
return;
}
}
m_Password[sizeof(m_Password)-1]=0;
};
const cell *GetPass(void) const
{
return &m_Password[0];
};
CAdminData & operator = (const CAdminData &src)
{
this->SetAccess(src.GetAccess());
this->SetFlags(src.GetFlags());
this->SetAuthID(src.GetAuthID());
this->SetPass(src.GetPass());
return *this;
}
};
#endif //CMISC_H

View File

@ -129,7 +129,7 @@ public:
}
//Added this for amxx inclusion
bool empty()
bool empty() const
{
if (!v)
return true;
@ -140,7 +140,7 @@ public:
return false;
}
size_t size()
size_t size() const
{
if (v)
return strlen(v);

View File

@ -20,7 +20,7 @@ OBJECTS = meta_api.cpp CFile.cpp CVault.cpp vault.cpp float.cpp file.cpp modules
amxxfile.cpp CLang.cpp md5.cpp emsg.cpp CForward.cpp CPlugin.cpp CModule.cpp \
CMenu.cpp util.cpp amx.cpp amxdbg.cpp natives.cpp newmenus.cpp debugger.cpp \
optimizer.cpp format.cpp messages.cpp libraries.cpp vector.cpp sorting.cpp \
amxmod_compat.cpp nongpl_matches.cpp
amxmod_compat.cpp nongpl_matches.cpp CFlagManager.cpp
LINK = -lgcc -static-libgcc

View File

@ -35,8 +35,13 @@
#include "debugger.h"
#include "binlog.h"
#include "libraries.h"
#include "CFlagManager.h"
#include "nongpl_matches.h"
extern CFlagManager FlagMan;
CVector<CAdminData *> DynamicAdmins;
char CVarTempBuffer[64];
const char *invis_cvar_list[5] = {"amxmodx_version", "amxmodx_modules", "amx_debug", "amx_mldebug", "amx_client_languages"};
bool CheckBadConList(const char *cvar, int type)
@ -1255,6 +1260,11 @@ static cell AMX_NATIVE_CALL register_concmd(AMX *amx, cell *params) /* 4 param *
listable = false;
}
if (FlagMan.ShouldIAddThisCommand(amx,params,temp)==1)
{
FlagMan.LookupOrAdd(temp,access,amx);
}
if ((cmd = g_commands.registerCommand(plugin, idx, temp, info, access, listable)) == NULL)
return 0;
@ -1295,6 +1305,11 @@ static cell AMX_NATIVE_CALL register_clcmd(AMX *amx, cell *params) /* 4 param */
listable = false;
}
if (FlagMan.ShouldIAddThisCommand(amx,params,temp)==1)
{
FlagMan.LookupOrAdd(temp,access,amx);
}
if ((cmd = g_commands.registerCommand(plugin, idx, temp, info, access, listable)) == NULL)
return 0;
@ -1713,8 +1728,8 @@ static cell AMX_NATIVE_CALL set_pcvar_float(AMX *amx, cell *params)
return 0;
}
ptr->value = amx_ctof(params[2]);
snprintf(CVarTempBuffer,sizeof(CVarTempBuffer)-1,"%f",amx_ctof(params[2]));
(*g_engfuncs.pfnCvar_DirectSet)(ptr, &CVarTempBuffer[0]);
return 1;
}
@ -1735,7 +1750,7 @@ static cell AMX_NATIVE_CALL get_pcvar_num(AMX *amx, cell *params)
return 0;
}
return (int)ptr->value;
return atoi(ptr->string);
}
static cell AMX_NATIVE_CALL get_cvar_num(AMX *amx, cell *params) /* 1 param */
@ -1753,7 +1768,7 @@ static cell AMX_NATIVE_CALL get_cvar_num(AMX *amx, cell *params) /* 1 param */
}
}
}
return (int)CVAR_GET_FLOAT(get_amxstring(amx, params[1], 0, ilen));
return atoi(CVAR_GET_STRING(get_amxstring(amx, params[1], 0, ilen)));
}
static cell AMX_NATIVE_CALL set_pcvar_num(AMX *amx, cell *params)
@ -1765,7 +1780,8 @@ static cell AMX_NATIVE_CALL set_pcvar_num(AMX *amx, cell *params)
return 0;
}
ptr->value = (float)params[2];
snprintf(CVarTempBuffer,sizeof(CVarTempBuffer)-1,"%d",params[2]);
(*g_engfuncs.pfnCvar_DirectSet)(ptr, &CVarTempBuffer[0]);
return 1;
}
@ -1789,6 +1805,22 @@ static cell AMX_NATIVE_CALL set_cvar_string(AMX *amx, cell *params) /* 2 param *
return 1;
}
static cell AMX_NATIVE_CALL set_pcvar_string(AMX *amx, cell *params) /* 2 param */
{
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
if (!ptr)
{
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
return 0;
}
int len;
(*g_engfuncs.pfnCvar_DirectSet)(ptr, get_amxstring(amx,params[2],0,len));
return 1;
}
static cell AMX_NATIVE_CALL log_message(AMX *amx, cell *params) /* 1 param */
{
int len;
@ -4408,9 +4440,109 @@ static cell AMX_NATIVE_CALL GetLangTransKey(AMX *amx, cell *params)
return g_langMngr.GetKeyEntry(key);
}
static cell AMX_NATIVE_CALL admins_push(AMX *amx, cell *params)
{
// admins_push("SteamID","password",access,flags);
CAdminData *TempData=new CAdminData;;
TempData->SetAuthID(get_amxaddr(amx,params[1]));
TempData->SetPass(get_amxaddr(amx,params[2]));
TempData->SetAccess(params[3]);
TempData->SetFlags(params[4]);
DynamicAdmins.push_back(TempData);
return 0;
};
static cell AMX_NATIVE_CALL admins_flush(AMX *amx, cell *params)
{
// admins_flush();
size_t iter=DynamicAdmins.size();
while (iter--)
{
delete DynamicAdmins[iter];
}
DynamicAdmins.clear();
return 0;
};
static cell AMX_NATIVE_CALL admins_num(AMX *amx, cell *params)
{
// admins_num();
return static_cast<cell>(DynamicAdmins.size());
};
static cell AMX_NATIVE_CALL admins_lookup(AMX *amx, cell *params)
{
// admins_lookup(Num, Property, Buffer[]={0}, BufferSize=-1);
if (params[1]>=static_cast<int>(DynamicAdmins.size()))
{
LogError(amx,AMX_ERR_NATIVE,"Invalid admins num");
return 1;
};
int BufferSize;
cell *Buffer;
const cell *Input;
switch(params[2])
{
case Admin_Auth:
BufferSize=params[4];
Buffer=get_amxaddr(amx, params[3]);
Input=DynamicAdmins[params[1]]->GetAuthID();
while (BufferSize-->0)
{
if ((*Buffer++=*Input++)==0)
{
return 0;
}
}
// hit max buffer size, terminate string
*Buffer=0;
return 0;
break;
case Admin_Password:
BufferSize=params[4];
Buffer=get_amxaddr(amx, params[3]);
Input=DynamicAdmins[params[1]]->GetPass();
while (BufferSize-->0)
{
if ((*Buffer++=*Input++)==0)
{
return 0;
}
}
// hit max buffer size, terminate string
*Buffer=0;
return 0;
break;
case Admin_Access:
return DynamicAdmins[params[1]]->GetAccess();
break;
case Admin_Flags:
return DynamicAdmins[params[1]]->GetFlags();
break;
};
// unknown property
return 0;
};
AMX_NATIVE_INFO amxmodx_Natives[] =
{
{"abort", amx_abort},
{"admins_flush", admins_flush},
{"admins_lookup", admins_lookup},
{"admins_num", admins_num},
{"admins_push", admins_push},
{"amxx_setpl_curweap", amxx_setpl_curweap},
{"arrayset", arrayset},
{"get_addr_val", get_addr_val},
@ -4575,6 +4707,7 @@ AMX_NATIVE_INFO amxmodx_Natives[] =
{"set_localinfo", set_localinfo},
{"set_pcvar_flags", set_pcvar_flags},
{"set_pcvar_float", set_pcvar_float},
{"set_pcvar_string", set_pcvar_string},
{"set_pcvar_num", set_pcvar_num},
{"set_task", set_task},
{"set_user_flags", set_user_flags},

View File

@ -339,6 +339,14 @@ struct func_s
const char *desc;
};
enum AdminProperty
{
Admin_Auth = 0,
Admin_Password,
Admin_Access,
Admin_Flags
};
extern enginefuncs_t *g_pEngTable;
#endif // AMXMODX_H

View File

@ -47,6 +47,9 @@
#include "messages.h"
#include "amxmod_compat.h"
#include "CFlagManager.h"
plugin_info_t Plugin_info =
{
META_INTERFACE_VERSION, // ifvers
@ -73,6 +76,7 @@ void (*function)(void*);
void (*endfunction)(void*);
extern List<AUTHORIZEFUNC> g_auth_funcs;
extern CVector<CAdminData *> DynamicAdmins;
CLog g_log;
CForwardMngr g_forwards;
@ -86,7 +90,7 @@ CPlayer* mPlayer;
CPluginMngr g_plugins;
CTaskMngr g_tasksMngr;
CmdMngr g_commands;
CFlagManager FlagMan;
EventsMngr g_events;
Grenades g_grenades;
LogEventsMngr g_logevents;
@ -381,6 +385,8 @@ int C_Spawn(edict_t *pent)
get_localinfo("amx_pluginsdir", "addons/amxmodx/plugins");
get_localinfo("amx_logdir", "addons/amxmodx/logs");
FlagMan.LoadFile();
char map_pluginsfile_path[256];
char configs_dir[256];
@ -390,6 +396,31 @@ int C_Spawn(edict_t *pent)
get_localinfo_r("amxx_configsdir", "addons/amxmodx/configs", configs_dir, sizeof(configs_dir)-1);
g_plugins.CALMFromFile(get_localinfo("amxx_plugins", "addons/amxmodx/configs/plugins.ini"));
LoadExtraPluginsToPCALM(configs_dir);
char temporaryMap[64];
strncpy(temporaryMap,STRING(gpGlobals->mapname),sizeof(temporaryMap)-1);
int i=0;
while (temporaryMap[i]!='_' && temporaryMap[i]!='\0')
{
++i;
}
if (temporaryMap[i]=='_')
{
// this map has a prefix
temporaryMap[i]='\0';
snprintf(map_pluginsfile_path, sizeof(map_pluginsfile_path)-1,
"%s/maps/prefixes/plugins-%s.ini",
configs_dir,
temporaryMap);
g_plugins.CALMFromFile(map_pluginsfile_path);
}
snprintf(map_pluginsfile_path, sizeof(map_pluginsfile_path)-1,
"%s/maps/plugins-%s.ini",
configs_dir,
@ -650,10 +681,19 @@ void C_ServerDeactivate_Post()
ClearMessages();
// Flush the dynamic admins list
for (size_t iter=DynamicAdmins.size();iter--; )
{
delete DynamicAdmins[iter];
}
DynamicAdmins.clear();
for (unsigned int i=0; i<g_hudsync.size(); i++)
delete [] g_hudsync[i];
g_hudsync.clear();
FlagMan.WriteCommands();
// last memreport
#ifdef MEMORY_TEST
if (g_memreport_enabled)
@ -1062,20 +1102,6 @@ void C_MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict
{
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 = (int)ed->v.armorvalue;
*z = stop;
ed->v.armorvalue = (float)stop;
}
mPlayerIndex = ENTINDEX(ed);
mPlayer = GET_PLAYER_POINTER_I(mPlayerIndex);
} else {
@ -1424,6 +1450,8 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m
GET_HOOK_TABLES(PLID, &g_pEngTable, NULL, NULL);
FlagMan.SetFile("cmdaccess.ini");
return (TRUE);
}

View File

@ -361,6 +361,9 @@
<File
RelativePath="..\CFile.cpp">
</File>
<File
RelativePath="..\CFlagManager.cpp">
</File>
<File
RelativePath="..\CForward.cpp">
</File>
@ -515,6 +518,9 @@
<File
RelativePath="..\CFile.h">
</File>
<File
RelativePath="..\CFlagManager.h">
</File>
<File
RelativePath="..\CForward.h">
</File>

View File

@ -505,6 +505,10 @@
RelativePath="..\CFile.cpp"
>
</File>
<File
RelativePath="..\CFlagManager.cpp"
>
</File>
<File
RelativePath="..\CForward.cpp"
>
@ -710,6 +714,10 @@
RelativePath="..\CFile.h"
>
</File>
<File
RelativePath="..\CFlagManager.h"
>
</File>
<File
RelativePath="..\CForward.h"
>

View File

@ -892,7 +892,9 @@ static cell AMX_NATIVE_CALL menu_destroy(AMX *amx, cell *params)
GETMENU_R(params[1]);
if (pMenu->isDestroying)
{
return 0; //prevent infinite recursion
}
pMenu->isDestroying = true;
g_menucmds.removeMenuId(pMenu->menuId);
@ -938,8 +940,16 @@ static cell AMX_NATIVE_CALL player_menu_info(AMX *amx, cell *params)
*m = player->menu;
*n = player->newmenu;
if (params[0] / sizeof(cell) == 4)
{
cell *addr = get_amxaddr(amx, params[4]);
*addr = player->page;
}
if ( (*m != 0 && *m != -1) || (*n != -1))
{
return 1;
}
return 0;
}

View File

@ -2773,7 +2773,7 @@ void ValidateMacros_DontCallThis_Smiley()
MF_FindLibrary(NULL, LibType_Class);
MF_AddLibraries(NULL, LibType_Class, NULL);
MF_RemoveLibraries(NULL);
MF_OverrideNatives(NULL);
MF_OverrideNatives(NULL, "");
}
#endif

View File

@ -57,6 +57,7 @@ extern int gmsgInitObj;
extern int gmsgSetObj;
extern int iFGrenade;
extern int iFRocket;
extern int iFInitCP;
extern CPlayer players[33];

View File

@ -29,6 +29,7 @@
*
*/
#include <string.h>
#include "amxxmodule.h"
#include "dodfun.h"
@ -37,6 +38,7 @@ funEventCall modMsgs[MAX_REG_MSGS];
void (*function)(void*);
void (*endfunction)(void*);
CPlayer* mPlayer;
CPlayer* gPlayerRocket;
CPlayer players[33];
CObjective mObjects;
@ -46,6 +48,7 @@ int mDest;
int mPlayerIndex;
int iFGrenade;
int iFRocket;
int iFInitCP;
int gmsgCurWeapon;
@ -96,20 +99,6 @@ void ServerActivate_Post( edict_t *pEdictList, int edictCount, int clientMax ){
RETURN_META(MRES_IGNORED);
}
void PlayerPreThink_Post( edict_t *pEntity ) {
CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity);
if ( pPlayer->staminaSet ) {
if ( (int)pEntity->v.fuser4 > pPlayer->staminaMax )
pEntity->v.fuser4 = (float)pPlayer->staminaMax;
else if ( (int)pEntity->v.fuser4 < pPlayer->staminaMin )
pEntity->v.fuser4 = (float)pPlayer->staminaMin;
}
RETURN_META(MRES_IGNORED);
}
void ServerDeactivate() {
for(int i = 1;i<=gpGlobals->maxClients; ++i){
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
@ -208,55 +197,108 @@ void WriteEntity_Post(int iValue) {
RETURN_META(MRES_IGNORED);
}
void SetModel_Post(edict_t *e, const char *m){
if ( !e->v.owner || !e->v.dmgtime )
RETURN_META(MRES_IGNORED);
void PlayerPreThink_Post(edict_t *pEntity)
{
CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity);
int owner = ENTINDEX(e->v.owner);
if ( owner && owner<33 && m[7]=='w' && m[8]=='_' ){
// Stamina
if(pPlayer->staminaSet)
{
if ( (int)pEntity->v.fuser4 > pPlayer->staminaMax)
pEntity->v.fuser4 = (float)pPlayer->staminaMax;
int w_id = 0;
CPlayer* pPlayer = GET_PLAYER_POINTER_I(owner);
bool newNade = ( pPlayer->current == 13 || pPlayer->current == 14 ) ? true:false;
if ( m[9]=='g' && m[10]=='r' && m[11]=='e' && m[12]=='n' )
newNade ? w_id = 13 : w_id = 16; // grenade
else if ( m[9]=='m' && m[10]=='i' )
newNade ? w_id = 36 : w_id = 16 ; // mills ; should I add mills_grenade_ex weapon ?
else if ( m[9]=='s' && m[10]=='t' && m[11]=='i')
newNade ? w_id = 14 : w_id = 15; // stick
if ( !w_id )
RETURN_META(MRES_IGNORED);
MF_ExecuteForward( iFGrenade, pPlayer->index, ENTINDEX(e) ,w_id );
/* fuse start */
if ( pPlayer->fuseSet ){
if ( newNade ){
if ( pPlayer->fuseType & 1<<0 ){
e->v.dmgtime += pPlayer->nadeFuse - 5.0;
}
}
else{ // cought
bool ownNade = ( (pPlayer->pEdict->v.team == 1 && pPlayer->current == 16) || (pPlayer->pEdict->v.team == 2 && pPlayer->current == 15) ) ? true:false;
if ( ownNade ){
float fExp = e->v.dmgtime - gpGlobals->time;
e->v.dmgtime += pPlayer->nadeFuse - fExp;
}
}
}
/* fuse end */
else if ( (int)pEntity->v.fuser4 < pPlayer->staminaMin)
pEntity->v.fuser4 = (float)pPlayer->staminaMin;
}
if(pPlayer->current == 29 || pPlayer->current == 30 || pPlayer->current == 31)
{
if(!(pPlayer->pEdict->v.oldbuttons&IN_ATTACK) && (pPlayer->pEdict->v.button&IN_ATTACK))
gPlayerRocket = GET_PLAYER_POINTER(pEntity);
}
RETURN_META(MRES_IGNORED);
}
void OnAmxxAttach() {
void SetModel_Post(edict_t *e, const char *m)
{
int w_id = 0;
if(!e->v.owner || !e->v.dmgtime)
{
int owner = ENTINDEX(e->v.owner);
if(owner && owner < 33 && m[7]=='w' && m[8]=='_')
{
CPlayer* pPlayer = GET_PLAYER_POINTER_I(owner);
bool newNade = (pPlayer->current == 13 || pPlayer->current == 14) ? true : false;
if(m[9]=='g' && m[10]=='r' && m[11]=='e' && m[12]=='n')
w_id = newNade ? 13 : 16; // grenade
else if(m[9]=='m' && m[10]=='i')
w_id = newNade ? 36 : 16 ; // mills ; should I add mills_grenade_ex weapon ?
else if(m[9]=='s' && m[10]=='t' && m[11]=='i')
w_id = newNade ? 14 : 15; // stick
if(!w_id)
RETURN_META(MRES_IGNORED);
if(w_id == 13 || w_id == 14 || w_id == 15 || w_id == 16 || w_id == 36)
{
MF_ExecuteForward(iFGrenade, pPlayer->index, ENTINDEX(e), w_id);
/* fuse start */
if(pPlayer->fuseSet)
{
if(newNade)
{
if(pPlayer->fuseType & 1<<0)
{
e->v.dmgtime += pPlayer->nadeFuse - 5.0;
}
}
else
{
float fExp = e->v.dmgtime - gpGlobals->time;
e->v.dmgtime += pPlayer->nadeFuse - fExp;
}
}
/* fuse end */
}
}
else if(strstr(m, "rocket") && gPlayerRocket)
{
if(strstr(m, "bazooka"))
w_id = 29;
else if(strstr(m, "piat"))
w_id = 30;
else if(strstr(m, "pschreck"))
w_id = 31;
MF_ExecuteForward(iFRocket, gPlayerRocket->index, ENTINDEX(e), w_id);
gPlayerRocket = NULL;
}
}
RETURN_META(MRES_IGNORED);
}
void OnAmxxAttach()
{
MF_AddNatives( base_Natives );
MF_AddNatives( pd_Natives );
}
void OnPluginsLoaded(){
iFGrenade = MF_RegisterForward("grenade_throw",ET_IGNORE,FP_CELL,FP_CELL,FP_CELL,FP_DONE);
void OnPluginsLoaded()
{
iFGrenade = MF_RegisterForward("grenade_throw",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*Grenade Ent*/,FP_CELL/*Weapon ID*/,FP_DONE);
iFRocket = MF_RegisterForward("rocket_shoot",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*Rocket Ent*/,FP_CELL/*Weapon ID*/,FP_DONE);
iFInitCP = MF_RegisterForward("controlpoints_init",ET_IGNORE,FP_DONE);
}

View File

@ -5,7 +5,7 @@
// Module info
#define MODULE_NAME "DoD Fun"
#define MODULE_VERSION "1.76b"
#define MODULE_VERSION "1.76c_beta_a"
#define MODULE_AUTHOR "AMX Mod X Dev Team"
#define MODULE_URL "http://www.amxmodx.org"
#define MODULE_LOGTAG "DODFUN"

View File

@ -33,73 +33,31 @@
#include "CMisc.h"
#include "dodx.h"
// *****************************************************
// class Grenades
// *****************************************************
void Grenades::put( edict_t* grenade, float time, int type, CPlayer* player )
{
Obj* a = new Obj;
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;
float lastTime = 0.0;
Obj** a = &head;
while ( *a ){
if ( (*a)->time > gpGlobals->time ) {
if ( (*a)->grenade == enemy ) {
found = true;
if ( (*a)->time > lastTime ){ // we need this because of catched grenades
(*p) = (*a)->player; // two people can have the same nade in our list
type = (*a)->type;
lastTime = (*a)->time;
}
}
}
else {
Obj* next = (*a)->next;
delete *a;
*a = next;
continue;
}
a = &(*a)->next;
}
return found;
}
void Grenades::clear()
{
while(head){
Obj* a = head->next;
delete head;
head = a;
}
}
// *****************************************************
// class CPlayer
// *****************************************************
void CPlayer::Disconnect(){
void CPlayer::Disconnect()
{
ingame = false;
bot = false;
savedScore = 0;
// Zors
olddeadflag=0;
oldteam=0;
oldplayerclass=0;
is_model_set=false;
body_num=0;
position = 0;
olddeadflag = 0;
oldteam = 0;
oldclass = 0;
oldprone = 0;
oldstamina = 0.0f;
// Model Stuff
sModel.is_model_set = false;
sModel.body_num = 0;
// Object stuff
object.pEdict = NULL;
object.type = 0;
object.carrying = false;
object.do_forward = false;
if ( ignoreBots(pEdict) || !isModuleActive() ) // ignore if he is bot and bots rank is disabled or module is paused
return;
@ -141,11 +99,13 @@ void CPlayer::Connect(const char* nn,const char* ippp ){
void CPlayer::restartStats(bool all)
{
if ( all ){
if ( all )
{
memset(weapons,0,sizeof(weapons));
memset(&round,0,sizeof(round));
memset(weaponsRnd,0,sizeof(weaponsRnd));
}
memset(weaponsLife,0,sizeof(weaponsLife)); //DEC-Weapon (Round) stats
memset(attackers,0,sizeof(attackers));
memset(victims,0,sizeof(victims));
@ -154,6 +114,12 @@ void CPlayer::restartStats(bool all)
void CPlayer::Init( int pi, edict_t* pe )
{
aiming = 0;
wpnModel = 0;
wpnscount = 0;
lastScore = 0;
sendScore = 0;
clearRound = 0.0f;
pEdict = pe;
index = pi;
current = 0;
@ -161,14 +127,24 @@ void CPlayer::Init( int pi, edict_t* pe )
ingame = false;
bot = false;
savedScore = 0;
olddeadflag = 0;
oldteam = 0;
oldclass = 0;
oldprone = 0;
oldstamina = 0.0f;
// Zors
olddeadflag=0;
oldteam=0;
oldplayerclass=0;
is_model_set=false;
body_num=0;
position = 0;
do_scoped = false;
is_scoped = false;
// Model Stuff
sModel.is_model_set = false;
sModel.body_num = 0;
// Object stuff
object.pEdict = NULL;
object.type = 0;
object.carrying = false;
object.do_forward = false;
}
void CPlayer::saveKill(CPlayer* pVictim, int wweapon, int hhs, int ttk){
@ -176,7 +152,8 @@ void CPlayer::saveKill(CPlayer* pVictim, int wweapon, int hhs, int ttk){
if ( ignoreBots(pEdict,pVictim->pEdict) )
return;
if ( pVictim->index == index ){ // killed self
if ( pVictim->index == index )
{ // killed self
pVictim->weapons[0].deaths++;
pVictim->life.deaths++;
pVictim->round.deaths++;
@ -293,7 +270,8 @@ void CPlayer::saveHit(CPlayer* pVictim, int wweapon, int ddamage, int bbody){
round.bodyHits[bbody]++;
}
void CPlayer::saveShot(int weapon){
void CPlayer::saveShot(int weapon)
{
if ( ignoreBots(pEdict) )
return;
@ -310,7 +288,8 @@ void CPlayer::saveShot(int weapon){
weaponsRnd[0].shots++; // DEC-Weapon (round) stats
}
void CPlayer::updateScore(int weapon, int score){
void CPlayer::updateScore(int weapon, int score)
{
if ( ignoreBots(pEdict) )
return;
@ -325,7 +304,8 @@ void CPlayer::updateScore(int weapon, int score){
weapons[0].points += score;
}
void CPlayer::killPlayer(){
void CPlayer::killPlayer()
{
pEdict->v.dmg_inflictor = NULL;
pEdict->v.health = 0;
pEdict->v.deadflag = DEAD_RESPAWNABLE;
@ -335,13 +315,13 @@ void CPlayer::killPlayer(){
void CPlayer::initModel(char* model)
{
newmodel = model;
is_model_set = true;
strcpy(sModel.modelclass, (const char*)model);
sModel.is_model_set = true;
}
void CPlayer::clearModel()
{
is_model_set = false;
sModel.is_model_set = false;
}
bool CPlayer::setModel()
@ -349,10 +329,10 @@ bool CPlayer::setModel()
if(!ingame || ignoreBots(pEdict))
return false;
if(is_model_set)
if(sModel.is_model_set)
{
ENTITY_SET_KEYVALUE(pEdict, "model", newmodel);
pEdict->v.body = body_num;
ENTITY_SET_KEYVALUE(pEdict, "model", sModel.modelclass);
pEdict->v.body = sModel.body_num;
return true;
}
@ -364,12 +344,17 @@ void CPlayer::setBody(int bn)
if(!ingame || ignoreBots(pEdict))
return;
body_num = bn;
sModel.body_num = bn;
return;
}
void CPlayer::checkStatus()
/*
iuser3 = 0 standing up
iuser3 = 1 going prone or mg tearing down
iuser3 = 2 setting up mg
*/
void CPlayer::PreThink()
{
if(!ingame || ignoreBots(pEdict))
return;
@ -380,12 +365,160 @@ void CPlayer::checkStatus()
if(oldteam != pEdict->v.team && iFTeamForward != -1)
MF_ExecuteForward(iFTeamForward, index, pEdict->v.team, oldteam);
if(oldplayerclass != pEdict->v.playerclass)
MF_ExecuteForward(iFClassForward, index, pEdict->v.playerclass, oldplayerclass);
if(oldclass != pEdict->v.playerclass && iFClassForward != -1)
MF_ExecuteForward(iFClassForward, index, pEdict->v.playerclass, oldclass);
if(oldprone != pEdict->v.iuser3 && oldprone != 2 && pEdict->v.iuser3 != 2 && iFProneForward != -1)
MF_ExecuteForward(iFProneForward, index, pEdict->v.iuser3);
if(oldstamina > pEdict->v.fuser4 && iFStaminaForward != -1)
MF_ExecuteForward(iFStaminaForward, index, ((int)pEdict->v.fuser4));
if(wpns_bitfield != pEdict->v.weapons)
WeaponsCheck(pEdict->v.weapons & ~(1<<31));
// Set the old variables for
oldprone = pEdict->v.iuser3;
olddeadflag = pEdict->v.deadflag;
oldteam = pEdict->v.team;
oldplayerclass = pEdict->v.playerclass;
oldclass = pEdict->v.playerclass;
oldstamina = pEdict->v.fuser4;
wpns_bitfield = pEdict->v.weapons & ~(1<<31);
}
void CPlayer::Scoping(int value)
{
// Everyone gets a 0 then another call for 90, so I need to figure out
// what weapon they have before I can then check if they are scoped or not
do_scoped = false;
switch(value)
{
// This is when the scope is dropped from the eye
case 0:
// Is this an initial call
if(mPlayer->current == 0)
return;
// SKar Spring SFG42 SEnfield
if((mPlayer->current == 6 || mPlayer->current == 9 || mPlayer->current == 32 || mPlayer->current == 35) && is_scoped)
{
is_scoped = false;
do_scoped = true;
}
break;
// This is when the scope is put up to the eye
case 20:
// SKar Spring SFG42 SEnfield
if((mPlayer->current == 6 || mPlayer->current == 9 || mPlayer->current == 32 || mPlayer->current == 35) && !is_scoped)
{
is_scoped = true;
do_scoped = true;
}
break;
// This means the scope has been initialized
case 90:
is_scoped = false;
return;
};
}
void CPlayer::ScopingCheck()
{
if(do_scoped)
MF_ExecuteForward(iFScopeForward, index, (int)is_scoped);
}
void CPlayer::WeaponsCheck(int weapons)
{
if(wpns_bitfield == 0)
return;
else if(pEdict->v.weapons == 0)
return;
int old;
int cur;
for(int i = 1; i < MAX_WEAPONS; ++i)
{
// Check to see we are not talking about a grenade and we have changed
if(i != 13 && i != 14 && i != 15 && i != 16 && i != 36)
{
old = wpns_bitfield&(1<<i);
cur = weapons&(1<<i);
if(old != cur)
MF_ExecuteForward(iFWpnPickupForward, index, i, ((weapons&(1<<i)) ? 1 : 0));
}
}
}
// *****************************************************
// class Grenades
// *****************************************************
void Grenades::put(edict_t* grenade, float time, int type, CPlayer* player )
{
Obj* a = new Obj;
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;
float lastTime = 0.0;
Obj** a = &head;
while(*a)
{
if((*a)->time > gpGlobals->time)
{
if((*a)->grenade == enemy)
{
found = true;
// we need this because of catched grenades
if((*a)->time > lastTime)
{
(*p) = (*a)->player; // two people can have the same nade in our list
type = (*a)->type;
lastTime = (*a)->time;
}
}
}
else
{
Obj* next = (*a)->next;
delete *a;
*a = next;
continue;
}
a = &(*a)->next;
}
return found;
}
void Grenades::clear()
{
while(head)
{
Obj* a = head->next;
delete head;
head = a;
}
}
// *****************************************************

View File

@ -47,101 +47,131 @@
#define MAX_TRACE 6
struct traceVault {
struct traceVault
{
char szName[16];
int iId;
int iAction;
float fDel;
};
#define ACT_NADE_NONE 0
#define ACT_NADE_SHOT 1<<0
#define ACT_NADE_PUT 1<<1
#define ACT_NADE_THROW 1<<2
#define ACT_NADE_NONE (0)
#define ACT_NADE_SHOT (1<<0)
#define ACT_NADE_PUT (1<<1)
#define ACT_NADE_THROW (1<<2)
#define ACT_ROCKET_NONE (0)
#define ACT_ROCKET_SHOT (1<<0)
#define ACT_ROCKET_PUT (1<<3)
// *****************************************************
// class CPlayer
// *****************************************************
class CPlayer {
private:
char ip[32];
public:
edict_t* pEdict;
int index;
int aiming;
int current;
int wpnModel;
class CPlayer
{
private:
char ip[32];
float savedScore;
int lastScore;
int sendScore;
public:
edict_t* pEdict;
int index;
int aiming;
int current;
int old;
int wpnModel;
int wpnscount;
int wpns_bitfield;
int old_weapons[DODMAX_WEAPONS];
bool ingame;
bool bot;
float clearStats;
float clearRound;
float savedScore;
int lastScore;
int sendScore;
struct PlayerWeapon : public Stats {
char* name;
int ammo;
int clip;
};
bool ingame;
bool bot;
float clearStats;
float clearRound;
PlayerWeapon weapons[DODMAX_WEAPONS];
PlayerWeapon attackers[33];
PlayerWeapon victims[33];
Stats weaponsLife[DODMAX_WEAPONS]; // DEC-Weapon (Life) stats
Stats weaponsRnd[DODMAX_WEAPONS]; // DEC-Weapon (Round) stats
Stats life;
Stats round;
int oldteam;
int olddeadflag;
int oldclass;
float oldstamina;
RankSystem::RankStats* rank;
struct ModelStruct
{
int body_num;
bool is_model_set;
char* modelclass;
}
sModel;
void Init( int pi, edict_t* pe );
void Connect(const char* name,const char* ip );
void PutInServer();
void Disconnect();
void saveKill(CPlayer* pVictim, int weapon, int hs, int tk);
void saveHit(CPlayer* pVictim, int weapon, int damage, int aiming);
void saveShot(int weapon);
void updateScore(int weapon, int score);
void restartStats(bool all = true);
void killPlayer();
int oldprone;
bool do_scoped;
bool is_scoped;
// Zors
int oldteam;
int olddeadflag;
int oldplayerclass;
struct ObjectStruct
{
edict_t* pEdict;
bool carrying;
bool do_forward;
int type;
}
object;
bool is_model_set;
char* newmodel;
int body_num;
struct PlayerWeapon : public Stats
{
char* name;
int ammo;
int clip;
};
int position;
PlayerWeapon weapons[DODMAX_WEAPONS];
PlayerWeapon attackers[33];
PlayerWeapon victims[33];
Stats weaponsLife[DODMAX_WEAPONS]; // DEC-Weapon (Life) stats
Stats weaponsRnd[DODMAX_WEAPONS]; // DEC-Weapon (Round) stats
Stats life;
Stats round;
void initModel(char*);
void clearModel();
bool setModel();
void setBody(int);
void checkStatus();
// Zors
RankSystem::RankStats* rank;
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));
}
void Init( int pi, edict_t* pe );
void Connect(const char* name,const char* ip );
void PutInServer();
void Disconnect();
void saveKill(CPlayer* pVictim, int weapon, int hs, int tk);
void saveHit(CPlayer* pVictim, int weapon, int damage, int aiming);
void saveShot(int weapon);
void updateScore(int weapon, int score);
void restartStats(bool all = true);
void killPlayer();
void initModel(char*);
void clearModel();
bool setModel();
void setBody(int);
void PreThink();
void Scoping(int);
void ScopingCheck();
void WeaponsCheck(int);
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));
}
};
// *****************************************************
// class Grenades
// *****************************************************
class Grenades
class Grenades // : public CObject
{
struct Obj
{
@ -154,11 +184,11 @@ class Grenades
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();
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();
};
// *****************************************************
@ -178,5 +208,7 @@ public:
void Init();
};
#endif // CMISC_H

View File

@ -32,62 +32,134 @@
#include "amxxmodule.h"
#include "dodx.h"
static cell AMX_NATIVE_CALL get_weapon_name(AMX *amx, cell *params){ // from id to name 3 params id, name, len
#define WEAPONLIST 71
/* Weapon names aren't send in WeaponList message in DoD */
weaponlist_s weaponlist[] =
{
{ 0, 0, 0, false}, // 0,
{ -1, 0, -1, true }, // DODW_AMERKNIFE = 1,
{ -1, 0, -1, true }, // DODW_GERKNIFE,
{ 4, 64, 7, true }, // DODW_COLT,
{ 4, 64, 8, true }, // DODW_LUGER,
{ 3, 128, 8, true }, // DODW_GARAND,
{ 3, 128, 5, true }, // DODW_SCOPED_KAR,
{ 1, 128, 30, true }, // DODW_THOMPSON,
{ 6, 128, 30, true }, // DODW_STG44,
{ 5, 128, 5, true }, // DODW_SPRINGFIELD,
{ 3, 128, 5, true }, // DODW_KAR,
{ 6, 128, 20, true }, // DODW_BAR,
{ 1, 130, 30, true }, // DODW_MP40,
{ 9, 24, -1, true }, // DODW_HANDGRENADE,
{ 11, 24, -1, true }, // DODW_STICKGRENADE,
{ 12, 24, -1, true }, // DODW_STICKGRENADE_EX,
{ 10, 24, -1, true }, // DODW_HANDGRENADE_EX,
{ 7, 2178, 250, true }, // DODW_MG42,
{ 8, 130, 150, true }, // DODW_30_CAL,
{ -1, 0, -1, true }, // DODW_SPADE,
{ 2, 128, 15, true }, // DODW_M1_CARBINE,
{ 2, 130, 75, true }, // DODW_MG34,
{ 1, 128, 30, true }, // DODW_GREASEGUN,
{ 6, 128, 20, true }, // DODW_FG42,
{ 2, 128, 10, true }, // DODW_K43,
{ 3, 128, 10, true }, // DODW_ENFIELD,
{ 1, 128, 30, true }, // DODW_STEN,
{ 6, 128, 30, true }, // DODW_BREN,
{ 4, 64, 6, true }, // DODW_WEBLEY,
{ 13, 642, 1, true }, // DODW_BAZOOKA,
{ 13, 642, 1, true }, // DODW_PANZERSCHRECK,
{ 13, 642, 1, true }, // DODW_PIAT,
{ 3, 128, 20, true }, // DODW_SCOPED_FG42, UNSURE ABOUT THIS ONE
{ 2, 128, 15, true }, // DODW_FOLDING_CARBINE,
{ 0, 0, 0, false}, // DODW_KAR_BAYONET,
{ 3, 128, 10, true }, // DODW_SCOPED_ENFIELD, UNSURE ABOUT THIS ONE
{ 9, 24, -1, true }, // DODW_MILLS_BOMB,
{ -1, 0, -1, true }, // DODW_BRITKNIFE,
{ 38, 0, 0, false}, // DODW_GARAND_BUTT,
{ 39, 0, 0, false}, // DODW_ENFIELD_BAYONET,
{ 40, 0, 0, false}, // DODW_MORTAR,
{ 41, 0, 0, false}, // DODW_K43_BUTT,
};
// from id to name 3 params id, name, len
static cell AMX_NATIVE_CALL get_weapon_name(AMX *amx, cell *params)
{
int id = params[1];
if (id<0 || id>=DODMAX_WEAPONS){
if(id < 0 || id >= DODMAX_WEAPONS)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid weapon id %d", id);
return 0;
}
return MF_SetAmxString(amx,params[2],weaponData[id].name,params[3]);
}
static cell AMX_NATIVE_CALL wpnlog_to_name(AMX *amx, cell *params){ // from log to name
// from log to name
static cell AMX_NATIVE_CALL wpnlog_to_name(AMX *amx, cell *params)
{
int iLen;
char *log = MF_GetAmxString(amx,params[1],0,&iLen);
int i;
for ( i=0; i<DODMAX_WEAPONS; i++ ){
if ( strcmp(log,weaponData[i].logname ) == 0 )
for(int i = 0; i < DODMAX_WEAPONS; i++)
{
if(strcmp(log,weaponData[i].logname ) == 0)
return MF_SetAmxString(amx,params[2],weaponData[i].name,params[3]);
}
return 0;
}
static cell AMX_NATIVE_CALL wpnlog_to_id(AMX *amx, cell *params){ // from log to id
// from log to id
static cell AMX_NATIVE_CALL wpnlog_to_id(AMX *amx, cell *params)
{
int iLen;
char *log = MF_GetAmxString(amx,params[1],0,&iLen);
char *log = MF_GetAmxString(amx, params[1], 0, &iLen);
int i;
for ( i=0; i<DODMAX_WEAPONS; i++ ){
if ( strcmp(log,weaponData[i].logname) == 0 )
for(int i = 0; i < DODMAX_WEAPONS; i++)
{
if(strcmp(log,weaponData[i].logname) == 0)
return i;
}
return 0;
}
static cell AMX_NATIVE_CALL get_weapon_logname(AMX *amx, cell *params){ // from id to log
// from id to log
static cell AMX_NATIVE_CALL get_weapon_logname(AMX *amx, cell *params)
{
int id = params[1];
if (id<0 || id>=DODMAX_WEAPONS){
if (id<0 || id>=DODMAX_WEAPONS)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid weapon id %d", id);
return 0;
}
return MF_SetAmxString(amx,params[2],weaponData[id].logname,params[3]);
}
static cell AMX_NATIVE_CALL is_melee(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL is_melee(AMX *amx, cell *params)
{
int id = params[1];
if (id<0 || id>=DODMAX_WEAPONS){
if(id < 0 || id >= DODMAX_WEAPONS)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid weapon id %d", id);
return 0;
}
return weaponData[id].melee;
}
static cell AMX_NATIVE_CALL get_team_score(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL get_team_score(AMX *amx, cell *params)
{
int index = params[1];
switch ( index ){
switch ( index )
{
case 1:
return AlliesScore;
break;
case 2:
return AxisScore;
break;
@ -95,30 +167,38 @@ static cell AMX_NATIVE_CALL get_team_score(AMX *amx, cell *params){
return 0;
}
static cell AMX_NATIVE_CALL get_user_score(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL get_user_score(AMX *amx, cell *params)
{
int index = params[1];
CHECK_PLAYER(index);
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
if (pPlayer->ingame)
return (cell)pPlayer->savedScore;
return -1;
}
static cell AMX_NATIVE_CALL get_user_class(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL get_user_class(AMX *amx, cell *params)
{
int index = params[1];
CHECK_PLAYER(index);
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
if (pPlayer->ingame)
return pPlayer->pEdict->v.playerclass;
return 0;
}
static cell AMX_NATIVE_CALL user_kill(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL user_kill(AMX *amx, cell *params)
{
int index = params[1];
CHECK_PLAYER(index);
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
if (pPlayer->ingame && pPlayer->IsAlive() ){
if(pPlayer->ingame && pPlayer->IsAlive())
{
pPlayer->killPlayer();
return 1;
}
@ -126,17 +206,22 @@ static cell AMX_NATIVE_CALL user_kill(AMX *amx, cell *params){
return 0;
}
static cell AMX_NATIVE_CALL get_map_info(AMX *amx, cell *params){
switch( params[1] ){
static cell AMX_NATIVE_CALL get_map_info(AMX *amx, cell *params)
{
switch(params[1])
{
case 0:
return g_map.detect_allies_country;
break;
case 1:
return g_map.detect_allies_paras;
break;
case 2:
return g_map.detect_axis_paras;
break;
default:
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid map info id %d", params[1]);
break;
@ -144,21 +229,26 @@ static cell AMX_NATIVE_CALL get_map_info(AMX *amx, cell *params){
return -1;
}
static cell AMX_NATIVE_CALL get_user_pronestate(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL get_user_pronestate(AMX *amx, cell *params)
{
int index = params[1];
CHECK_PLAYER(index);
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
if (pPlayer->ingame)
return pPlayer->pEdict->v.iuser3;
return 0;
}
static cell AMX_NATIVE_CALL get_user_weapon(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL get_user_weapon(AMX *amx, cell *params)
{
int index = params[1];
CHECK_PLAYER(index);
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
if (pPlayer->ingame){
if (pPlayer->ingame)
{
int wpn = pPlayer->current;
cell *cpTemp = MF_GetAmxAddr(amx,params[2]);
*cpTemp = pPlayer->weapons[wpn].clip;
@ -170,55 +260,100 @@ static cell AMX_NATIVE_CALL get_user_weapon(AMX *amx, cell *params){
return 0;
}
static cell AMX_NATIVE_CALL register_forward(AMX *amx, cell *params)
{ // forward
/* We want to get just the weapon of whichever type that the player is on him */
static cell AMX_NATIVE_CALL dod_weapon_type(AMX *amx, cell *params) /* 2 params */
{
int index = params[1];
int type = params[2];
#ifdef FORWARD_OLD_SYSTEM
CHECK_PLAYER(index);
int iFunctionIndex;
int err;
switch( params[1] ){
case 0:
if( (err=MF_AmxFindPublic(amx, "client_damage", &iFunctionIndex)) == AMX_ERR_NONE )
g_damage_info.put( amx , iFunctionIndex );
else
MF_LogError(amx, err, "client_damage not found");
return 0;
break;
case 1:
if( (err=MF_AmxFindPublic(amx, "client_death", &iFunctionIndex)) == AMX_ERR_NONE )
g_death_info.put( amx , iFunctionIndex );
else
MF_LogError(amx, err, "client_Death not found");
return 0;
break;
case 2:
if( (err=MF_AmxFindPublic(amx, "client_score", &iFunctionIndex)) == AMX_ERR_NONE )
g_score_info.put( amx , iFunctionIndex );
else
MF_LogError(amx, err, "client_score not found");
return 0;
break;
default:
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid forward id %d", params[2]);
if(type < DODWT_PRIMARY || type > DODWT_OTHER)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid weapon type id %d", type);
return 0;
}
#endif
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
if(pPlayer->ingame)
{
int weaponsbit = pPlayer->pEdict->v.weapons & ~(1<<31); // don't count last element
for(int x = 1; x < MAX_WEAPONS; ++x)
{
if((weaponsbit&(1<<x)) > 0)
{
if(weaponData[x].type == type)
return x;
}
}
}
return 0;
}
// forward
static cell AMX_NATIVE_CALL register_forward(AMX *amx, cell *params)
{
#ifdef FORWARD_OLD_SYSTEM
int iFunctionIndex;
int err;
switch( params[1] )
{
case 0:
if((err = MF_AmxFindPublic(amx, "client_damage", &iFunctionIndex)) == AMX_ERR_NONE)
g_damage_info.put( amx , iFunctionIndex );
else
MF_LogError(amx, err, "client_damage not found");
return 0;
break;
case 1:
if((err = MF_AmxFindPublic(amx, "client_death", &iFunctionIndex)) == AMX_ERR_NONE)
g_death_info.put( amx , iFunctionIndex );
else
MF_LogError(amx, err, "client_Death not found");
return 0;
break;
case 2:
if((err = MF_AmxFindPublic(amx, "client_score", &iFunctionIndex)) == AMX_ERR_NONE)
g_score_info.put( amx , iFunctionIndex );
else
MF_LogError(amx, err, "client_score not found");
return 0;
break;
default:
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid forward id %d", params[2]);
return 0;
}
#endif
return 1;
}
static cell AMX_NATIVE_CALL register_cwpn(AMX *amx, cell *params){ // name,logname,melee=0
// name,logname,melee=0
static cell AMX_NATIVE_CALL register_cwpn(AMX *amx, cell *params)
{
int i;
bool bFree = false;
for ( i=DODMAX_WEAPONS-DODMAX_CUSTOMWPNS;i<DODMAX_WEAPONS;i++){
if ( !weaponData[i].needcheck ){
for(i = DODMAX_WEAPONS - DODMAX_CUSTOMWPNS; i < DODMAX_WEAPONS; i++)
{
if(!weaponData[i].needcheck)
{
bFree = true;
break;
}
}
if ( !bFree )
if(!bFree)
return 0;
int iLen;
@ -232,9 +367,14 @@ static cell AMX_NATIVE_CALL register_cwpn(AMX *amx, cell *params){ // name,logna
return i;
}
static cell AMX_NATIVE_CALL cwpn_dmg(AMX *amx, cell *params){ // wid,att,vic,dmg,hp=0
// wid,att,vic,dmg,hp=0
static cell AMX_NATIVE_CALL cwpn_dmg(AMX *amx, cell *params)
{
int weapon = params[1];
if ( weapon < DODMAX_WEAPONS-DODMAX_CUSTOMWPNS ){ // only for custom weapons
// only for custom weapons
if(weapon < DODMAX_WEAPONS-DODMAX_CUSTOMWPNS)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid custom weapon id %d", weapon);
return 0;
}
@ -246,13 +386,15 @@ static cell AMX_NATIVE_CALL cwpn_dmg(AMX *amx, cell *params){ // wid,att,vic,dmg
CHECK_PLAYER(params[3]);
int dmg = params[4];
if ( dmg<1 ){
if(dmg<1)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid damage %d", dmg);
return 0;
}
int aim = params[5];
if ( aim < 0 || aim > 7 ){
if(aim < 0 || aim > 7)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid aim %d", aim);
return 0;
}
@ -262,33 +404,39 @@ static cell AMX_NATIVE_CALL cwpn_dmg(AMX *amx, cell *params){ // wid,att,vic,dmg
pVic->pEdict->v.dmg_inflictor = NULL;
if ( pAtt->index != pVic->index )
pAtt->saveHit( pVic , weapon , dmg, aim );
if(pAtt->index != pVic->index)
pAtt->saveHit(pVic , weapon , dmg, aim);
if(!pAtt)
pAtt = pVic;
if ( !pAtt ) pAtt = pVic;
int TA = 0;
if ( (pVic->pEdict->v.team == pAtt->pEdict->v.team ) && ( pVic != pAtt) )
if((pVic->pEdict->v.team == pAtt->pEdict->v.team) && (pVic != pAtt))
TA = 1;
MF_ExecuteForward( iFDamage,pAtt->index, pVic->index, dmg, weapon, aim, TA );
MF_ExecuteForward(iFDamage,pAtt->index, pVic->index, dmg, weapon, aim, TA);
if ( pVic->IsAlive() )
if(pVic->IsAlive())
return 1;
pAtt->saveKill(pVic,weapon,( aim == 1 ) ? 1:0 ,TA);
MF_ExecuteForward( iFDeath,pAtt->index, pVic->index, weapon, aim, TA );
MF_ExecuteForward(iFDeath,pAtt->index, pVic->index, weapon, aim, TA);
return 1;
}
static cell AMX_NATIVE_CALL cwpn_shot(AMX *amx, cell *params){ // player,wid
// player,wid
static cell AMX_NATIVE_CALL cwpn_shot(AMX *amx, cell *params)
{
int index = params[2];
CHECK_PLAYER(index);
int weapon = params[1];
if ( weapon < DODMAX_WEAPONS-DODMAX_CUSTOMWPNS ){
if(weapon < DODMAX_WEAPONS-DODMAX_CUSTOMWPNS)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid custom weapon id %d", weapon);
return 0;
}
@ -299,23 +447,30 @@ static cell AMX_NATIVE_CALL cwpn_shot(AMX *amx, cell *params){ // player,wid
return 1;
}
static cell AMX_NATIVE_CALL get_maxweapons(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL get_maxweapons(AMX *amx, cell *params)
{
return DODMAX_WEAPONS;
}
static cell AMX_NATIVE_CALL get_stats_size(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL get_stats_size(AMX *amx, cell *params)
{
return 9;
}
static cell AMX_NATIVE_CALL is_custom(AMX *amx, cell *params){
static cell AMX_NATIVE_CALL is_custom(AMX *amx, cell *params)
{
int weapon = params[1];
if ( weapon < DODMAX_WEAPONS-DODMAX_CUSTOMWPNS ){
if(weapon < DODMAX_WEAPONS-DODMAX_CUSTOMWPNS)
{
return 0;
}
return 1;
}
static cell AMX_NATIVE_CALL dod_get_user_team(AMX *amx, cell *params){ // player,wid
// player,wid
static cell AMX_NATIVE_CALL dod_get_user_team(AMX *amx, cell *params)
{
int index = params[1];
CHECK_PLAYER(index);
@ -324,22 +479,29 @@ static cell AMX_NATIVE_CALL dod_get_user_team(AMX *amx, cell *params){ // player
}
static cell AMX_NATIVE_CALL get_user_team(AMX *amx, cell *params){ // player,wid
// player,wid
static cell AMX_NATIVE_CALL get_user_team(AMX *amx, cell *params)
{
int index = params[1];
CHECK_PLAYER(index);
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
int iTeam = pPlayer->pEdict->v.team;
if ( params[3] ){
if ( params[3] )
{
char *szTeam = "";
switch(iTeam){
switch(iTeam)
{
case 1:
szTeam = "Allies";
break;
case 2:
szTeam = "Axis";
break;
}
MF_SetAmxString(amx,params[2],szTeam,params[3]);
}
return iTeam;
@ -352,7 +514,10 @@ static cell AMX_NATIVE_CALL dod_set_model(AMX *amx, cell *params) // player,mode
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
if(!pPlayer->ingame)
return false;
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid Player, Not on Server");
return 0;
}
int length;
pPlayer->initModel((char*)STRING(ALLOC_STRING(MF_GetAmxString(amx, params[2], 1, &length))));
@ -367,7 +532,10 @@ static cell AMX_NATIVE_CALL dod_set_body(AMX *amx, cell *params) // player,bodyn
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
if(!pPlayer->ingame)
return false;
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid Player, Not on Server");
return 0;
}
pPlayer->setBody(params[2]);
@ -388,8 +556,70 @@ static cell AMX_NATIVE_CALL dod_clear_model(AMX *amx, cell *params) // player
return true;
}
AMX_NATIVE_INFO base_Natives[] = {
/*
0 [Byte] 1 // Weapons Groupings
1 [Byte] 210 // Total Rounds Allowed
2 [Byte] -1 // Undefined Not Used
3 [Byte] -1 // Undefined Not Used
4 [Byte] 2 // Weapon Slot
5 [Byte] 0 // Bucket ( Position Under Weapon Slot )
6 [Short] 7 // Weapon Number / Bit Field for the weapon
7 [Byte] 128 // Bit Field for the Ammo or Ammo Type
8 [Byte] 30 // Rounds Per Mag
id, wpnID, slot, position, totalrds
*/
static cell AMX_NATIVE_CALL dod_weaponlist(AMX *amx, cell *params) // player
{
if(!weaponlist[params[1]].changeable)
{
MF_LogError(amx, AMX_ERR_NATIVE, "This Weapon Cannot be Changed");
return 0;
}
int id = params[1];
int wpnID = params[2];
int slot = params[3];
int position = params[4];
int totalrds = params[5];
UTIL_LogPrintf("ID (%d) WpnID (%d) Slot (%d) Pos (%d) Rounds (%d)", id, wpnID, slot, position, totalrds);
CHECK_PLAYER(id);
CPlayer* pPlayer = GET_PLAYER_POINTER_I(id);
if(!pPlayer->ingame)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid Player, Not on Server");
return 0;
}
MESSAGE_BEGIN(MSG_ONE, GET_USER_MSG_ID(PLID, "WeaponList", NULL), NULL, INDEXENT(id));
WRITE_BYTE(weaponlist[wpnID].grp);
WRITE_BYTE(totalrds);
WRITE_BYTE(-1);
WRITE_BYTE(-1);
WRITE_BYTE(slot - 1);
WRITE_BYTE(position);
WRITE_SHORT(wpnID);
WRITE_BYTE(weaponlist[wpnID].bitfield);
// Is it grenades
if(wpnID == 13 || wpnID == 14 || wpnID == 15 || wpnID == 16 || wpnID == 36)
WRITE_BYTE(-1);
else if(wpnID == 29 || wpnID == 30 || wpnID == 31)
WRITE_BYTE(1);
else
WRITE_BYTE(weaponlist[wpnID].clip);
MESSAGE_END();
return 1;
}
AMX_NATIVE_INFO base_Natives[] =
{
{ "dod_wpnlog_to_name", wpnlog_to_name },
{ "dod_wpnlog_to_id", wpnlog_to_id },
@ -398,6 +628,8 @@ AMX_NATIVE_INFO base_Natives[] = {
{ "dod_get_user_class", get_user_class },
{ "dod_get_user_weapon", get_user_weapon },
{ "dod_weapon_type", dod_weapon_type },
{ "dod_get_map_info", get_map_info },
{ "dod_user_kill", user_kill },
{ "dod_get_pronestate", get_user_pronestate },
@ -426,10 +658,10 @@ AMX_NATIVE_INFO base_Natives[] = {
{ "dod_get_wpnlogname", get_weapon_logname },
{ "dod_is_melee", is_melee },
// Zors
{"dod_set_model", dod_set_model},
{"dod_set_body_number", dod_set_body},
{"dod_clear_model", dod_clear_model},
{"dod_set_weaponlist", dod_weaponlist},
///*******************
{ NULL, NULL }

View File

@ -33,113 +33,140 @@
#include "dodx.h"
/* Weapon names aren't send in WeaponList message in DoD */
weapon_t weaponData[] = {
{ false,false,"mortar","mortar",0 },
{ true,true,"amerknife","knife",0 }, // aknife->bknife
{ false,true,"gerknife","knife",0 },
{ false,false,"colt","Colt",4 },
{ false,false,"luger","Luger",4 },
{ true,false,"garand","Garand",3 }, // Garand->Garand butt
{ false,false,"scopedkar","scoped K98",3 },
{ false,false,"thompson","Thompson",1 },
{ false,false,"mp44","STG44",6 },
{ false,false,"spring","Springfield",5 },
{ true,false,"kar","K98",3 }, // KAR->KAR bayonet
{ false,false,"bar","BAR",6 },
{ false,false,"mp40","MP40",1 },
{ false,false,"grenade","handgrenade",9 },
{ false,false,"grenade2","stickgrenade",11 },
{ false,false,"stickgrenade_ex","stickgrenade_ex",11 },
{ false,false,"handgrenade_ex","handgrenade_ex",9 },
{ false,false,"mg42","MG42",7 },
{ false,false,"30cal",".30 cal",8 },
{ false,true,"spade","spade",0 },
{ true,false,"m1carbine","M1 Carbine",2 }, // M1 Carbine->Folding Carbine
{ false,false,"mg34","MG34",2 },
{ false,false,"greasegun","Greasegun",1 },
{ true,false,"fg42","FG42",6 }, // FG42 -> scoped FG42
{ true,false,"k43","K43",2 },
{ true,false,"enfield","Enfield",3 }, // Enfield->Scoped Enfield->Enfield bayonet
{ false,false,"sten","Sten",1 },
{ false,false,"bren","Bren",6 },
{ false,false,"webley","Webley",4 },
{ false,false,"bazooka","Bazooka",13 },
{ false,false,"pschreck","Panzerschrek",13 },
{ false,false,"piat","Piat",13 },
{ false,false,"scoped_fg42","scoped FG42",6 },
{ false,false,"fcarbine","Folding Carbine" },
{ false,true,"bayonet","K98 bayonet",0 }, // KAR bayonet
{ false,false,"scoped_enfield","scoped Enfield",3 },
{ false,false,"mills_bomb","mills bomb",9 },
{ false,true,"brit_knife","knife",0 },
{ false,true,"garandbutt","Garand butt",0 }, // Garand butt
{ false,true,"enf_bayonet","Enfield bayonet",0 },
{ false,false,"mortar","mortar",0 }, // mortar new id
{ false,true,"k43butt","K43 butt",0 },
weapon_t weaponData[] =
{
{ false, false, "mortar", "mortar", 0, DODWT_OTHER },
{ true, true, "amerknife", "knife", 0, DODWT_MELEE }, // aknife->bknife
{ false, true, "gerknife", "knife", 0, DODWT_MELEE },
{ false, false, "colt", "Colt", 4, DODWT_SECONDARY },
{ false, false, "luger", "Luger", 4, DODWT_SECONDARY },
{ true, false, "garand", "Garand", 3, DODWT_PRIMARY }, // Garand->Garand butt
{ false, false, "scopedkar", "scoped K98", 3, DODWT_PRIMARY },
{ false, false, "thompson", "Thompson", 1, DODWT_PRIMARY },
{ false, false, "mp44", "STG44", 6, DODWT_PRIMARY },
{ false, false, "spring", "Springfield", 5, DODWT_PRIMARY },
{ true, false, "kar", "K98", 3, DODWT_PRIMARY }, // KAR->KAR bayonet
{ false, false, "bar", "BAR", 6, DODWT_PRIMARY },
{ false, false, "mp40", "MP40", 1, DODWT_PRIMARY },
{ false, false, "grenade", "handgrenade", 9, DODWT_GRENADE },
{ false, false, "grenade2", "stickgrenade", 11, DODWT_GRENADE },
{ false, false, "stickgrenade_ex", "stickgrenade_ex", 11, DODWT_GRENADE },
{ false, false, "handgrenade_ex", "handgrenade_ex", 9, DODWT_GRENADE },
{ false, false, "mg42", "MG42", 7, DODWT_PRIMARY },
{ false, false, "30cal", ".30 cal", 8, DODWT_PRIMARY },
{ false, true, "spade", "spade", 0, DODWT_MELEE },
{ true, false, "m1carbine", "M1 Carbine", 2, DODWT_PRIMARY }, // M1 Carbine->Folding Carbine
{ false, false, "mg34", "MG34", 2, DODWT_PRIMARY },
{ false, false, "greasegun", "Greasegun", 1, DODWT_PRIMARY },
{ true, false, "fg42", "FG42", 6, DODWT_PRIMARY }, // FG42 -> scoped FG42
{ true, false, "k43", "K43", 2, DODWT_PRIMARY },
{ true, false, "enfield", "Enfield", 3, DODWT_PRIMARY }, // Enfield->Scoped Enfield->Enfield bayonet
{ false, false, "sten", "Sten", 1, DODWT_PRIMARY },
{ false, false, "bren", "Bren", 6, DODWT_PRIMARY },
{ false, false, "webley", "Webley", 4, DODWT_PRIMARY },
{ false, false, "bazooka", "Bazooka", 13, DODWT_PRIMARY },
{ false, false, "pschreck", "Panzerschrek", 13, DODWT_PRIMARY },
{ false, false, "piat", "Piat", 13, DODWT_PRIMARY },
{ false, false, "scoped_fg42", "scoped FG42", 6, DODWT_PRIMARY },
{ false, false, "fcarbine", "Folding Carbine", 0, DODWT_PRIMARY },
{ false, true, "bayonet", "K98 bayonet", 0, DODWT_MELEE }, // KAR bayonet
{ false, false, "scoped_enfield", "scoped Enfield", 3, DODWT_PRIMARY },
{ false, false, "mills_bomb", "mills bomb", 9, DODWT_GRENADE },
{ false, true, "brit_knife", "knife", 0, DODWT_MELEE },
{ false, true, "garandbutt", "Garand butt", 0, DODWT_MELEE }, // Garand butt
{ false, true, "enf_bayonet", "Enfield bayonet", 0, DODWT_MELEE },
{ false, false, "mortar", "mortar", 0, DODWT_OTHER }, // mortar new id
{ false, true, "k43butt", "K43 butt", 0, DODWT_MELEE },
};
/* Function will select correct id */
int get_weaponid(CPlayer* pPlayer){
int get_weaponid(CPlayer* pPlayer)
{
int weapon = pPlayer->current;
const char *sz;
switch(weapon) {
case 1: if ( g_map.detect_allies_country ) weapon = 37; break;
case 5: if ( pPlayer->pEdict->v.button&IN_ATTACK2 ) weapon = 38; break;
case 10: if ( pPlayer->pEdict->v.button&IN_ATTACK2 ) weapon = 34; break;
case 20:
if ( g_map.detect_allies_paras ) weapon = 33;
switch(weapon)
{
case 1:
if(g_map.detect_allies_country) weapon = 37;
break;
case 5:
if(pPlayer->pEdict->v.button&IN_ATTACK2) weapon = 38;
break;
case 10:
if(pPlayer->pEdict->v.button&IN_ATTACK2) weapon = 34;
break;
case 20:
if(g_map.detect_allies_paras) weapon = 33;
break;
case 23:
sz = STRING(pPlayer->pEdict->v.weaponmodel);
if ( sz[13] == 's' )
if(sz[13] == 's')
weapon = 32;
break;
case 24: if ( pPlayer->pEdict->v.button&IN_ATTACK2 ) weapon = 41; break;
case 24:
if(pPlayer->pEdict->v.button&IN_ATTACK2) weapon = 41;
break;
case 25:
sz = STRING(pPlayer->pEdict->v.weaponmodel);
if ( sz[16] == 's' )
if(sz[16] == 's')
weapon = 35;
else if ( pPlayer->pEdict->v.button&IN_ATTACK2 )
else if(pPlayer->pEdict->v.button&IN_ATTACK2)
weapon = 39;
break;
case 15:
weapon = 14;
break;
case 16:
if ( g_map.detect_allies_country ) weapon = 36;
if(g_map.detect_allies_country) weapon = 36;
else weapon = 13;
break;
}
return weapon;
}
traceVault traceData[] = {
traceVault traceData[] =
{
{ "grenade", 13, ACT_NADE_PUT|ACT_NADE_SHOT, 2.0 }, // or 36
{ "grenade2", 14, ACT_NADE_PUT|ACT_NADE_SHOT, 2.0 },
{ "shell_bazooka", 29, ACT_NADE_PUT, 2.0 },
{ "shell_pschreck", 30, ACT_NADE_PUT, 2.0 },
{ "shell_piat", 31, ACT_NADE_PUT, 2.0 },
{ "shell_bazooka", 29, ACT_ROCKET_PUT|ACT_ROCKET_SHOT, 2.0 },
{ "shell_pschreck", 30, ACT_ROCKET_PUT|ACT_ROCKET_SHOT, 2.0 },
{ "shell_piat", 31, ACT_ROCKET_PUT|ACT_ROCKET_SHOT, 2.0 },
{ "monster_mortar", 40, ACT_NADE_PUT|ACT_NADE_SHOT, 2.0 },
};
bool ignoreBots (edict_t *pEnt, edict_t *pOther){
if ( !rankBots && ( pEnt->v.flags & FL_FAKECLIENT || ( pOther && pOther->v.flags & FL_FAKECLIENT ) ) )
bool ignoreBots (edict_t *pEnt, edict_t *pOther)
{
if(!rankBots && (pEnt->v.flags & FL_FAKECLIENT || (pOther && pOther->v.flags & FL_FAKECLIENT)))
return true;
return false;
}
bool isModuleActive(){
if ( !(int)CVAR_GET_FLOAT("dodstats_pause") )
bool isModuleActive()
{
if(!(int)CVAR_GET_FLOAT("dodstats_pause"))
return true;
return false;
}
edict_t *FindEntityByString(edict_t *pentStart, const char *szKeyword, const char *szValue)
{
edict_t *pentEntity;
pentEntity=FIND_ENTITY_BY_STRING(pentStart, szKeyword, szValue);
pentEntity = FIND_ENTITY_BY_STRING(pentStart, szKeyword, szValue);
if(!FNullEnt(pentEntity))
return pentEntity;
return NULL;
}
@ -147,3 +174,13 @@ edict_t *FindEntityByClassname(edict_t *pentStart, const char *szName)
{
return FindEntityByString(pentStart, "classname", szName);
}
edict_t *FindEntityInSphere(edict_t *pentStart, edict_t *origin, float radius)
{
edict_t* temp = FIND_ENTITY_IN_SPHERE(pentStart, origin->v.origin, radius);
if(!temp)
return NULL;
return temp;
}

View File

@ -47,30 +47,64 @@ extern AMX_NATIVE_INFO stats_Natives[];
extern AMX_NATIVE_INFO base_Natives[];
extern AMX_NATIVE_INFO pd_Natives[];
struct weapon_t {
// Weapons grabbing by type
enum
{
DODWT_PRIMARY = 0,
DODWT_SECONDARY,
DODWT_MELEE,
DODWT_GRENADE,
DODWT_OTHER
};
// Model Sequences
enum
{
DOD_SEQ_PRONE_IDLE = 15,
DOD_SEQ_PRONE_FORWARD,
DOD_SEQ_PRONE_DOWN,
DOD_SEQ_PRONE_UP
};
// Weapons Structure
struct weapon_t
{
bool needcheck;
bool melee;
char logname[16];
char name[32];
char hashname[32];
int ammoSlot;
int type;
};
struct weaponlist_s
{
int grp;
int bitfield;
int clip;
bool changeable;
};
extern bool rankBots;
extern int mState;
extern int mDest;
extern int mCurWpnEnd;
extern int mPlayerIndex;
void Client_CurWeapon(void*);
void Client_CurWeapon_End(void*);
void Client_Health_End(void*);
void Client_ResetHUD_End(void*);
void Client_ObjScore(void*);
void Client_TeamScore(void*);
void Client_RoundState(void*);
void Client_AmmoX(void*);
void Client_AmmoShort(void*);
void Client_Health_End(void*);
// Zors
//void WeaponList(void*);
//void WeaponList_End(void*);
void Client_SetFOV(void*);
void Client_SetFOV_End(void*);
void Client_Object(void*);
void Client_Object_End(void*);
typedef void (*funEventCall)(void*);
@ -78,6 +112,8 @@ extern int AlliesScore;
extern int AxisScore;
extern int gmsgCurWeapon;
extern int gmsgCurWeaponEnd;
extern int gmsgHealth;
extern int gmsgResetHUD;
extern int gmsgObjScore;
extern int gmsgRoundState;
@ -86,7 +122,10 @@ extern int gmsgScoreShort;
extern int gmsgPTeam;
extern int gmsgAmmoX;
extern int gmsgAmmoShort;
extern int gmsgHealth_End;
extern int gmsgSetFOV;
extern int gmsgSetFOV_End;
extern int gmsgObject;
extern int gmsgObject_End;
extern int iFDamage;
extern int iFDeath;
@ -94,6 +133,14 @@ extern int iFScore;
extern int iFSpawnForward;
extern int iFTeamForward;
extern int iFClassForward;
extern int iFScopeForward;
extern int iFProneForward;
extern int iFWpnPickupForward;
extern int iFCurWpnForward;
extern int iFGrenadeExplode;
extern int iFRocketExplode;
extern int iFObjectTouched;
extern int iFStaminaForward;
extern cvar_t* dodstats_maxsize;
extern cvar_t* dodstats_rank;
@ -113,7 +160,9 @@ extern CMapInfo g_map;
int get_weaponid(CPlayer* player);
bool ignoreBots (edict_t *pEnt, edict_t *pOther = NULL );
bool isModuleActive();
edict_t *FindEntityByString(edict_t *pentStart, const char *szKeyword, const char *szValue);
edict_t *FindEntityByClassname(edict_t *pentStart, const char *szName);
edict_t *FindEntityInSphere(edict_t *pentStart, edict_t *origin, float radius);
#define CHECK_ENTITY(x) \
if (x < 0 || x > gpGlobals->maxEntities) { \

View File

@ -42,6 +42,8 @@ CMapInfo g_map;
bool rankBots;
int mState;
int mDest;
int mCurWpnEnd;
int mPlayerIndex;
int AlliesScore;
@ -50,13 +52,21 @@ int AxisScore;
int iFDamage = -1;
int iFDeath = -1;
int iFScore = -1;
// Zors
int iFSpawnForward = -1;
int iFTeamForward = -1;
int iFClassForward = -1;
int iFScopeForward = -1;
int iFProneForward = -1;
int iFWpnPickupForward = -1;
int iFCurWpnForward = -1;
int iFGrenadeExplode = -1;
int iFRocketExplode = -1;
int iFObjectTouched = -1;
int iFStaminaForward = -1;
int gmsgCurWeapon;
int gmsgCurWeaponEnd;
int gmsgHealth;
int gmsgResetHUD;
int gmsgObjScore;
int gmsgRoundState;
@ -65,11 +75,10 @@ int gmsgScoreShort;
int gmsgPTeam;
int gmsgAmmoX;
int gmsgAmmoShort;
int gmsgHealth_End;
// Zors
//int gmsgWeaponList;
//int gmsgWeaponList_End;
int gmsgSetFOV;
int gmsgSetFOV_End;
int gmsgObject;
int gmsgObject_End;
RankSystem g_rank;
Grenades g_grenades;
@ -85,29 +94,31 @@ cvar_t *dodstats_rank;
cvar_t *dodstats_rankbots;
cvar_t *dodstats_pause;
struct sUserMsg {
// User Messages
struct sUserMsg
{
const char *name;
int* id;
funEventCall func;
bool endmsg;
} g_user_msg[] =
}
g_user_msg[] =
{
{ "CurWeapon", &gmsgCurWeapon, Client_CurWeapon, false },
{ "ObjScore", &gmsgObjScore, Client_ObjScore, false },
{ "RoundState", &gmsgRoundState, Client_RoundState, false },
{ "ResetHUD", &gmsgResetHUD, Client_ResetHUD_End, true },
{ "TeamScore", &gmsgTeamScore, Client_TeamScore, false },
{ "AmmoX", &gmsgAmmoX, Client_AmmoX, false },
{ "AmmoShort", &gmsgAmmoShort, Client_AmmoShort, false },
{ "Health", &gmsgHealth_End, Client_Health_End, true },
//Zors
//{ "WeaponList", &gmsgWeaponList, WeaponList, true },
//{ "WeaponList", &gmsgWeaponList_End, WeaponList_End, true },
{ "PTeam", &gmsgPTeam, NULL, false },
{ "ScoreShort", &gmsgScoreShort, NULL, false },
{ "CurWeapon", &gmsgCurWeapon, Client_CurWeapon, false },
{ "CurWeapon", &gmsgCurWeaponEnd, Client_CurWeapon_End, true },
{ "ObjScore", &gmsgObjScore, Client_ObjScore, false },
{ "RoundState", &gmsgRoundState, Client_RoundState, false },
{ "Health", &gmsgHealth, Client_Health_End, true },
{ "ResetHUD", &gmsgResetHUD, Client_ResetHUD_End, true },
{ "TeamScore", &gmsgTeamScore, Client_TeamScore, false },
{ "AmmoX", &gmsgAmmoX, Client_AmmoX, false },
{ "AmmoShort", &gmsgAmmoShort, Client_AmmoShort, false },
{ "SetFOV", &gmsgSetFOV, Client_SetFOV, false },
{ "SetFOV", &gmsgSetFOV_End, Client_SetFOV_End, true },
{ "Object", &gmsgObject, Client_Object, false },
{ "Object", &gmsgObject_End, Client_Object_End, true },
{ "ScoreShort", &gmsgScoreShort, NULL, false },
{ "PTeam", &gmsgPTeam, NULL, false },
{ 0,0,0,false }
};
@ -119,18 +130,20 @@ const char* get_localinfo( const char* name , const char* def = 0 )
return b;
}
int RegUserMsg_Post(const char *pszName, int iSize){
for (int i = 0; g_user_msg[ i ].name; ++i ){
if ( !*g_user_msg[i].id && strcmp( g_user_msg[ i ].name , pszName ) == 0 ){
int id = META_RESULT_ORIG_RET( int );
int RegUserMsg_Post(const char *pszName, int iSize)
{
for (int i = 0; g_user_msg[i].name; ++i )
{
if(!*g_user_msg[i].id && strcmp(g_user_msg[i].name, pszName) == 0)
{
int id = META_RESULT_ORIG_RET(int);
*g_user_msg[ i ].id = id;
*g_user_msg[i].id = id;
if ( g_user_msg[ i ].endmsg )
modMsgsEnd[ id ] = g_user_msg[ i ].func;
if(g_user_msg[i].endmsg)
modMsgsEnd[id] = g_user_msg[i].func;
else
modMsgs[ id ] = g_user_msg[ i ].func;
modMsgs[id] = g_user_msg[i].func;
break;
}
}
@ -149,47 +162,55 @@ void ServerActivate_Post( edict_t *pEdictList, int edictCount, int clientMax ){
RETURN_META(MRES_IGNORED);
}
void PlayerPreThink_Post( edict_t *pEntity ) {
void PlayerPreThink_Post(edict_t *pEntity)
{
if ( !isModuleActive() )
RETURN_META(MRES_IGNORED);
CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity);
if ( !pPlayer->ingame )
if (!pPlayer->ingame)
RETURN_META(MRES_IGNORED);
// Zors
pPlayer->checkStatus();
pPlayer->PreThink();
if (pPlayer->clearStats && pPlayer->clearStats < gpGlobals->time){
if ( !ignoreBots(pEntity) ){
if(pPlayer->clearStats && pPlayer->clearStats < gpGlobals->time)
{
if(!ignoreBots(pEntity))
{
pPlayer->clearStats = 0.0f;
pPlayer->rank->updatePosition( &pPlayer->life );
pPlayer->restartStats(false);
}
}
if (pPlayer->clearRound && pPlayer->clearRound < gpGlobals->time){
if(pPlayer->clearRound && pPlayer->clearRound < gpGlobals->time)
{
pPlayer->clearRound = 0.0f;
memset(&pPlayer->round,0,sizeof(pPlayer->round));
memset(pPlayer->weaponsRnd,0,sizeof(pPlayer->weaponsRnd));
}
if (pPlayer->sendScore && pPlayer->sendScore < gpGlobals->time){
if (pPlayer->sendScore && pPlayer->sendScore < gpGlobals->time)
{
pPlayer->sendScore = 0;
MF_ExecuteForward( iFScore,pPlayer->index, pPlayer->lastScore, pPlayer->savedScore );
MF_ExecuteForward(iFScore, pPlayer->index, pPlayer->lastScore, pPlayer->savedScore);
}
RETURN_META(MRES_IGNORED);
}
void ServerDeactivate() {
void ServerDeactivate()
{
int i;
for( i = 1;i<=gpGlobals->maxClients; ++i){
for( i = 1;i<=gpGlobals->maxClients; ++i)
{
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
if (pPlayer->ingame) pPlayer->Disconnect();
}
if ( (g_rank.getRankNum() >= (int)dodstats_maxsize->value) || ((int)dodstats_reset->value == 1) ) {
if ( (g_rank.getRankNum() >= (int)dodstats_maxsize->value) || ((int)dodstats_reset->value == 1) )
{
CVAR_SET_FLOAT("dodstats_reset",0.0);
g_rank.clear();
}
@ -205,13 +226,15 @@ void ServerDeactivate() {
RETURN_META(MRES_IGNORED);
}
BOOL ClientConnect_Post( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ){
BOOL ClientConnect_Post( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] )
{
GET_PLAYER_POINTER(pEntity)->Connect(pszName,pszAddress);
RETURN_META_VALUE(MRES_IGNORED, TRUE);
}
void ClientDisconnect( edict_t *pEntity ) {
void ClientDisconnect( edict_t *pEntity )
{
CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity);
if (pPlayer->ingame)
@ -220,27 +243,33 @@ void ClientDisconnect( edict_t *pEntity ) {
RETURN_META(MRES_IGNORED);
}
void ClientPutInServer_Post( edict_t *pEntity ) {
void ClientPutInServer_Post( edict_t *pEntity )
{
GET_PLAYER_POINTER(pEntity)->PutInServer();
RETURN_META(MRES_IGNORED);
}
void ClientUserInfoChanged_Post( edict_t *pEntity, char *infobuffer ) {
void ClientUserInfoChanged_Post( edict_t *pEntity, char *infobuffer )
{
CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity);
const char* name = INFOKEY_VALUE(infobuffer,"name");
const char* oldname = STRING(pEntity->v.netname);
if ( pPlayer->ingame){
if ( strcmp(oldname,name) ) {
if ( pPlayer->ingame)
{
if ( strcmp(oldname,name) )
{
if (!dodstats_rank->value)
pPlayer->rank = g_rank.findEntryInRank( name, name );
else
pPlayer->rank->setName( name );
}
}
else if ( pPlayer->IsBot() ) {
else if ( pPlayer->IsBot() )
{
pPlayer->Connect( name , "127.0.0.1" );
pPlayer->PutInServer();
}
@ -248,17 +277,26 @@ void ClientUserInfoChanged_Post( edict_t *pEntity, char *infobuffer ) {
RETURN_META(MRES_IGNORED);
}
void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) {
if (ed){
void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed)
{
if(ed)
{
mPlayerIndex = ENTINDEX(ed);
mPlayer = GET_PLAYER_POINTER_I(mPlayerIndex);
} else {
}
else
{
mPlayerIndex = 0;
mPlayer = NULL;
}
mDest = msg_dest;
mState = 0;
if ( msg_type < 0 || msg_type >= MAX_REG_MSGS )
msg_type = 0;
function=modMsgs[msg_type];
endfunction=modMsgsEnd[msg_type];
RETURN_META(MRES_IGNORED);
@ -309,26 +347,48 @@ void WriteEntity_Post(int iValue) {
RETURN_META(MRES_IGNORED);
}
void TraceLine_Post(const float *v1, const float *v2, int fNoMonsters, edict_t *e, TraceResult *ptr) {
if (ptr->pHit&&(ptr->pHit->v.flags& (FL_CLIENT | FL_FAKECLIENT) )&&
e && (e->v.flags&(FL_CLIENT | FL_FAKECLIENT) )){
void TraceLine_Post(const float *v1, const float *v2, int fNoMonsters, edict_t *e, TraceResult *ptr)
{
if(ptr->pHit && (ptr->pHit->v.flags&(FL_CLIENT | FL_FAKECLIENT)) && e && (e->v.flags&(FL_CLIENT | FL_FAKECLIENT)))
{
GET_PLAYER_POINTER(e)->aiming = ptr->iHitgroup;
RETURN_META(MRES_IGNORED);
}
if ( e && e->v.owner && e->v.owner->v.flags& (FL_CLIENT | FL_FAKECLIENT) ){
if(e && e->v.owner && e->v.owner->v.flags&(FL_CLIENT | FL_FAKECLIENT))
{
CPlayer *pPlayer = GET_PLAYER_POINTER(e->v.owner);
for ( int i=0;i<MAX_TRACE;i++){
if ( strcmp( traceData[i].szName,STRING(e->v.classname)) == 0 ){
if ( traceData[i].iAction & ACT_NADE_SHOT ){
if ( traceData[i].iId == 13 && g_map.detect_allies_country )
pPlayer->saveShot(36);
for(int i = 0;i < MAX_TRACE; i++)
{
if(strcmp(traceData[i].szName, STRING(e->v.classname)) == 0)
{
int grenId = (traceData[i].iId == 13 && g_map.detect_allies_country) ? 36 : traceData[i].iId;
int rocketId = traceData[i].iId;
if(traceData[i].iAction&ACT_NADE_SHOT)
{
if(traceData[i].iId == 13 && g_map.detect_allies_country)
pPlayer->saveShot(grenId);
else
pPlayer->saveShot(traceData[i].iId);
}
if ( traceData[i].iAction & ACT_NADE_PUT ){
g_grenades.put(e,traceData[i].fDel, (traceData[i].iId == 13 && g_map.detect_allies_country )?36:traceData[i].iId ,GET_PLAYER_POINTER(e->v.owner));
else if(traceData[i].iAction&ACT_ROCKET_SHOT)
pPlayer->saveShot(traceData[i].iId);
cell position[3] = {v2[0], v2[1], v2[2]};
cell pos = MF_PrepareCellArray(position, 3);
if(traceData[i].iAction&ACT_NADE_PUT)
{
g_grenades.put(e, traceData[i].fDel, grenId, GET_PLAYER_POINTER(e->v.owner));
MF_ExecuteForward(iFGrenadeExplode, GET_PLAYER_POINTER(e->v.owner)->index, pos, grenId);
}
if(traceData[i].iAction&ACT_ROCKET_PUT)
MF_ExecuteForward(iFRocketExplode, pPlayer->index, pos, rocketId);
break;
}
}
@ -338,7 +398,6 @@ void TraceLine_Post(const float *v1, const float *v2, int fNoMonsters, edict_t *
void DispatchKeyValue_Post( edict_t *pentKeyvalue, KeyValueData *pkvd )
{
if ( !pkvd->szClassName ){
// info_doddetect
if ( pkvd->szValue[0]=='i' && pkvd->szValue[5]=='d' ){
@ -392,6 +451,7 @@ void SetClientKeyValue(int id, char *protocol, char *type, char *var)
RETURN_META(MRES_IGNORED);
}
void OnMetaAttach()
{
CVAR_REGISTER (&init_dodstats_maxsize);
@ -408,7 +468,6 @@ void OnMetaAttach()
void OnAmxxAttach()
{
MF_AddNatives( stats_Natives );
MF_AddNatives( base_Natives );
@ -444,5 +503,12 @@ void OnPluginsLoaded()
iFTeamForward = MF_RegisterForward("dod_client_changeteam",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*team*/,FP_CELL/*oldteam*/,FP_DONE);
iFSpawnForward = MF_RegisterForward("dod_client_spawn",ET_IGNORE,FP_CELL/*id*/,FP_DONE);
iFClassForward = MF_RegisterForward("dod_client_changeclass",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*class*/,FP_CELL/*oldclass*/,FP_DONE);
iFScopeForward = MF_RegisterForward("dod_client_scope",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*value*/,FP_DONE);
iFWpnPickupForward = MF_RegisterForward("dod_client_weaponpickup",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*weapon*/,FP_CELL/*value*/,FP_DONE);
iFProneForward = MF_RegisterForward("dod_client_prone",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*value*/,FP_DONE);
iFCurWpnForward = MF_RegisterForward("dod_client_weaponswitch",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*wpnold*/,FP_CELL/*wpnew*/,FP_DONE);
iFGrenadeExplode = MF_RegisterForward("dod_grenade_explosion",ET_IGNORE,FP_CELL/*id*/,FP_ARRAY/*pos[3]*/,FP_CELL/*wpnid*/,FP_DONE);
iFRocketExplode = MF_RegisterForward("dod_rocket_explosion",ET_IGNORE,FP_CELL/*id*/,FP_ARRAY/*pos[3]*/,FP_CELL/*wpnid*/,FP_DONE);
iFObjectTouched = MF_RegisterForward("dod_client_objectpickup",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*object*/,FP_ARRAY/*pos[3]*/,FP_CELL/*value*/,FP_DONE);
iFStaminaForward = MF_RegisterForward("dod_client_stamina",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*stamina*/,FP_DONE);
}

View File

@ -5,7 +5,7 @@
// Module info
#define MODULE_NAME "DoDX"
#define MODULE_VERSION "1.76b"
#define MODULE_VERSION "1.76c_beta_6"
#define MODULE_AUTHOR "AMX Mod X Dev Team"
#define MODULE_URL "http://www.amxmodx.org"
#define MODULE_LOGTAG "DODX"

View File

@ -98,47 +98,129 @@ void Client_ObjScore(void* mValue)
}
}
void Client_CurWeapon(void* mValue)
{
static int iState;
static int iId;
static int iState;
static int iId;
switch (mState++)
{
case 0:
iState = *(int*)mValue;
break;
case 1:
if (!iState) break;
iId = *(int*)mValue;
break;
case 2:
if ( !iState || !isModuleActive() )
break;
int iClip = *(int*)mValue;
mPlayer->current = iId;
if ( weaponData[iId].needcheck )
switch (mState++)
{
iId = get_weaponid(mPlayer);
mPlayer->current = iId;
case 0:
iState = *(int*)mValue;
break;
case 1:
if (!iState)
break;
iId = *(int*)mValue;
break;
case 2:
if(!iState || !isModuleActive())
break;
int iClip = *(int*)mValue;
mPlayer->old = mPlayer->current;
mPlayer->current = iId;
if(weaponData[iId].needcheck)
{
iId = get_weaponid(mPlayer);
mPlayer->current = iId;
}
if(iClip > -1)
{
if(mPlayer->current == 17)
{
if(iClip+2 == mPlayer->weapons[iId].clip)
mPlayer->saveShot(iId);
}
else
{
if ( iClip+1 == mPlayer->weapons[iId].clip)
mPlayer->saveShot(iId);
}
}
mPlayer->weapons[iId].clip = iClip;
mCurWpnEnd = 1;
break;
};
}
void Client_CurWeapon_End(void*)
{
if(mCurWpnEnd == 1 && mPlayer->index && mPlayer->current && mPlayer->old && (mPlayer->current != mPlayer->old))
MF_ExecuteForward(iFCurWpnForward, mPlayer->index, mPlayer->current, mPlayer->old);
mCurWpnEnd = 0;
}
/*
Nie ma damage event ...
*/
void Client_Health_End(void* mValue)
{
if ( !isModuleActive() )
return;
edict_t *enemy = mPlayer->pEdict->v.dmg_inflictor;
int damage = (int)mPlayer->pEdict->v.dmg_take;
if ( !mPlayer || !damage || !enemy )
return;
int weapon = 0;
int aim = 0;
mPlayer->pEdict->v.dmg_take = 0.0;
CPlayer* pAttacker = NULL;
if(enemy->v.flags & (FL_CLIENT | FL_FAKECLIENT))
{
pAttacker = GET_PLAYER_POINTER(enemy);
weapon = pAttacker->current;
if ( weaponData[weapon].needcheck )
weapon = get_weaponid(pAttacker);
aim = pAttacker->aiming;
if ( weaponData[weapon].melee )
pAttacker->saveShot(weapon);
}
else
{
g_grenades.find(enemy , &pAttacker , weapon);
}
if (iClip > -1) {
if ( mPlayer->current == 17 )
{
if ( iClip+2 == mPlayer->weapons[iId].clip)
mPlayer->saveShot(iId);
}
else
{
if ( iClip+1 == mPlayer->weapons[iId].clip)
mPlayer->saveShot(iId);
}
int TA = 0;
if ( !pAttacker )
{
pAttacker = mPlayer;
}
if ( pAttacker->index != mPlayer->index )
{
pAttacker->saveHit( mPlayer , weapon , damage, aim );
if ( mPlayer->pEdict->v.team == pAttacker->pEdict->v.team )
TA = 1;
}
MF_ExecuteForward( iFDamage, pAttacker->index, mPlayer->index, damage, weapon, aim, TA );
if ( !mPlayer->IsAlive() )
{
pAttacker->saveKill(mPlayer,weapon,( aim == 1 ) ? 1:0 ,TA);
MF_ExecuteForward( iFDeath, pAttacker->index, mPlayer->index, weapon, aim, TA );
}
mPlayer->weapons[iId].clip = iClip;
}
}
void Client_AmmoX(void* mValue)
@ -170,135 +252,97 @@ void Client_AmmoShort(void* mValue)
case 0:
iAmmo = *(int*)mValue;
break;
case 1:
if (!mPlayer ) break;
if(!mPlayer )
break;
for(int i = 1; i < MAX_WEAPONS ; ++i)
{
if (iAmmo == weaponData[i].ammoSlot)
mPlayer->weapons[i].ammo = *(int*)mValue;
mPlayer->weapons[i].ammo = *(int*)mValue;
}
}
}
void Client_Health_End(void* mValue)
// Called with a value of 90 at start 20 when someone scopes in and 0 when they scope out
void Client_SetFOV(void* mValue)
{
if ( !isModuleActive() )
if(!mPlayer)
return;
CPlayer* pVictim = mPlayer;
mPlayer->Scoping(*(int*)mValue);
}
edict_t *enemy = pVictim->pEdict->v.dmg_inflictor;
int damage = (int)pVictim->pEdict->v.dmg_take;
if(!pVictim || !damage || !enemy)
void Client_SetFOV_End(void* mValue)
{
if(!mPlayer)
return;
int weapon = 0;
int aim = 0;
mPlayer->ScopingCheck();
}
pVictim->pEdict->v.dmg_take = 0.0;
void Client_Object(void* mValue)
{
if(!mPlayer)
return;
CPlayer* pAttacker = NULL;
// First need to find out what was picked up
const char *classname;
edict_t* pObject = NULL;
if(enemy->v.flags & (FL_CLIENT | FL_FAKECLIENT))
const char* value;
if(mValue)
{
pAttacker = GET_PLAYER_POINTER(enemy);
weapon = pAttacker->current;
value = (char*)mValue;
}
if(weaponData[weapon].needcheck)
weapon = get_weaponid(pAttacker);
if(!mPlayer->object.carrying)
{
// We grab the first object within the sphere of our player
pObject = FindEntityInSphere(mPlayer->pEdict, mPlayer->pEdict, 50.0);
aim = pAttacker->aiming;
// The loop through all the objects within the sphere
while(pObject && !FNullEnt(pObject))
{
classname = STRING(pObject->v.classname);
if(weaponData[weapon].melee)
pAttacker->saveShot(weapon);
if(strcmp(classname, "dod_object") == 0)
{
mPlayer->object.pEdict = pObject;
mPlayer->object.do_forward = true;
return;
}
pObject = FindEntityInSphere(pObject, mPlayer->pEdict, 50.0);
}
}
else
g_grenades.find(enemy , &pAttacker , weapon);
int TA = 0;
if(!pAttacker)
{
pAttacker = pVictim;
}
if(pAttacker->index != pVictim->index)
{
pAttacker->saveHit(pVictim , weapon , damage, aim);
if(pVictim->pEdict->v.team == pAttacker->pEdict->v.team)
TA = 1;
}
MF_ExecuteForward(iFDamage, pAttacker->index, pVictim->index, damage, weapon, aim, TA);
if(!pVictim->IsAlive())
{
pAttacker->saveKill(pVictim, weapon, (aim == 1) ? 1:0 , TA);
MF_ExecuteForward(iFDeath, pAttacker->index, pVictim->index, weapon, aim, TA);
mPlayer->object.do_forward = true;
}
}
/*
Working on being able to modify and switch weapons as they are sent to the client
void WeaponList(void* value)
void Client_Object_End(void* mValue)
{
if(!mPlayer)
return;
if(!mPlayer->ingame || ignoreBots(mPlayer->pEdict))
return;
float fposition[3];
switch(mPlayer->position)
if(mPlayer->object.do_forward)
{
case 0: MF_Log("pszName = %s", value); break; // string weapon name
case 1: MF_Log("pszAmmo1 = %d", (int)value); break; // byte Ammo Type
case 2: MF_Log("iMaxAmmo1 = %d", (int)value); break; // byte Max Ammo 1
case 3: MF_Log("pszAmmo2 = %d", (int)value); break; // byte Ammo2 Type
case 4: MF_Log("iMaxAmmo2 = %d", (int)value); break; // byte Max Ammo 2
case 5: MF_Log("iSlot = %d", (int)value); break; // byte bucket
case 6: MF_Log("iPosition = %d", (int)value); break; // byte bucket pos
case 7: MF_Log("iId = %d", (int)value); break; // byte id (bit index into pev->weapons)
case 8: MF_Log("iFlags = %d", (int)value); break; // byte Flags
};
mPlayer->object.do_forward = (mPlayer->object.do_forward) ? false : true;
mPlayer->object.carrying = (mPlayer->object.carrying) ? false : true;
mPlayer->position++;
mPlayer->object.pEdict->v.origin.CopyToArray(fposition);
cell position[3] = {fposition[0], fposition[1], fposition[2]};
cell pos = MF_PrepareCellArray(position, 3);
MF_ExecuteForward(iFObjectTouched, mPlayer->index, ENTINDEX(mPlayer->object.pEdict), pos, mPlayer->object.carrying);
if(!mPlayer->object.carrying)
mPlayer->object.pEdict = NULL;
}
}
void WeaponList_End(void* mValue)
{
if(!mPlayer)
return;
MF_Log("Done with %d", mPlayer->position);
mPlayer->position = 0;
}
struct weapon_info_s
{
char *pszName; // string weapon name
int pszAmmo1; // byte Ammo Type
int iMaxAmmo1; // byte Max Ammo 1
int pszAmmo2; // byte Ammo2 Type
int iMaxAmmo2; // byte Max Ammo 2
int iSlot; // byte bucket
int iPosition; // byte bucket pos
int iId; // byte id (bit index into pev->weapons)
int iFlags; // byte Flags
}weapon_info_t;
MESSAGE_BEGIN( MSG_ONE, gmsgWeaponList, NULL, pev );
WRITE_STRING(pszName); // string weapon name
WRITE_BYTE(GetAmmoIndex(II.pszAmmo1)); // byte Ammo Type
WRITE_BYTE(II.iMaxAmmo1); // byte Max Ammo 1
WRITE_BYTE(GetAmmoIndex(II.pszAmmo2)); // byte Ammo2 Type
WRITE_BYTE(II.iMaxAmmo2); // byte Max Ammo 2
WRITE_BYTE(II.iSlot); // byte bucket
WRITE_BYTE(II.iPosition); // byte bucket pos
WRITE_BYTE(II.iId); // byte id (bit index into pev->weapons)
WRITE_BYTE(II.iFlags); // byte Flags
MESSAGE_END();
*/

413
dlls/hamsandwich/CString.h Normal file
View File

@ -0,0 +1,413 @@
/* AMX Mod X
*
* by the AMX Mod X Development Team
* originally developed by OLO
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#ifndef _INCLUDE_CSTRING_H
#define _INCLUDE_CSTRING_H
#include <string.h>
#include <stdio.h>
//by David "BAILOPAN" Anderson
class String
{
public:
String()
{
v = NULL;
a_size = 0;
//assign("");
}
~String()
{
if (v)
delete [] v;
}
String(const char *src)
{
v = NULL;
a_size = 0;
assign(src);
}
const char * _fread(FILE *fp)
{
Grow(512, false);
char *ret = fgets(v, 511, fp);
return ret;
}
String(const String &src)
{
v = NULL;
a_size = 0;
assign(src.c_str());
}
const char *c_str() { return v?v:""; }
const char *c_str() const { return v?v:""; }
void append(const char *t)
{
Grow(size() + strlen(t) + 1);
strcat(v, t);
}
void append(const char c)
{
size_t len = size();
Grow(len + 2);
v[len] = c;
v[len + 1] = '\0';
}
void append(String &d)
{
append(d.c_str());
}
void assign(const String &src)
{
assign(src.c_str());
}
void assign(const char *d)
{
if (!d)
{
clear();
} else {
size_t len = strlen(d);
Grow(len + 1, false);
memcpy(v, d, len);
v[len] = '\0';
}
}
void clear()
{
if (v)
v[0] = '\0';
}
int compare (const char *d) const
{
if (!v)
return strcmp("", d);
else
return strcmp(v, d);
}
//Added this for amxx inclusion
bool empty() const
{
if (!v)
return true;
if (v[0] == '\0')
return true;
return false;
}
size_t size() const
{
if (v)
return strlen(v);
else
return 0;
}
int find(const char c, int index = 0)
{
int len = static_cast<int>(size());
if (len < 1)
return npos;
if (index >= len || index < 0)
return npos;
int i = 0;
for (i=index; i<len; i++)
{
if (v[i] == c)
{
return i;
}
}
return npos;
}
bool is_space(int c)
{
if (c == '\f' || c == '\n' ||
c == '\t' || c == '\r' ||
c == '\v' || c == ' ')
{
return true;
}
return false;
}
void reparse_newlines()
{
size_t len = size();
int offs = 0;
char c;
if (!len)
return;
for (size_t i=0; i<len; i++)
{
c = v[i];
if (c == '^' && (i != len-1))
{
c = v[++i];
if (c == 'n')
c = '\n';
else if (c == 't')
c = '\t';
offs++;
}
v[i-offs] = c;
}
v[len-offs] = '\0';
}
void trim()
{
if (!v)
return;
unsigned int i = 0;
unsigned int j = 0;
size_t len = strlen(v);
if (len == 1)
{
if (is_space(v[i]))
{
clear();
return;
}
}
unsigned char c0 = v[0];
if (is_space(c0))
{
for (i=0; i<len; i++)
{
if (!is_space(v[i]) || (is_space(v[i]) && ((unsigned char)i==len-1)))
{
erase(0, i);
break;
}
}
}
len = strlen(v);
if (len < 1)
{
return;
}
if (is_space(v[len-1]))
{
for (i=len-1; i>=0; i--)
{
if (!is_space(v[i])
|| (is_space(v[i]) && i==0))
{
erase(i+1, j);
break;
}
j++;
}
}
if (len == 1)
{
if (is_space(v[0]))
{
clear();
return;
}
}
}
void erase(unsigned int start, int num = npos)
{
if (!v)
return;
unsigned int i = 0;
size_t len = size();
//check for bounds
if (num == npos || start+num > len-start)
num = len - start;
//do the erasing
bool copyflag = false;
for (i=0; i<len; i++)
{
if (i>=start && i<start+num)
{
if (i+num < len)
{
v[i] = v[i+num];
} else {
v[i] = 0;
}
copyflag = true;
} else if (copyflag) {
if (i+num < len)
{
v[i] = v[i+num];
} else {
v[i] = 0;
}
}
}
len -= num;
v[len] = 0;
}
String substr(unsigned int index, int num = npos)
{
if (!v)
{
String b("");
return b;
}
String ns;
size_t len = size();
if (index >= len || !v)
return ns;
if (num == npos)
{
num = len - index;
} else if (index+num >= len) {
num = len - index;
}
unsigned int i = 0;
unsigned int nslen = num + 2;
ns.Grow(nslen);
for (i=index; i<index+num; i++)
ns.append(v[i]);
return ns;
}
void toLower()
{
if (!v)
return;
unsigned int i = 0;
size_t len = strlen(v);
for (i=0; i<len; i++)
{
if (v[i] >= 65 && v[i] <= 90)
v[i] &= ~(1<<5);
}
}
String & operator = (const String &src)
{
assign(src);
return *this;
}
String & operator = (const char *src)
{
assign(src);
return *this;
}
char operator [] (unsigned int index)
{
if (index > size() || !v)
{
return -1;
} else {
return v[index];
}
}
int at(int a)
{
if (a < 0 || a >= (int)size() || !v)
return -1;
return v[a];
}
bool at(int at, char c)
{
if (at < 0 || at >= (int)size() || !v)
return false;
v[at] = c;
return true;
}
private:
void Grow(unsigned int d, bool copy=true)
{
if (d <= a_size)
return;
char *n = new char[d + 1];
if (copy && v)
strcpy(n, v);
if (v)
delete [] v;
else
strcpy(n, "");
v = n;
a_size = d + 1;
}
char *v;
unsigned int a_size;
public:
static const int npos = -1;
};
#endif //_INCLUDE_CSTRING_H

491
dlls/hamsandwich/CVector.h Normal file
View File

@ -0,0 +1,491 @@
/* AMX Mod X
*
* by the AMX Mod X Development Team
* originally developed by OLO
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#ifndef __CVECTOR_H__
#define __CVECTOR_H__
#include <assert.h>
// Vector
template <class T> class CVector
{
bool Grow()
{
// automatic grow
size_t newSize = m_Size * 2;
if (newSize == 0)
newSize = 8; // a good init value
T *newData = new T[newSize];
if (!newData)
return false;
if (m_Data)
{
for (size_t i=0; i<m_CurrentUsedSize; i++)
newData[i] = m_Data[i];
delete [] m_Data;
}
m_Data = newData;
m_Size = newSize;
return true;
}
bool GrowIfNeeded()
{
if (m_CurrentUsedSize >= m_Size)
return Grow();
else
return true;
}
bool ChangeSize(size_t size)
{
// change size
if (size == m_Size)
return true;
if (!size)
{
if (m_Data)
{
delete [] m_Data;
m_Data = NULL;
m_Size = 0;
}
return true;
}
T *newData = new T[size];
if (!newData)
return false;
if (m_Data)
{
size_t end = (m_CurrentUsedSize < size) ? (m_CurrentUsedSize) : size;
for (size_t i=0; i<end; i++)
newData[i] = m_Data[i];
delete [] m_Data;
}
m_Data = newData;
m_Size = size;
if (m_CurrentUsedSize > m_Size)
m_CurrentUsedSize = m_Size;
return true;
}
void FreeMemIfPossible()
{
if (!m_Data)
return;
if (!m_CurrentUsedSize)
{
ChangeSize(0);
return;
}
size_t newSize = m_Size;
while (m_CurrentUsedSize <= newSize / 2)
newSize /= 2;
if (newSize != m_Size)
ChangeSize(newSize);
}
protected:
T *m_Data;
size_t m_Size;
size_t m_CurrentUsedSize;
public:
class iterator
{
protected:
T *m_Ptr;
public:
// constructors / destructors
iterator()
{
m_Ptr = NULL;
}
iterator(T * ptr)
{
m_Ptr = ptr;
}
// member functions
T * base()
{
return m_Ptr;
}
const T * base() const
{
return m_Ptr;
}
// operators
T & operator*()
{
return *m_Ptr;
}
T * operator->()
{
return m_Ptr;
}
iterator & operator++() // preincrement
{
++m_Ptr;
return (*this);
}
iterator operator++(int) // postincrement
{
iterator tmp = *this;
++m_Ptr;
return tmp;
}
iterator & operator--() // predecrement
{
--m_Ptr;
return (*this);
}
iterator operator--(int) // postdecrememnt
{
iterator tmp = *this;
--m_Ptr;
return tmp;
}
bool operator==(T * right) const
{
return (m_Ptr == right);
}
bool operator==(const iterator & right) const
{
return (m_Ptr == right.m_Ptr);
}
bool operator!=(T * right) const
{
return (m_Ptr != right);
}
bool operator!=(const iterator & right) const
{
return (m_Ptr != right.m_Ptr);
}
iterator & operator+=(size_t offset)
{
m_Ptr += offset;
return (*this);
}
iterator & operator-=(size_t offset)
{
m_Ptr -= offset;
return (*this);
}
iterator operator+(size_t offset) const
{
iterator tmp(*this);
tmp.m_Ptr += offset;
return tmp;
}
iterator operator-(size_t offset) const
{
iterator tmp(*this);
tmp.m_Ptr -= offset;
return tmp;
}
T & operator[](size_t offset)
{
return (*(*this + offset));
}
const T & operator[](size_t offset) const
{
return (*(*this + offset));
}
bool operator<(const iterator & right) const
{
return m_Ptr < right.m_Ptr;
}
bool operator>(const iterator & right) const
{
return m_Ptr > right.m_Ptr;
}
bool operator<=(const iterator & right) const
{
return m_Ptr <= right.m_Ptr;
}
bool operator>=(const iterator & right) const
{
return m_Ptr >= right.m_Ptr;
}
size_t operator-(const iterator & right) const
{
return m_Ptr - right.m_Ptr;
}
};
// constructors / destructors
CVector<T>()
{
m_Size = 0;
m_CurrentUsedSize = 0;
m_Data = NULL;
}
CVector<T>(const CVector<T> & other)
{
// copy data
m_Data = new T [other.m_CurrentUsedSize];
m_Size = other.m_CurrentUsedSize;
m_CurrentUsedSize = other.m_CurrentUsedSize;
for (size_t i=0; i<other.m_CurrentUsedSize; i++)
m_Data[i] = other.m_Data[i];
}
~CVector<T>()
{
clear();
}
// interface
size_t size() const
{
return m_CurrentUsedSize;
}
size_t capacity() const
{
return m_Size;
}
iterator begin() const
{
return iterator(m_Data);
}
iterator end() const
{
return iterator(m_Data + m_CurrentUsedSize);
}
iterator iterAt(size_t pos)
{
if (pos > m_CurrentUsedSize)
assert(0);
return iterator(m_Data + pos);
}
bool reserve(size_t newSize)
{
if (newSize > m_Size)
return ChangeSize(newSize);
return true;
}
bool push_back(const T & elem)
{
++m_CurrentUsedSize;
if (!GrowIfNeeded())
{
--m_CurrentUsedSize;
return false;
}
m_Data[m_CurrentUsedSize - 1] = elem;
return true;
}
void pop_back()
{
--m_CurrentUsedSize;
if (m_CurrentUsedSize < 0)
m_CurrentUsedSize = 0;
FreeMemIfPossible();
}
bool resize(size_t newSize)
{
if (!ChangeSize(newSize))
return false;
m_CurrentUsedSize = newSize;
return true;
}
bool empty() const
{
return (m_CurrentUsedSize == 0);
}
T & at(size_t pos)
{
if (pos > m_CurrentUsedSize)
{
assert(0);
}
return m_Data[pos];
}
const T & at(size_t pos) const
{
if (pos > m_CurrentUsedSize)
{
assert(0);
}
return m_Data[pos];
}
T & operator[](size_t pos)
{
return at(pos);
}
const T & operator[](size_t pos) const
{
return at(pos);
}
T & front()
{
if (m_CurrentUsedSize < 1)
{
assert(0);
}
return m_Data[0];
}
const T & front() const
{
if (m_CurrentUsedSize < 1)
{
assert(0);
}
return m_Data[0];
}
T & back()
{
if (m_CurrentUsedSize < 1)
{
assert(0);
}
return m_Data[m_CurrentUsedSize - 1];
}
const T & back() const
{
if (m_CurrentUsedSize < 1)
{
assert(0);
}
return m_Data[m_CurrentUsedSize - 1];
}
iterator insert(iterator where, const T & value)
{
// validate iter
if (where < m_Data || where > (m_Data + m_CurrentUsedSize))
return iterator(0);
size_t ofs = where - begin();
++m_CurrentUsedSize;
if (!GrowIfNeeded())
{
--m_CurrentUsedSize;
return false;
}
where = begin() + ofs;
// Move subsequent entries
for (T *ptr = m_Data + m_CurrentUsedSize - 2; ptr >= where.base(); --ptr)
*(ptr + 1) = *ptr;
*where.base() = value;
return where;
}
iterator erase(iterator where)
{
// validate iter
if (where < m_Data || where >= (m_Data + m_CurrentUsedSize))
return iterator(0);
size_t ofs = where - begin();
if (m_CurrentUsedSize > 1)
{
// move
T *theend = m_Data + m_CurrentUsedSize;
for (T *ptr = where.base() + 1; ptr < theend; ++ptr)
*(ptr - 1) = *ptr;
}
--m_CurrentUsedSize;
FreeMemIfPossible();
return begin() + ofs;
}
void clear()
{
m_Size = 0;
m_CurrentUsedSize = 0;
if (m_Data)
{
delete [] m_Data;
m_Data = NULL;
}
}
};
#endif // __CVECTOR_H__

View File

@ -0,0 +1,161 @@
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "sdk/amxxmodule.h"
#include "FileParser.h"
#define FP_MAX_LENGTH 2048
/**
* Given a string, this will remove whitespace at the beginning and end, and remove comments.
*
* @param data The string to format. It changes this data directly.
* @return Returns a pointer to the end of the newly formated string.
*/
static char *FP_FormatLine(char *data)
{
char *End; /**< Pointer to the end of the string. */
char *Start; /**< Pointer to the start of the string. */
char *Temp=Start; /**< Temporary pointer for parsing. */
Start=data;
// Strip beginning whitespace
while (*Start==' ' || *Start=='\t') Start++;
// if the beginning non-whitespace character is a ';', then it's a comment
// ignore the rest of the file
if (*Start==';')
{
// just set data[0] to \0 and return out of here.
*data='\0';
return data;
}
// now strip comments from the end of a line
Temp=Start;
End=Start+(strlen(Start)-1);
while (Temp<=End)
{
if (*Temp==';')
{
*Temp='\0';
break;
}
++Temp;
}
// now go to the end of the line, and remove whitespace
while ( (*End=='\n' ||
*End=='\r' ||
*End==' ' ||
*End=='\t') &&
End>=Start)
{
End--;
}
++End;
*End='\0';
// if Start==data, we're done
if (Start==data)
{
return End;
}
// otherwise, copy from Start to data
while ((*data++=*Start++)!='\0')/*do nothing*/;
return End;
};
static const char* get_localinfo( const char* name , const char* def = 0 )
{
const char* b = LOCALINFO( (char*)name );
if (((b==0)||(*b==0)) && def )
SET_LOCALINFO((char*)name,(char*)(b = def) );
return b;
}
/**
* Reads the config file and parses keys.
*
* @param Category The category (prefix) to look for. Eg.: "cs_linux_", "dod_windows_"
* @param Feedback The function to call when a match is made.
* @noreturn
*/
void FP_SetupOffsets(const char *Category, FP_ptrFeedback Feedback)
{
char FileName[512];
size_t CatLen=strlen(Category);
MF_BuildPathnameR(FileName,sizeof(FileName)-1,"%s",get_localinfo("amxx_configsdir","addons/amxmodx/configs"));
strncat(FileName,"/hamdata.ini",sizeof(FileName)-1);
FILE *fp=fopen(FileName,"r");
if (!fp)
{
MF_Log("Unable to open \"%s\" for reading",FileName);
return;
}
char Data[FP_MAX_LENGTH + 1];
while (!feof(fp))
{
Data[0]='\0';
fgets(Data,FP_MAX_LENGTH,fp);
FP_FormatLine(Data);
if (strncmp(Data,Category,CatLen)==0)
{
// Find the first space, set it to NULL
char *Param=&Data[0];
while (*Param!=' ' && *Param!='\t' && *Param!='\0')
{
++Param;
}
if (*Param=='\0')
{
// special instance; if this is NULL get out of here
continue;
}
// NULL this space, and then find the first non whitespace character and
// use that as the parameter field in the callback
*Param++='\0';
while (*Param==' ' || *Param=='\t')
{
++Param;
}
if (*Param=='\0')
{
// special instance; if this is NULL get out of here
continue;
}
Feedback(&Data[0],Param);
}
}
fclose(fp);
}

View File

@ -0,0 +1,6 @@
#ifndef FILEPARSER_H
#define FILEPARSER_H
typedef bool (*FP_ptrFeedback)(const char *key, const char *value);
#endif // FILEPARSER_H

110
dlls/hamsandwich/Makefile Normal file
View File

@ -0,0 +1,110 @@
#(C)2004-2005 AMX Mod X Development Team
# Makefile written by David "BAILOPAN" Anderson
HLSDK = ../../../hlsdk
MM_ROOT = ../../../metamod/metamod
### EDIT BELOW FOR OTHER PROJECTS ###
CRAZY_OPT_FLAGS = -DCRAZY_OPTS -O3 -funroll-loops -ffast-math -s -pipe -fomit-frame-pointer -fno-strict-aliasing -DNDEBUG -fmerge-all-constants -fmodulo-sched -fgcse-sm -fgcse-las -fgcse-after-reload -floop-optimize2 -funsafe-loop-optimizations -ftree-loop-linear -ftree-loop-im -ftree-loop-ivcanon -fivopts -ftree-vectorize -fvariable-expansion-in-unroller -funsafe-math-optimizations -ffinite-math-only -fpeel-loops -funswitch-loops -fvisibility=hidden -fvisibility-inlines-hidden -fPIC -Wall -Wno-unknown-pragmas -Wno-deprecated -fno-exceptions -DHAVE_STDINT_H -static-libgcc -fno-rtti -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion -Wsign-compare -Wmissing-noreturn -Winline -Wlong-long -Wunsafe-loop-optimizations -Wctor-dtor-privacy -Wno-non-virtual-dtor -Wreorder -Woverloaded-virtual -Wsign-promo -Wsynth -shared
CRAZY_LINK_FLAGS = -fwhole-program
#-fwhole-program -combine
SANE_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fomit-frame-pointer -fno-strict-aliasing -DNDEBUG
OPT_FLAGS =
DEBUG_FLAGS = -g -ggdb3
CPP = gcc-4.1
#CPP = gcc-2.95
NAME = hamsandwich
BIN_SUFFIX = amxx_i386.so
OBJECTS = sdk/amxxmodule.cpp FileParser.cpp amxxapi.cpp hooks.cpp \
tableentries/VTableManager.cpp tableentries/TakeDamage.cpp tableentries/Use.cpp \
tableentries/Blocked.cpp
#natives.cpp vtable.cpp
#tableentries/VTableUse.cpp tableentries/VTableTakedamage.cpp
#natives/cs.cpp natives/dod.cpp natives/tfc.cpp \
#natives/ns.cpp natives/ts.cpp natives/sven.cpp \
#FileParser.cpp
LINK =
INCLUDE = -I. -I$(HLSDK) -I$(HLSDK)/dlls -I$(HLSDK)/engine -I$(HLSDK)/game_shared -I$(HLSDK)/game_shared \
-I$(MM_ROOT) -I$(HLSDK)/common -I$(HLSDK)/pm_shared -I./tableentries
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
ifeq "$(DEBUG)" "true"
BIN_DIR = Debug
CFLAGS = $(DEBUG_FLAGS)
else
ifeq "$(CRAZY)" "true"
BIN_DIR = Optimized
OPT_FLAGS = $(CRAZY_OPT_FLAGS)
LINK = $(CRAZY_LINK_FLAGS)
else
BIN_DIR = Release
OPT_FLAGS = $(SANE_OPT_FLAGS)
endif
ifeq "$(GCC_VERSION)" "4"
OPT_FLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
endif
CFLAGS = $(OPT_FLAGS)
endif
CFLAGS += -fPIC -Wall -Wno-non-virtual-dtor -fno-exceptions -DHAVE_STDINT_H -fno-rtti
BINARY = $(NAME)_$(BIN_SUFFIX)
CFLAGS += -DPAWN_CELL_SIZE=32 -DJIT -DASM32
OPT_FLAGS += -march=i586
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
$(BIN_DIR)/%.o: %.cpp
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
all:
mkdir -p $(BIN_DIR)
mkdir -p $(BIN_DIR)/sdk
mkdir -p $(BIN_DIR)/natives
mkdir -p $(BIN_DIR)/tableentries
$(MAKE) hamsandwich
hamsandwich: $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
debug:
$(MAKE) all DEBUG=true
default: all
crazy:
$(MAKE) all CRAZY=true
clean:
rm -rf Release/*.o
rm -rf Release/sdk/*.o
rm -rf Release/natives/*.o
rm -rf Release/tableentries/*.o
rm -rf Release/$(NAME)_$(BIN_SUFFIX)
rm -rf Debug/*.o
rm -rf Debug/sdk/*.o
rm -rf Debug/natives/*.o
rm -rf Debug/tableentries/*.o
rm -rf Debug/$(NAME)_$(BIN_SUFFIX)
rm -rf Optimized/*.o
rm -rf Optimized/sdk/*.o
rm -rf Optimized/natives/*.o
rm -rf Optimized/tableentries/*.o
rm -rf Optimized/$(NAME)_$(BIN_SUFFIX)

View File

@ -0,0 +1,90 @@
/* Ham Sandwich
*
* by sawce
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
/* Inlined replacements for INDEXENT/ENTINDEX
* It only really removes the overhead of the push/jump
* but since INDEXENT/ENTINDEX are used a lot with amxx
* it might be beneficial to include.
* NOTE: Bad stuff will happen if you call these before
* NEW_Initialize()
* NOTE: No bounds checking is done because natives
* should use their own bounds checking!
*/
#ifndef NEW_UTIL_H
#define NEW_UTIL_H
extern edict_t *NEW_FirstEdict;
extern bool NEW_Initialized;
/**
* This is called on the first Spawn() ever hooked. This would be worldspawn (index 0)
*/
inline void NEW_Initialize(edict_t *Entity)
{
// This is not worldspawn?
// compensate
NEW_FirstEdict=Entity;
NEW_Initialized=true;
}
/**
* Converts an integer index into an edict pointer
*/
inline edict_t *INDEXENT_NEW(const int Index)
{
return (edict_t *)(NEW_FirstEdict + Index);
};
/**
* Converts an edict pointer into an integer index
*/
inline int ENTINDEX_NEW(const edict_t *Ent)
{
return (int)(Ent - NEW_FirstEdict);
};
// Inlined replacement of MF_GetAmxAddr
inline REAL amx_ctof2(cell x)
{
return *(REAL*)&x;
}
inline cell amx_ftoc2(REAL x)
{
return *(cell*)&x;
}
#endif // NEW_UTIL_H

View File

@ -0,0 +1,624 @@
/* Trampolines
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#ifndef TRAMPOLINES_H
#define TRAMPOLINES_H
#ifndef NDEBUG
#define TPRINT(msg) printf msg
#else
#define TPRINT(msg) /* nothing */
#endif
#if defined _WIN32
#include <windows.h>
#elif defined __linux__
#include <sys/mman.h>
#endif
#include <stddef.h> // size_t
#include <string.h> // memcpy
namespace Trampolines
{
/**
* List of x86 bytecodes for creating
* basic trampolines at runtime.
* -
* These are defined here so that, should
* the need ever arise, this can be ported
* to other architectures fairly painlessly
*/
namespace Bytecode
{
/**
* Prologue for a void function
* Clobbers EBX and EAX
*/
const unsigned char codeVoidPrologue[] = {
0x55, // push ebp
0x89, 0xE5, // mov ebp, esp
0x50, // push eax
};
/**
* Prologue for a function that returns
* Clobbers EBX, EAX too but not after call
*/
const unsigned char codeReturnPrologue[] = {
0x55, // push ebp
0x89, 0xE5, // mov ebp, esp
};
const unsigned char codeThisReturnPrologue[] = {
0x55, // push ebp
0x89, 0xE5, // mov ebp, esp
};
/**
* Takes a paramter from the trampoline's stack
* and pushes it onto the target's stack.
*/
const unsigned char codePushParam[] = {
0xFF, 0x75, 0xFF // pushl [ebp+0xFF]
};
/**
* Offset of codePushParam to modify at runtime
* that contains the stack offset
*/
const unsigned int codePushParamReplace = 2;
/**
* Takes the "this" pointer from the trampoline and
* pushes it onto the target's stack.
*/
const unsigned char codePushThis[] = {
#if defined _WIN32
0x51 // push ecx
#elif defined __linux__
0xFF, 0x75, 0x04 // pushl [ebp+0x08h]
#endif
};
#if defined __linux__
const int codePushThisReplace = 2;
#endif
/**
* Pushes a raw number onto the target's stack
*/
const unsigned char codePushID[] = {
0x68, 0xDE, 0xFA, 0xAD, 0xDE // push DEADFADEh
};
/**
* Offset of codePushID to modify at runtime
* to contain the number to push
*/
const unsigned int codePushIDReplace = 1;
/**
* Call our procedure
*/
const unsigned char codeCall[] = {
0xB8, 0xDE, 0xFA, 0xAD, 0xDE,// mov eax, DEADFADEh
0xFF, 0xD0 // call eax
};
/**
* Offset of codeCall to modify at runtime
* to contain the pointer to the function
*/
const unsigned int codeCallReplace = 1;
/**
* Adds to ESP, freeing up stack space
*/
const unsigned char codeFreeStack[] = {
0x81, 0xC4, 0xFF, 0xFF, 0xFF, 0xFF// add esp REPLACEME
};
/**
* Offset of codeFreeStack to modify at runtime
* to contain how much data to free
*/
const unsigned int codeFreeStackReplace = 2;
/**
* Epilogue of a simple return function
*/
const unsigned char codeReturnEpilogue[] = {
0x5D, // pop ebp
0xC3 // ret
};
const unsigned char codeReturnEpilogueN[] = {
0x5D, // pop ebp
0xC2, 0xCD, 0xAB // retn 0xABCD
};
const int codeReturnEpilogueNReplace = 2;
/**
* Epilogue of a void return function
*/
const unsigned char codeVoidEpilogue[] = {
0x58, // pop eax
0x5D, // pop ebp
0xC3 // ret
};
const unsigned char codeVoidEpilogueN[] = {
0x58, // pop eax
0x5D, // pop ebp
0xC2, 0xCD, 0xAB // retn 0xABCD
};
const int codeVoidEpilogueNReplace = 3;
const unsigned char codeBreakpoint[] = {
0xCC // int 3
};
}
/**
* Our actual maker of the trampolines!!@$
* I've no idea why I made this a class and not a namespace
* Oh well!
*/
class TrampolineMaker
{
private:
unsigned char *m_buffer; // the actual buffer containing the code
int m_size; // size of the buffer
int m_mystack; // stack for the trampoline itself
int m_calledstack; // stack for the target function
int m_paramstart;
int m_thiscall;
/**
* Adds data to the buffer
* data must be pre-formatted before hand!
*/
void Append(const unsigned char *src, size_t size)
{
int orig=m_size;
m_size+=size;
if (m_buffer==NULL)
{
m_buffer=(unsigned char *)malloc(m_size);
}
else
{
m_buffer=(unsigned char *)realloc(m_buffer,m_size);
}
unsigned char *dat=m_buffer+orig; // point dat to the end of the prewritten
while (orig<m_size)
{
*dat++=*src++;
orig++;
};
};
public:
TrampolineMaker()
{
m_buffer=NULL;
m_size=0;
m_mystack=0;
m_calledstack=0;
m_paramstart=0;
m_thiscall=0;
};
/**
* Inserts a breakpoint (int 3) into the trampoline.
*/
void Breakpoint()
{
Append(&::Trampolines::Bytecode::codeBreakpoint[0],sizeof(::Trampolines::Bytecode::codeBreakpoint));
};
/**
* Adds the "return prologue", pushes registers and prepares stack
*/
void ReturnPrologue()
{
Append(&::Trampolines::Bytecode::codeReturnPrologue[0],sizeof(::Trampolines::Bytecode::codeReturnPrologue));
m_paramstart=0;
m_thiscall=0;
};
void ThisReturnPrologue()
{
this->ReturnPrologue();
m_thiscall=1;
};
/**
* Adds the void prologue pushes registers, prepares the stack
*/
void VoidPrologue()
{
Append(&::Trampolines::Bytecode::codeVoidPrologue[0],sizeof(::Trampolines::Bytecode::codeVoidPrologue));
m_paramstart=0;
m_thiscall=0;
};
/**
* Flags this trampoline as a thiscall trampoline, and prepares the void prologue.
*/
void ThisVoidPrologue()
{
this->VoidPrologue();
m_thiscall=1;
};
/**
* Epilogue for a returning function pops registers but does not free any more of the stack!
*/
void ReturnEpilogue()
{
Append(&::Trampolines::Bytecode::codeReturnEpilogue[0],sizeof(::Trampolines::Bytecode::codeReturnEpilogue));
};
/**
* Epilogue that also frees it's estimated stack usage. Useful for stdcall/thiscall/fastcall.
*/
void ReturnEpilogueAndFree()
{
printf("Freeing %d bytes\n",m_mystack);
this->ReturnEpilogue(m_mystack);
};
/**
* Return epilogue. Pops registers, and frees given amount of data from the stack.
*
* @param howmuch How many bytes to free from the stack.
*/
void ReturnEpilogue(int howmuch)
{
unsigned char code[sizeof(::Trampolines::Bytecode::codeReturnEpilogueN)];
memcpy(&code[0],&::Trampolines::Bytecode::codeReturnEpilogueN[0],sizeof(::Trampolines::Bytecode::codeReturnEpilogueN));
unsigned char *c=&code[0];
union
{
int i;
unsigned char b[4];
} bi;
bi.i=howmuch;
c+=::Trampolines::Bytecode::codeReturnEpilogueNReplace;
*c++=bi.b[0];
*c++=bi.b[1];
Append(&code[0],sizeof(::Trampolines::Bytecode::codeReturnEpilogueN));
//Append(&::Trampolines::Bytecode::codeReturnEpilogueN[0],sizeof(::Trampolines::Bytecode::codeReturnEpilogueN));
};
/**
* Void epilogue, pops registers and frees the estimated stack usage of the trampoline.
*/
void VoidEpilogueAndFree()
{
printf("Freeing %d bytes\n",m_mystack);
this->VoidEpilogue(m_mystack);
};
/**
* Void epilogue, pops registers, nothing else done with stack.
*/
void VoidEpilogue()
{
Append(&::Trampolines::Bytecode::codeVoidEpilogue[0],sizeof(::Trampolines::Bytecode::codeVoidEpilogue));
};
/**
* Void epilogue, pops registers, frees given amount of data off of the stack.
*
* @param howmuch How many bytes to free from the stack.
*/
void VoidEpilogue(int howmuch)
{
unsigned char code[sizeof(::Trampolines::Bytecode::codeVoidEpilogueN)];
memcpy(&code[0],&::Trampolines::Bytecode::codeVoidEpilogueN[0],sizeof(::Trampolines::Bytecode::codeVoidEpilogueN));
unsigned char *c=&code[0];
union
{
int i;
unsigned char b[4];
} bi;
bi.i=howmuch;
c+=::Trampolines::Bytecode::codeVoidEpilogueNReplace;
*c++=bi.b[0];
*c++=bi.b[1];
Append(&code[0],sizeof(::Trampolines::Bytecode::codeVoidEpilogueN));
Append(&::Trampolines::Bytecode::codeVoidEpilogueN[0],sizeof(::Trampolines::Bytecode::codeVoidEpilogueN));
};
/**
* Pushes the "this" pointer onto the callee stack. Pushes ECX for MSVC, and param0 on GCC.
*/
void PushThis()
{
if (!m_thiscall)
{
return;
}
unsigned char code[sizeof(::Trampolines::Bytecode::codePushThis)];
memcpy(&code[0],&::Trampolines::Bytecode::codePushThis[0],sizeof(::Trampolines::Bytecode::codePushThis));
#if defined __linux__
unsigned char *c=&code[0];
union
{
int i;
unsigned char b[4];
} bi;
bi.i=m_paramstart+8;
c+=::Trampolines::Bytecode::codePushThisReplace;
*c++=bi.b[0];
#endif
Append(&code[0],sizeof(::Trampolines::Bytecode::codePushThis));
#if defined __linux__
TPRINT(("mystack=%d+4\n",m_mystack));
m_mystack+=4;
#endif
TPRINT(("calledstack=%d+4\n",m_calledstack));
m_calledstack+=4;
};
/**
* Frees what is estimated as the stack usage of the trampoline.
*/
void FreeMyStack(void)
{
TPRINT(("freeing mystack=%d+4\n",m_mystack));
this->FreeStack(m_mystack);
};
/**
* Frees the estimated stack usage of the callee.
*/
void FreeTargetStack(void)
{
TPRINT(("freeing calledstack=%d+4\n",m_calledstack));
this->FreeStack(m_calledstack);
};
/**
* Frees the estimated stack usage of the callee and the trampoline.
*/
void FreeBothStacks(void)
{
TPRINT(("freeing mystack=%d+4\n",m_mystack));
TPRINT(("freeing calledstack=%d+4\n",m_calledstack));
this->FreeStack(m_calledstack + m_mystack);
};
/**
* Frees a given amount of bytes from the stack.
*
* @param howmuch How many bytes to free.
*/
void FreeStack(int howmuch)
{
unsigned char code[sizeof(::Trampolines::Bytecode::codeFreeStack)];
memcpy(&code[0],&::Trampolines::Bytecode::codeFreeStack[0],sizeof(::Trampolines::Bytecode::codeFreeStack));
unsigned char *c=&code[0];
union
{
int i;
unsigned char b[4];
} bi;
bi.i=howmuch;
c+=::Trampolines::Bytecode::codeFreeStackReplace;
*c++=bi.b[0];
*c++=bi.b[1];
*c++=bi.b[2];
*c++=bi.b[3];
Append(&code[0],sizeof(::Trampolines::Bytecode::codeFreeStack));
};
/**
* Pushes a raw number onto the callee stack.
*
* @param Number The number to push onto the callee stack.
*/
void PushNum(int Number)
{
unsigned char code[sizeof(::Trampolines::Bytecode::codePushID)];
memcpy(&code[0],&::Trampolines::Bytecode::codePushID[0],sizeof(::Trampolines::Bytecode::codePushID));
unsigned char *c=&code[0];
union
{
int i;
unsigned char b[4];
} bi;
bi.i=Number;
c+=::Trampolines::Bytecode::codePushIDReplace;
*c++=bi.b[0];
*c++=bi.b[1];
*c++=bi.b[2];
*c++=bi.b[3];
Append(&code[0],sizeof(::Trampolines::Bytecode::codePushID));
TPRINT(("calledstack=%d+4\n",m_calledstack));
m_calledstack+=4; // increase auto detected stack size
};
/**
* Takes a parameter passed on the trampoline's stack and inserts it into the callee's stack.
*
* @param which The parameter number to push. 1-based. "thiscall" trampolines automatically compensate for the off-number on GCC.
*/
void PushParam(int which)
{
#if defined __linux__
if (m_thiscall)
{
which++;
}
#endif
which=which*4;
which+=m_paramstart+4;
unsigned char value=which;
unsigned char code[sizeof(::Trampolines::Bytecode::codePushParam)];
memcpy(&code[0],&::Trampolines::Bytecode::codePushParam[0],sizeof(::Trampolines::Bytecode::codePushParam));
unsigned char *c=&code[0];
c+=::Trampolines::Bytecode::codePushParamReplace;
*c=value;
Append(&code[0],sizeof(::Trampolines::Bytecode::codePushParam));
TPRINT(("calledstack=%d+4\n",m_calledstack));
m_calledstack+=4; // increase auto detected stack size
TPRINT(("mystack=%d+4\n",m_mystack));
m_mystack+=4;
};
/**
* Insert a function to call into the trampoline.
*
* @param ptr The function to call, cast to void*.
*/
void Call(void *ptr)
{
unsigned char code[sizeof(::Trampolines::Bytecode::codeCall)];
memcpy(&code[0],&::Trampolines::Bytecode::codeCall[0],sizeof(::Trampolines::Bytecode::codeCall));
unsigned char *c=&code[0];
union
{
void *p;
unsigned char b[4];
} bp;
bp.p=ptr;
c+=::Trampolines::Bytecode::codeCallReplace;
*c++=bp.b[0];
*c++=bp.b[1];
*c++=bp.b[2];
*c++=bp.b[3];
Append(&code[0],sizeof(::Trampolines::Bytecode::codeCall));
};
/**
* Finalizes the trampoline. Do not try to modify it after this.
*
* @param size A pointer to retrieve the size of the trampoline. Ignored if set to NULL.
* @return The trampoline pointer, cast to void*.
*/
void *Finish(int *size)
{
void *ret=(void *)m_buffer;
if (size)
{
*size=m_size;
}
#if defined _WIN32
DWORD OldFlags;
VirtualProtect(ret,m_size,PAGE_EXECUTE_READWRITE,&OldFlags);
#elif defined __linux__
mprotect(ret,m_size,PROT_READ|PROT_WRITE|PROT_EXEC);
#endif
m_size=0;
m_buffer=NULL; // so we don't accidentally rewrite!
m_mystack=0;
m_calledstack=0;
return ret;
};
};
};
#endif // TRAMPOLINEMANAGER_H

View File

@ -0,0 +1,243 @@
/* AMX Mod X
*
* by the AMX Mod X Development Team
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
* Description: AMX Mod X Module Interface hooks
*/
#include <stdlib.h>
#include <stddef.h>
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "CVector.h"
#include "CString.h"
#include "FileParser.h"
#include "NEW_Util.h"
#include "VTableManager.h"
#include "VTableEntries.h"
CVector<String *> SuffixNames; /**< List of names being searched for in the config file. */
CVector<void (*)(const char *, const char *)> SuffixFunctions; /**< Callback functions for when we find a hunted keyvalue. */
CVector<void (*)(void)> ConfigDoneCallbacks; /**< Callbacks when our config file is done being parsed. */
edict_t *NEW_FirstEdict=NULL; /**< Used for the NEW_Utils INDEXENT/ENTINDEX replacements. */
bool NEW_Initialized=false; /**< Whether NEW_Utils has been initialized yet. */
void FP_SetupOffsets(const char *name, FP_ptrFeedback feedback);
unsigned int HAM_pev=0; /**< Offset of pev from the this pointer. */
unsigned int HAM_pevset=0; /**< Whether or not the pev offset has been set. */
unsigned int HAM_classbase=0; /**< Offset of the vtable from the this pointer. */
unsigned int HAM_classbaseset=0; /**< Whether or not the classbase offset has been set. */
char ModKey[256]; /**< Temporary buffer for holding the <modname>_<os> prefix. */
/**
* Adds a callback to the config parser for this config suffix.
*
* @param suffix The suffix to add, eg "takedamage" would be called for "cs_linux_takedamage"
* @param callback The function to call when this key is found.
* @noreturn
*/
void RegisterKeySuffix(const char *suffix, void (*callback)(const char *,const char *))
{
String *Suffix=new String(suffix);
SuffixNames.push_back(Suffix);
SuffixFunctions.push_back(callback);
};
/**
* Adds this entry to the configdone callback.
*
* @param callback Function to call when the config file is done being parsed.
* @noreturn
*/
void RegisterConfigCallback(void (*callback)(void))
{
ConfigDoneCallbacks.push_back(callback);
};
/**
* Starts each vtable entry. This needs to be edited for every additional hook.
*
* @noreturn
*/
void HAM_CallInitialization(void)
{
#define VTINIT(TableName) VTable##TableName::Initialize(&HAM_pev,&HAM_pevset,&HAM_classbase,&HAM_classbaseset)
VTINIT(TakeDamage);
VTINIT(Use);
#undef VTINIT
}
/**
* Tells all the table entries that the config file is done being parsed. Register their natives now.
*
* @noreturn
*/
void HAM_CallConfigDone(void)
{
int i=0; /**< Iterator. */
int end=ConfigDoneCallbacks.size(); /**< How many to parse. */
while (i<end)
{
ConfigDoneCallbacks[i]();
++i;
}
// done with this, free up the vector
ConfigDoneCallbacks.clear();
};
/**
* Simple wrapper to uniform string to number conversion. I don't just use -1 on strtol base because I don't want octal conversion.
*
* @param input The input string.
* @return The input string converted to an unsigned integer.
*/
int HAM_StrToNum(const char *input)
{
char *end; /**< Temporary pointer, needed for strtoul(). */
// if begins with 0x or 0X it's to be interpretted as hex
if (*input=='0' &&
(*(input+1)=='x' || *(input+1)=='X'))
{
return strtoul(input,&end,16);
}
// otherwise it's to be interpretted as base 10
return strtoul(input,&end,10);
}
/**
* This is called every time a key with the <mod>_<os>_ prefix is found.
*
* @param key The full key (eg: cs_windows_takedamage)
* @param data The corresponding data.
* @return true when key is used, false otherwise
*/
bool HAM_GetKey(const char *key, const char *data)
{
char TempKey[512]; /**< Temporary buffer. */
int i=0; /**< Iterator. */
int end=SuffixNames.size(); /**< How many suffixes to check. */
bool found=false; /**< Whether this key has been used or not. */
while (i<end)
{
snprintf(TempKey,sizeof(TempKey)-1,"%s_%s",ModKey,SuffixNames[i]->c_str());
if (strcmp(TempKey,key)==0)
{
SuffixFunctions[i](SuffixNames[i]->c_str(),data);
found=true;
}
++i;
}
return found;
}
/**
* Simple function to set the "pev" field that is used by all forwards.
*
* @param key The key suffix being forwarded.
* @param data The data corresponding to the key.
* @noreturn
*/
void HAM_SetPev(const char *key, const char *data)
{
HAM_pev=HAM_StrToNum(data);
HAM_pevset=1;
}
/**
* Simple function to set the "classbase" field that is used by all natives when built with GCC.
*
* @param key The key suffix being forwarded.
* @param data The data corresponding to the key.
* @noreturn
*/
#if defined __linux__
void HAM_SetClassBase(const char *key, const char *data)
{
HAM_classbase=HAM_StrToNum(data);
HAM_classbaseset=1;
}
#endif
void OnAmxxAttach()
{
HAM_CallInitialization();
#ifdef __linux__
snprintf(ModKey,sizeof(ModKey)-1,"%s_linux",MF_GetModname());
#else
snprintf(ModKey,sizeof(ModKey)-1,"%s_windows",MF_GetModname());
#endif
RegisterKeySuffix("pev",HAM_SetPev);
// this is only needed for Linux
#if defined __linux__
RegisterKeySuffix("classbase",HAM_SetClassBase);
#else // Emulate it being set on Windows, since it's not needed
HAM_classbase=0;
HAM_classbaseset=1;
#endif
FP_SetupOffsets(ModKey,HAM_GetKey);
HAM_CallConfigDone();
/* TODO: Cbase natives
if (HAM_Set & HAM_GOT_PEV)
{
HAM_RegisterCbaseFast();
}
HAM_RegisterCbaseSafe();
VTH_Natives();
*/
}
void OnPluginsLoaded()
{
NEW_Initialize(INDEXENT(0));
};
void OnPluginsUnloaded()
{
VTMan.Cleanup();
};

View File

@ -0,0 +1,109 @@
; Ham Sandwich module config file
; -
; Do not modify this file unless you know exactly what you're doing!
; -
; entry syntax is as follows:
; [modname]_[os]_key
; Example: the "use" key on TS running Linux would be "ts_linux_use"
; "modname" is the game directory, NOT the game description!
; eg: "ts", not "The Specialists"
; -
; Keys support either hexadecimal (MUST prefix with 0x) or base 10
; -
; Key types:
; * takedamage: this is the vtable index of the takedamage routine
; * use: this is the vtable index of the use routine
; * pev: this is the offset in bytes of the location of pev in the cbaseentity
; * classbase: this is the size in bytes of the cbaseentity base class LINUX ONLY
; NOTE: If the mod is compiled with GCC 3.3+ (NS is the only one
; I know of), then the classbase will always be 0x0
; -
; NOTE: If a mod is missing keys for a certain native, that particular native
; will not be loaded! Example: Say CS is missing the "takedamage" index
; but has the use and pev indexes. The hs_use and hs_pdata_cbase natives
; will be registered, but the hs_takedamage native will not be registered.
; Data dated: 2007-02-23
; Version tested: 1.6 Steam (legitimate)
cstrike_windows_takedamage 12
cstrike_windows_use 46
cstrike_windows_pev 4
cstrike_linux_takedamage 14
cstrike_linux_use 48
cstrike_linux_pev 0
cstrike_linux_classbase 0x94
; Data dated: 2007-02-23
; Version tested: 1.6 Steam (legitimate)
czero_windows_takedamage 12
czero_windows_use 46
czero_windows_pev 4
czero_linux_takedamage 14
czero_linux_use 48
czero_linux_pev 0
czero_linux_classbase 0x94
; Data dated: 2007-02-23
; Version tested: 3.1
ns_windows_takedamage 10
ns_windows_use 48
ns_windows_pev 4
ns_linux_takedamage 11
ns_linux_use 49
ns_linux_pev 4
ns_linux_classbase 0x0
; Data dated: 2007-02-23
; Version tested: 3.2 beta 2
nsp_windows_takedamage 10
nsp_windows_use 48
nsp_windows_pev 4
nsp_linux_takedamage 11
nsp_linux_use 49
nsp_linux_pev 4
nsp_linux_classbase 0x0
; Data dated: 2007-02-23
; Version tested: 1.3 (?) Steam (legitimate)
dod_windows_takedamage 18
dod_windows_use 51
dod_windows_pev 4
dod_linux_takedamage 20
dod_linux_use 51
dod linux_pev 0
dod_linux_classbase 0x154
; Data dated: 2007-02-23
; Version tested: 2.1
ts_windows_takedamage 14
ts_windows_use 48
ts_windows_pev 4
ts_linux_takedamage 16
ts_linux_use 50
ts_linux_pev 0
ts_linux_classbase 0x60
; Data dated: 2007-02-23
; Version tested: ?? (Most up to date) Steam (legitimate)
tfc_windows_takedamage 12
tfc_windows_use 44
tfc_windows_pev 4
tfc_linux_takedamage 14
tfc_linux_use 46
tfc_linux_pev 0
tfc_linux_classbase 0x470
; Data dated: 2007-02-23
; Version tested: 3.0
; Sven-Coop does not have a Linux build
svencoop_windows_takedamage 11
svencoop_windows_use 46
svencoop_windows_pev 4
; Data dated: 2007-02-26
; Version tested: 2.18.07
; Earth's Special Forces (I can't find the non beta version, but it should still work!
; ESF does not have a Linux binary!
esf_openbeta_windows_takedamage 12
esf_openbeta_windows_use 46
esf_openbeta_windows_pev 4

View File

@ -0,0 +1,132 @@
/* Ham Sandwich
*
* by sawce
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#ifndef HAMSANDWICH_H
#define HAMSANDWICH_H
#include "NEW_Util.h"
extern unsigned int HAM_pev;
extern unsigned int HAM_classbase;
inline edict_t *PrivateToEdict(const void *pdata)
{
if (!pdata)
{
return NULL;
}
char *ptr=(char*)pdata + HAM_pev;
entvars_t *pev=(entvars_t *)ptr;
if (!pev)
{
return NULL;
}
return pev->pContainingEntity;
};
inline int PrivateToIndex(const void *pdata)
{
if (pdata==NULL)
{
return -1;
}
char *ptr=(char*)pdata;
ptr+=HAM_pev;
entvars_t *pev=*(entvars_t **)ptr;
if (pev==NULL)
{
return -1;
}
if (pev->pContainingEntity==NULL)
{
return -1;
}
return ENTINDEX_NEW(pev->pContainingEntity);
};
inline int EntvarToIndex(entvars_t *pev)
{
if (pev==NULL)
{
return -1;
}
if (pev->pContainingEntity==NULL)
{
return -1;
}
return ENTINDEX_NEW(pev->pContainingEntity);
};
inline edict_t *EntvarToEdict(entvars_t *pev)
{
if (pev==NULL)
{
return NULL;
}
return pev->pContainingEntity;
};
inline void **EdictToVTable(edict_t *ent)
{
char *btbl=(char *)ent->pvPrivateData;
btbl+=HAM_classbase;
return *((void ***)btbl);
};
void RegisterKeySuffix(const char *suffix, void (*callback)(const char *,const char *));
void RegisterConfigCallback(void (*callback)(void));
void HAM_CallConfigDone(void);
void HAM_CallInitialization(void);
int HAM_StrToNum(const char *input);
bool HAM_GetKey(const char *key, const char *data);
void HAM_SetPev(const char *key, const char *data);
#ifdef __linux__
void HAM_SetClassBase(const char *key, const char *data);
#endif
#endif //HAMSANDWICH_H

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual C++ Express 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sven", "sven.vcproj", "{29798873-02F2-4075-AFE7-58CE8F9B5124}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ham sandwich", "hs.vcproj", "{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -9,10 +9,10 @@ Global
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{29798873-02F2-4075-AFE7-58CE8F9B5124}.Debug|Win32.ActiveCfg = Debug|Win32
{29798873-02F2-4075-AFE7-58CE8F9B5124}.Debug|Win32.Build.0 = Debug|Win32
{29798873-02F2-4075-AFE7-58CE8F9B5124}.Release|Win32.ActiveCfg = Release|Win32
{29798873-02F2-4075-AFE7-58CE8F9B5124}.Release|Win32.Build.0 = Release|Win32
{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}.Debug|Win32.ActiveCfg = Debug|Win32
{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}.Debug|Win32.Build.0 = Debug|Win32
{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}.Release|Win32.ActiveCfg = Release|Win32
{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -2,8 +2,9 @@
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="sven"
ProjectGUID="{29798873-02F2-4075-AFE7-58CE8F9B5124}"
Name="ham sandwich"
ProjectGUID="{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}"
RootNamespace="hamsandwich"
>
<Platforms>
<Platform
@ -37,27 +38,24 @@
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName=".\Release/sven.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SVEN_EXPORTS"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="z:\metamod\metamod;z:\hlsdk\common;z:\hlsdk\engine;z:\hlsdk\dlls;z:\hlsdk\pm_shared;.."
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ns_amxx_EXPORTS"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="false"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Release/sven.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
CompileAs="0"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@ -65,20 +63,14 @@
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1053"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile=".\Release/sven_amxx.dll"
LinkIncremental="1"
SuppressStartupBanner="true"
ModuleDefinitionFile=""
ProgramDatabaseFile=".\Release/sven.pdb"
ImportLibrary=".\Release/sven.lib"
TargetMachine="1"
OutputFile="$(OutDir)\hamsandwich_amxx.dll"
/>
<Tool
Name="VCALinkTool"
@ -120,6 +112,8 @@
/>
<Tool
Name="VCCustomBuildTool"
CommandLine="del c:\HLServer\tfc\addons\amxmodx\modules&#x0D;&#x0A;copy $(TargetDir)$(TargetFileName) c:\HLServer\tfc\addons\amxmodx\modules&#x0D;&#x0A;"
Outputs="&quot;echo lol"
/>
<Tool
Name="VCXMLDataGeneratorTool"
@ -133,24 +127,26 @@
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName=".\Debug/sven.tlb"
TypeLibraryName=".\Debug/ns_amxx.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SVEN_EXPORTS"
AdditionalIncludeDirectories="z:\metamod\metamod;z:\hlsdk\common;z:\hlsdk\engine;z:\hlsdk\dlls;z:\hlsdk\pm_shared;.."
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ns_amxx_EXPORTS"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
RuntimeLibrary="3"
RuntimeTypeInfo="false"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Debug/sven.pch"
PrecompiledHeaderFile=".\Debug/ns_amxx.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
DebugInformationFormat="3"
CompileAs="0"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@ -158,20 +154,19 @@
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1053"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="Debug/sven_amxx.dll"
OutputFile=".\Debug/hamsandwich_amxx.dll"
LinkIncremental="1"
SuppressStartupBanner="true"
ModuleDefinitionFile=""
GenerateDebugInformation="true"
ProgramDatabaseFile=".\Debug/sven_debug.pdb"
ImportLibrary=".\Debug/sven_debug.lib"
ProgramDatabaseFile=".\Debug/ns_amxx.pdb"
ImportLibrary=".\Debug/ns_amxx.lib"
TargetMachine="1"
/>
<Tool
@ -204,48 +199,69 @@
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
Name="sdk"
>
<File
RelativePath=".\amxxmodule.cpp"
RelativePath="..\sdk\amxxmodule.cpp"
>
</File>
<File
RelativePath=".\svencoop.cpp"
RelativePath="..\sdk\amxxmodule.h"
>
</File>
<File
RelativePath="..\sdk\moduleconfig.h"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
<File
RelativePath="..\amxxapi.cpp"
>
<File
RelativePath=".\amxxmodule.h"
>
</File>
<File
RelativePath=".\moduleconfig.h"
>
</File>
<File
RelativePath=".\pdata.h"
>
</File>
<File
RelativePath=".\svencoop.h"
>
</File>
<File
RelativePath=".\svencoop_const.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
</File>
<File
RelativePath="..\FileParser.cpp"
>
</Filter>
</File>
<File
RelativePath="..\FileParser.h"
>
</File>
<File
RelativePath="..\hamsandwich.h"
>
</File>
<File
RelativePath="..\Makefile"
>
</File>
<File
RelativePath="..\natives.cpp"
>
</File>
<File
RelativePath="..\NEW_Util.h"
>
</File>
<File
RelativePath="..\Trampolines.h"
>
</File>
<File
RelativePath="..\vfunc_gcc295.h"
>
</File>
<File
RelativePath="..\vfunc_msvc.h"
>
</File>
<File
RelativePath="..\vtable.cpp"
>
</File>
<File
RelativePath="..\VTableManager.h"
>
</File>
</Files>
<Globals>
</Globals>

View File

@ -0,0 +1,148 @@
#if defined _hamsandwich_included
#endinput
#endif
#define _hamsandwich_included
#if AMXX_VERSION_NUM >= 175
#pragma reqlib hamsandwich
#if !defined AMXMODX_NOAUTOLOAD
#pragma loadlib hamsandwich
#endif
#else
#pragma library hamsandwich
#endif
/**
* Ham Sandwich general usage
* -
* Mods supported:
* cs:
* * 1.6 - legimate, most up to date version
* * linux 32bit and windows
* * czero - legimate, most up to date version
* * linux 32bit and windows
* * czero untested, theoretically it should work
* dod:
* * whatever the most up to date legitimate version is (1.3?)
* * linux and windows
* * windows untested, should work
* tfc:
* * whatever most up to date legitimate version is
* * linux and windows
* * windows untested, should work
* ns:
* * 3.2 beta 2
* * linux and windows
* * windows untested, should work
* ts:
* * 2.1
* * linux and windows
* * windows untested, should work
* sven:
* * 3.0
* * windows
* * windows untested, should work
* -
* The module will automatically use the relevant function depending
* on what game mod is loaded. You only have to tell it to do the damage.
* -
* Be VERY VERY careful. I check _NO_ bounds in any of the natives
* Also, these call the game's private function, and I do not have
* the time nor desire to figure out the quirks of each mod's function
* -
* The USE natives haven't been tested yet, but should work!
* -
* The only mod I tested the windows version of takedamage
* for was cs 1.6. It's much easier for me to test linux.
*/
/**
* Calls the mod's private damage routine.
* -
* parameters:
* id: index of the entity that is to be damaged
*
* inflictor: the entity that is "doing the damage" (eg a weapon)
*
* attacker: the entity who controls the inflictor (eg weapon holder)
*
* damage: how much damage to do to the victim
*
* type: bitmask of damage flags. Most mods do not
* follow the standard HLSDK damage flags, so
* you may have to do some testing!
* The only flags I figured out were CS related:
* * (1<<6) = no slowdown on damage
* * (1<<13) = always gib
* * (1<<12) = never gib
*
* -
* Note: Setting damage to a ridiculously high value can mess up
* some mods!
*/
native hs_takedamage(id,inflictor,attacker,Float:damage,type);
native hs_etakedamage(id,inflictor,attacker,Float:damage,type);
/**
* Calls the mod's private use routine.
* -
* parameters:
* id: index of the entity that is to be used
*
* activator: the entity that is "doing the use" (eg a trigger_multiple)
*
* caller: the entity who controls the activator (eg the player who trigger the trigger_multiple)
*
* use_type: how to use the entity
* TYPICAL settings in HLSDK are:
* 0 = USE_OFF - turns the object "off"
* 1 = USE_ON - turns the object "on"
* 2 = USE_SET - sets the object use state (uses the value flag)
* 3 = USE_TOGGLE - toggles the state (from on->off and off->on)
*
* use_value: set when USE_SET is invoked
* TYPICALLY USE_SET is only used for players using an object
* when he begins using it, the use_value is set to 1.0
* when he's done using it, the use_value is set to 0.0
*
* -
* NOTE: This native was not tested at all beyond theory tests!
*/
native hs_use(id,activator,caller,use_type,Float:use_value);
native hs_euse(id,activator,caller,use_type,Float:use_value);
enum
{
HAM_UNSET = 0,
HAM_IGNORED,
HAM_HANDLED,
HAM_OVERRIDE,
HAM_SUPERCEDE
};
/**
* Forwards all takedamage routines that would occur to the given
* classname to the public provided.
*
* Parameters are:
* function(IDVictim, IDInflictor, IDAttacker, Float:Damage, DamageType)
*
* Note: For now, this will also intercept calls to hs_takedamage
* that is very likely to change shortly in the future.
*/
native register_takedamage(const classname[], const function[]);
/**
* Forwards all use routines that would occur to the given
* classname to the public provided.
*
* Parameters are:
* function(IDUsed, IDActivator, IDCaller, UseType, Float:UseValue)
*
* Note: For now, this will also intercept calls to hs_use
* that is very likely to change shortly in the future.
*/
native register_use(const classname[], const function[]);

View File

@ -0,0 +1,185 @@
/* Ham Sandwich
*
* by sawce
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "NEW_Util.h"
#include "vfunc_msvc.h"
#include "vfunc_gcc295.h"
static cell AMX_NATIVE_CALL hs_takedamage(AMX *amx, cell *params)
{
return VCall4<int>(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
HAM_Takedamage, /*vtable entry*/
HAM_Classbase, /*size of class*/
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
&(INDEXENT_NEW(params[3])->v), /*attacker*/
amx_ctof2(params[4]), /*damage*/
(int)params[5]); /*dmgtype*/
};
static cell AMX_NATIVE_CALL hs_use(AMX *amx, cell *params)
{
VoidVCall4(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
HAM_Use, /*vtable entry*/
HAM_Classbase, /*size of class*/
INDEXENT_NEW(params[2])->pvPrivateData, /*activator*/
INDEXENT_NEW(params[3])->pvPrivateData, /*caller*/
params[4], /*use type*/
amx_ctof2(params[5])); /*value*/
return 1;
}
/**
* Very fast, but potentially unsafe (if you use the wrong index/offset)
* method of converting a CBaseEntity pointer into a usable entity index
*/
static cell AMX_NATIVE_CALL hs_pdata_cbase(AMX *amx, cell *params)
{
// Get the offset of the private data
int Offset=params[2];
// If this is a linux server increase the offset
#ifdef __linux__
Offset+=params[3];
#endif
// Get the CBase pointer
int *ent=*((int **)INDEXENT_NEW(params[1])->pvPrivateData + Offset);
// Null pointer; get out
if (ent==NULL)
{
return 0;
}
// Now move up HAM_Pev bytes
char *bent=*(char**)&ent;
bent+=HAM_Pev;
entvars_t *pev=*(entvars_t **)&bent;
// Null pointer, get out
if (pev==NULL)
{
return 0;
}
return ENTINDEX_NEW(pev->pContainingEntity);
}
/**
* Slow, but very safe replacement for hs_pdata_cbase
* -
* This will scan through all entities to check their private
* data against the requested offset's data.
* It will never reference the requested PData, so unless
* the plugin author is way off with the offset it should
* never crash.
* -
* This should only be used for offset searching; NEVER
* in a release quality script.
*/
static cell AMX_NATIVE_CALL hs_pdata_cbase_safe(AMX *amx, cell *params)
{
// Get the offset of the private data
int Offset=params[2];
// If this is a linux server increase the offset
#ifdef __linux__
Offset+=params[3];
#endif
// Get the CBase pointer
int *data=*((int **)INDEXENT_NEW(params[1])->pvPrivateData + Offset);
// Get the first entity
edict_t *Entity=INDEXENT_NEW(0);
// Get the last entity
edict_t *Last=INDEXENT_NEW(gpGlobals->maxEntities);
// Scan through all of the entities (excluding 0, because no other module allows for worldspawn)
while (Entity++<Last)
{
// If this entity's private data matches the CBase pointer requested, return
if (((int *)Entity->pvPrivateData)==data)
{
return ENTINDEX_NEW(Entity);
}
}
// Not found
return 0;
}
static AMX_NATIVE_INFO reg_takedamage[] = {
{ "hs_takedamage", hs_takedamage },
{ NULL, NULL }
};
static AMX_NATIVE_INFO reg_use[] = {
{ "hs_use", hs_use },
{ NULL, NULL }
};
static AMX_NATIVE_INFO reg_cbase_fast[] = {
{ "hs_pdata_cbase", hs_pdata_cbase },
{ NULL, NULL }
};
static AMX_NATIVE_INFO reg_cbase_safe[] = {
{ "hs_pdata_cbase_safe", hs_pdata_cbase_safe },
{ NULL, NULL }
};
void HAM_RegisterTakeDamage()
{
MF_AddNatives(reg_takedamage);
}
void HAM_RegisterUse()
{
MF_AddNatives(reg_use);
}
void HAM_RegisterCbaseFast()
{
MF_AddNatives(reg_cbase_fast);
}
void HAM_RegisterCbaseSafe()
{
MF_AddNatives(reg_cbase_safe);
}

View File

@ -2430,11 +2430,14 @@ static amxx_module_info_s g_ModuleInfo =
#else // MODULE_RELOAD_ON_MAPCHANGE
0,
#endif // MODULE_RELOAD_ON_MAPCHANGE
MODULE_LOGTAG
MODULE_LOGTAG,
MODULE_LIBRARY,
MODULE_LIBCLASS
};
// Storage for the requested functions
PFN_ADD_NATIVES g_fn_AddNatives;
PFN_ADD_NEW_NATIVES g_fn_AddNewNatives;
PFN_BUILD_PATHNAME g_fn_BuildPathname;
PFN_BUILD_PATHNAME_R g_fn_BuildPathnameR;
PFN_GET_AMXADDR g_fn_GetAmxAddr;
@ -2504,6 +2507,16 @@ PFN_REQ_FNPTR g_fn_RequestFunction;
PFN_AMX_PUSH g_fn_AmxPush;
PFN_SET_TEAM_INFO g_fn_SetTeamInfo;
PFN_PLAYER_PROP_ADDR g_fn_PlayerPropAddr;
PFN_REG_AUTH_FUNC g_fn_RegAuthFunc;
PFN_UNREG_AUTH_FUNC g_fn_UnregAuthFunc;
PFN_FINDLIBRARY g_fn_FindLibrary;
PFN_ADDLIBRARIES g_fn_AddLibraries;
PFN_REMOVELIBRARIES g_fn_RemoveLibraries;
PFN_OVERRIDENATIVES g_fn_OverrideNatives;
PFN_GETLOCALINFO g_fn_GetLocalInfo;
PFN_AMX_REREGISTER g_fn_AmxReRegister;
PFN_REGISTERFUNCTIONEX g_fn_RegisterFunctionEx;
PFN_MESSAGE_BLOCK g_fn_MessageBlock;
// *** Exports ***
C_DLLEXPORT int AMXX_Query(int *interfaceVersion, amxx_module_info_s *moduleInfo)
@ -2554,6 +2567,7 @@ C_DLLEXPORT int AMXX_Attach(PFN_REQ_FNPTR reqFnptrFunc)
REQFUNC("MergeDefinitionFile", g_fn_MergeDefinition_File, PFN_MERGEDEFINITION_FILE);
REQFUNC("Format", g_fn_Format, PFN_FORMAT);
REQFUNC("RegisterFunction", g_fn_RegisterFunction, PFN_REGISTERFUNCTION);
REQFUNC("RegisterFunctionEx", g_fn_RegisterFunctionEx, PFN_REGISTERFUNCTIONEX);
// Amx scripts
REQFUNC("GetAmxScript", g_fn_GetAmxScript, PFN_GET_AMXSCRIPT);
@ -2579,6 +2593,7 @@ C_DLLEXPORT int AMXX_Attach(PFN_REQ_FNPTR reqFnptrFunc)
// Natives / Forwards
REQFUNC("AddNatives", g_fn_AddNatives, PFN_ADD_NATIVES);
REQFUNC("AddNewNatives", g_fn_AddNewNatives, PFN_ADD_NEW_NATIVES);
REQFUNC("RaiseAmxError", g_fn_RaiseAmxError, PFN_RAISE_AMXERROR);
REQFUNC("RegisterForward", g_fn_RegisterForward, PFN_REGISTER_FORWARD);
REQFUNC("RegisterSPForward", g_fn_RegisterSPForward, PFN_REGISTER_SPFORWARD);
@ -2615,6 +2630,18 @@ C_DLLEXPORT int AMXX_Attach(PFN_REQ_FNPTR reqFnptrFunc)
REQFUNC("amx_Push", g_fn_AmxPush, PFN_AMX_PUSH);
REQFUNC("SetPlayerTeamInfo", g_fn_SetTeamInfo, PFN_SET_TEAM_INFO);
REQFUNC("PlayerPropAddr", g_fn_PlayerPropAddr, PFN_PLAYER_PROP_ADDR);
REQFUNC("RegAuthFunc", g_fn_RegAuthFunc, PFN_REG_AUTH_FUNC);
REQFUNC("UnregAuthFunc", g_fn_UnregAuthFunc, PFN_UNREG_AUTH_FUNC);
//Added in 1.75
REQFUNC("FindLibrary", g_fn_FindLibrary, PFN_FINDLIBRARY);
REQFUNC("AddLibraries", g_fn_AddLibraries, PFN_ADDLIBRARIES);
REQFUNC("RemoveLibraries", g_fn_RemoveLibraries, PFN_REMOVELIBRARIES);
REQFUNC("OverrideNatives", g_fn_OverrideNatives, PFN_OVERRIDENATIVES);
REQFUNC("GetLocalInfo", g_fn_GetLocalInfo, PFN_GETLOCALINFO);
REQFUNC("AmxReregister", g_fn_AmxReRegister, PFN_AMX_REREGISTER);
REQFUNC("MessageBlock", g_fn_MessageBlock, PFN_MESSAGE_BLOCK);
#ifdef MEMORY_TEST
// Memory
@ -2650,14 +2677,27 @@ C_DLLEXPORT int AMXX_PluginsLoaded()
return AMXX_OK;
}
C_DLLEXPORT void AMXX_PluginsUnloaded()
{
#ifdef FN_AMXX_PLUGINSUNLOADED
FN_AMXX_PLUGINSUNLOADED();
#endif // FN_AMXX_PLUGINSUNLOADED
}
C_DLLEXPORT void AMXX_PluginsUnloading()
{
#ifdef FN_AMXX_PLUGINSUNLOADING
FN_AMXX_PLUGINSUNLOADING();
#endif // FN_AMXX_PLUGINSUNLOADING
}
// Advanced MF functions
void MF_Log(const char *fmt, ...)
{
// :TODO: Overflow possible here
char msg[3072];
va_list arglst;
va_start(arglst, fmt);
vsprintf(msg, fmt, arglst);
vsnprintf(msg, sizeof(msg) - 1, fmt, arglst);
va_end(arglst);
g_fn_Log("[%s] %s", MODULE_LOGTAG, msg);
@ -2665,11 +2705,10 @@ void MF_Log(const char *fmt, ...)
void MF_LogError(AMX *amx, int err, const char *fmt, ...)
{
// :TODO: Overflow possible here
char msg[3072];
va_list arglst;
va_start(arglst, fmt);
vsprintf(msg, fmt, arglst);
vsnprintf(msg, sizeof(msg) - 1, fmt, arglst);
va_end(arglst);
g_fn_LogErrorFunc(amx, err, "[%s] %s", MODULE_LOGTAG, msg);
@ -2737,8 +2776,16 @@ void ValidateMacros_DontCallThis_Smiley()
MF_GetPlayerEdict(0);
MF_Format("", 4, "str");
MF_RegisterFunction(NULL, "");
MF_RegisterFunctionEx(NULL, "");
MF_SetPlayerTeamInfo(0, 0, "");
MF_PlayerPropAddr(0, 0);
MF_RegAuthFunc(NULL);
MF_UnregAuthFunc(NULL);
MF_FindLibrary(NULL, LibType_Class);
MF_AddLibraries(NULL, LibType_Class, NULL);
MF_RemoveLibraries(NULL);
MF_OverrideNatives(NULL, NULL);
MF_MessageBlock(0, 0, NULL);
}
#endif

View File

@ -22,7 +22,7 @@
#ifndef __linux__
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define LINUX
#endif
@ -34,7 +34,8 @@
// module interface version was 1
// 2 - added logtag to struct (amxx1.1-rc1)
// 3 - added new tagAMX structure (amxx1.5)
#define AMXX_INTERFACE_VERSION 3
// 4 - added new 'library' setting for direct loading
#define AMXX_INTERFACE_VERSION 4
// amxx module info
struct amxx_module_info_s
@ -44,6 +45,8 @@ struct amxx_module_info_s
const char *version;
int reload; // reload on mapchange when nonzero
const char *logtag; // added in version 2
const char *library; // added in version 4
const char *libclass; // added in version 4
};
// return values from functions called by amxx
@ -153,9 +156,137 @@ typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx);
#endif
#if defined _MSC_VER
#pragma warning(disable:4103) /* disable warning message 4103 that complains
* about pragma pack in a header file */
#pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */
#pragma warning(disable:4103) /* disable warning message 4103 that complains
* about pragma pack in a header file */
#pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */
#if _MSC_VER >= 1400
#if !defined NO_MSVC8_AUTO_COMPAT
/* Disable deprecation warnings concerning unsafe CRT functions */
#if !defined _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
#endif
/* Replace the POSIX function with ISO C++ conformant ones as they are now deprecated */
#define access _access
#define cabs _cabs
#define cgets _cgets
#define chdir _chdir
#define chmod _chmod
#define chsize _chsize
#define close _close
#define cprintf _cprintf
#define cputs _cputts
#define creat _creat
#define cscanf _cscanf
#define cwait _cwait
#define dup _dup
#define dup2 _dup2
#define ecvt _ecvt
#define eof _eof
#define execl _execl
#define execle _execle
#define execlp _execlp
#define execlpe _execlpe
#define execv _execv
#define execve _execv
#define execvp _execvp
#define execvpe _execvpe
#define fcloseall _fcloseall
#define fcvt _fcvt
#define fdopen _fdopen
#define fgetchar _fgetchar
#define filelength _filelength
#define fileno _fileno
#define flushall _flushall
#define fputchar _fputchar
#define gcvt _gcvt
#define getch _getch
#define getche _getche
#define getcwd _getcwd
#define getpid _getpid
#define getw _getw
#define hypot _hypot
#define inp _inp
#define inpw _inpw
#define isascii __isascii
#define isatty _isatty
#define iscsym __iscsym
#define iscsymf __iscsymf
#define itoa _itoa
#define j0 _j0
#define j1 _j1
#define jn _jn
#define kbhit _kbhit
#define lfind _lfind
#define locking _locking
#define lsearch _lsearch
#define lseek _lseek
#define ltoa _ltoa
#define memccpy _memccpy
#define memicmp _memicmp
#define mkdir _mkdir
#define mktemp _mktemp
#define open _open
#define outp _outp
#define outpw _outpw
#define putch _putch
#define putenv _putenv
#define putw _putw
#define read _read
#define rmdir _rmdir
#define rmtmp _rmtmp
#define setmode _setmode
#define sopen _sopen
#define spawnl _spawnl
#define spawnle _spawnle
#define spawnlp _spawnlp
#define spawnlpe _spawnlpe
#define spawnv _spawnv
#define spawnve _spawnve
#define spawnvp _spawnvp
#define spawnvpe _spawnvpe
#define strcmpi _strcmpi
#define strdup _strdup
#define stricmp _stricmp
#define strlwr _strlwr
#define strnicmp _strnicmp
#define strnset _strnset
#define strrev _strrev
#define strset _strset
#define strupr _strupr
#define swab _swab
#define tell _tell
#define tempnam _tempnam
#define toascii __toascii
#define tzset _tzset
#define ultoa _ultoa
#define umask _umask
#define ungetch _ungetch
#define unlink _unlink
#define wcsdup _wcsdup
#define wcsicmp _wcsicmp
#define wcsicoll _wcsicoll
#define wcslwr _wcslwr
#define wcsnicmp _wcsnicmp
#define wcsnset _wcsnset
#define wcsrev _wcsrev
#define wcsset _wcsset
#define wcsupr _wcsupr
#define write _write
#define y0 _y0
#define y1 _y1
#define yn _yn
/* Disable deprecation warnings because MSVC8 seemingly thinks the ISO C++ conformant
* functions above are deprecated. */
#pragma warning (disable:4996)
#endif
#else
#define vsnprintf _vsnprintf
#endif
#endif
@ -1904,6 +2035,14 @@ void FN_AMXX_DETACH(void);
void FN_AMXX_PLUGINSLOADED(void);
#endif // FN_AMXX_PLUGINSLOADED
#ifdef FN_AMXX_PLUGINSUNLOADING
void FN_AMXX_PLUGINSUNLOADING(void);
#endif // FN_AMXX_PLUGINSUNLOADING
#ifdef FN_AMXX_PLUGINSUNLOADED
void FN_AMXX_PLUGINSUNLOADED(void);
#endif // FN_AMXX_PLUGINSUNLOADED
// *** Types ***
typedef void* (*PFN_REQ_FNPTR)(const char * /*name*/);
@ -1950,7 +2089,22 @@ enum PlayerProp
Player_NewmenuPage, //int
};
enum LibType
{
LibType_Library,
LibType_Class
};
#define MSGBLOCK_SET 0
#define MSGBLOCK_GET 1
#define BLOCK_NOT 0
#define BLOCK_ONCE 1
#define BLOCK_SET 2
typedef void (*AUTHORIZEFUNC)(int player, const char *authstring);
typedef int (*PFN_ADD_NATIVES) (const AMX_NATIVE_INFO * /*list*/);
typedef int (*PFN_ADD_NEW_NATIVES) (const AMX_NATIVE_INFO * /*list*/);
typedef char * (*PFN_BUILD_PATHNAME) (const char * /*format*/, ...);
typedef char * (*PFN_BUILD_PATHNAME_R) (char * /*buffer*/, size_t /* maxlen */, const char * /* format */, ...);
typedef cell * (*PFN_GET_AMXADDR) (AMX * /*amx*/, cell /*offset*/);
@ -2027,8 +2181,19 @@ typedef const char * (*PFN_FORMAT) (const char * /*fmt*/, ... /*params*/);
typedef void (*PFN_REGISTERFUNCTION) (void * /*pfn*/, const char * /*desc*/);
typedef int (*PFN_AMX_PUSH) (AMX * /*amx*/, cell /*value*/);
typedef int (*PFN_SET_TEAM_INFO) (int /*player */, int /*teamid */, const char * /*name */);
typedef void (*PFN_REG_AUTH_FUNC) (AUTHORIZEFUNC);
typedef void (*PFN_UNREG_AUTH_FUNC) (AUTHORIZEFUNC);
typedef int (*PFN_FINDLIBRARY) (const char * /*name*/, LibType /*type*/);
typedef size_t (*PFN_ADDLIBRARIES) (const char * /*name*/, LibType /*type*/, void * /*parent*/);
typedef size_t (*PFN_REMOVELIBRARIES) (void * /*parent*/);
typedef void (*PFN_OVERRIDENATIVES) (AMX_NATIVE_INFO * /*natives*/, const char * /*myname*/);
typedef const char * (*PFN_GETLOCALINFO) (const char * /*name*/, const char * /*def*/);
typedef int (*PFN_AMX_REREGISTER) (AMX * /*amx*/, AMX_NATIVE_INFO * /*list*/, int /*list*/);
typedef void * (*PFN_REGISTERFUNCTIONEX) (void * /*pfn*/, const char * /*desc*/);
typedef void (*PFN_MESSAGE_BLOCK) (int /* mode */, int /* message */, int * /* opt */);
extern PFN_ADD_NATIVES g_fn_AddNatives;
extern PFN_ADD_NEW_NATIVES g_fn_AddNewNatives;
extern PFN_BUILD_PATHNAME g_fn_BuildPathname;
extern PFN_BUILD_PATHNAME_R g_fn_BuildPathnameR;
extern PFN_GET_AMXADDR g_fn_GetAmxAddr;
@ -2092,11 +2257,22 @@ extern PFN_REQ_FNPTR g_fn_RequestFunction;
extern PFN_AMX_PUSH g_fn_AmxPush;
extern PFN_SET_TEAM_INFO g_fn_SetTeamInfo;
extern PFN_PLAYER_PROP_ADDR g_fn_PlayerPropAddr;
extern PFN_REG_AUTH_FUNC g_fn_RegAuthFunc;
extern PFN_UNREG_AUTH_FUNC g_fn_UnregAuthFunc;
extern PFN_FINDLIBRARY g_fn_FindLibrary;
extern PFN_ADDLIBRARIES g_fn_AddLibraries;
extern PFN_REMOVELIBRARIES g_fn_RemoveLibraries;
extern PFN_OVERRIDENATIVES g_fn_OverrideNatives;
extern PFN_GETLOCALINFO g_fn_GetLocalInfo;
extern PFN_AMX_REREGISTER g_fn_AmxReRegister;
extern PFN_REGISTERFUNCTIONEX g_fn_RegisterFunctionEx;
extern PFN_MESSAGE_BLOCK g_fn_MessageBlock;
#ifdef MAY_NEVER_BE_DEFINED
// Function prototypes for intellisense and similar systems
// They understand #if 0 so we use #ifdef MAY_NEVER_BE_DEFINED
int MF_AddNatives (const AMX_NATIVE_INFO *list) { }
int MF_AddNewNatives (const AMX_NATIVE_INFO *list) { }
char * MF_BuildPathname (const char * format, ...) { }
char * MF_BuildPathnameR (char *buffer, size_t maxlen, const char *fmt, ...) { }
cell * MF_GetAmxAddr (AMX * amx, cell offset) { }
@ -2154,9 +2330,20 @@ int MF_AmxPush (AMX *amx, cell *params) { }
int MF_AmxExec (AMX *amx, cell *retval, int idx) { }
int MF_SetPlayerTeamInfo (int id, int teamid, const char *teamname) { }
void * MF_PlayerPropAddr (int id, int prop) { }
void MF_RegAuthFunc (AUTHORIZEFUNC fn) { }
void MF_UnregAuthFunc (AUTHORIZEFUNC fn) { }
int MF_FindLibrary (const char *name, LibType type) { }
size_t MF_AddLibraries (const char *name, LibType type, void *parent) { }
size_t MF_RemoveLibraries (void *parent) { }
void MF_OverrideNatives (AMX_NATIVE_INFO *natives, const char *myname) { }
const char * MF_GetLocalInfo (const char *name, const char *def) { }
int MF_AmxReRegister (AMX *amx, AMX_NATIVE_INFO *list, int number) { return 0; }
void * MF_RegisterFunctionEx (void *pfn, const char *description) { }
void * MF_MessageBlock (int mode, int msg, int *opt) { }
#endif // MAY_NEVER_BE_DEFINED
#define MF_AddNatives g_fn_AddNatives
#define MF_AddNewNatives g_fn_AddNewNatives
#define MF_BuildPathname g_fn_BuildPathname
#define MF_BuildPathnameR g_fn_BuildPathnameR
#define MF_FormatAmxString g_fn_FormatAmxString
@ -2217,10 +2404,20 @@ void MF_LogError(AMX *amx, int err, const char *fmt, ...);
#define MF_GetPlayerEdict g_fn_GetPlayerEdict
#define MF_Format g_fn_Format
#define MF_RegisterFunction g_fn_RegisterFunction
#define MF_RequestFunction g_fn_RequestFunction;
#define MF_RequestFunction g_fn_RequestFunction
#define MF_AmxPush g_fn_AmxPush
#define MF_SetPlayerTeamInfo g_fn_SetTeamInfo
#define MF_PlayerPropAddr g_fn_PlayerPropAddr
#define MF_RegAuthFunc g_fn_RegAuthFunc
#define MF_UnregAuthFunc g_fn_UnregAuthFunc
#define MF_FindLibrary g_fn_FindLibrary
#define MF_AddLibraries g_fn_AddLibraries
#define MF_RemoveLibraries g_fn_RemoveLibraries
#define MF_OverrideNatives g_fn_OverrideNatives
#define MF_GetLocalInfo g_fn_GetLocalInfo
#define MF_AmxReRegister g_fn_AmxReRegister
#define MF_RegisterFunctionEx g_fn_RegisterFunctionEx
#define MF_MessageBlock g_fn_MessageBlock
#ifdef MEMORY_TEST
/*** Memory ***/

View File

@ -0,0 +1,491 @@
// Configuration
#ifndef __MODULECONFIG_H__
#define __MODULECONFIG_H__
// Module info
#define MODULE_NAME "Ham Sandwich"
#define MODULE_VERSION "1.77"
#define MODULE_AUTHOR "AMX Mod X Dev Team"
#define MODULE_URL "http://www.amxmodx.org"
#define MODULE_LOGTAG "HAM"
#define MODULE_LIBRARY "hamsandwich"
#define MODULE_LIBCLASS ""
// If you want the module not to be reloaded on mapchange, remove / comment out the next line
// #define MODULE_RELOAD_ON_MAPCHANGE
#ifdef __DATE__
#define MODULE_DATE __DATE__
#else // __DATE__
#define MODULE_DATE "Unknown"
#endif // __DATE__
// metamod plugin?
#define USE_METAMOD
// use memory manager/tester?
// note that if you use this, you cannot construct/allocate
// anything before the module attached (OnAmxxAttach).
// be careful of default constructors using new/malloc!
// #define MEMORY_TEST
// Unless you use STL or exceptions, keep this commented.
// It allows you to compile without libstdc++.so as a dependency
// #define NO_ALLOC_OVERRIDES
// Uncomment this if you are using MSVC8 or greater and want to fix some of the compatibility issues yourself
// #define NO_MSVC8_AUTO_COMPAT
/**
* AMXX Init functions
* Also consider using FN_META_*
*/
/** AMXX query */
//#define FN_AMXX_QUERY OnAmxxQuery
/** AMXX attach
* Do native functions init here (MF_AddNatives)
*/
#define FN_AMXX_ATTACH OnAmxxAttach
/** AMXX Detach (unload) */
//#define FN_AMXX_DETACH OnAmxxDetach
/** All plugins loaded
* Do forward functions init here (MF_RegisterForward)
*/
#define FN_AMXX_PLUGINSLOADED OnPluginsLoaded
/** All plugins are about to be unloaded */
//#define FN_AMXX_PLUGINSUNLOADING OnPluginsUnloading
/** All plugins are now unloaded */
#define FN_AMXX_PLUGINSUNLOADED OnPluginsUnloaded
/**** METAMOD ****/
// If your module doesn't use metamod, you may close the file now :)
#ifdef USE_METAMOD
// ----
// Hook Functions
// Uncomment these to be called
// You can also change the function name
// - Metamod init functions
// Also consider using FN_AMXX_*
// Meta query
//#define FN_META_QUERY OnMetaQuery
// Meta attach
//#define FN_META_ATTACH OnMetaAttach
// Meta detach
//#define FN_META_DETACH OnMetaDetach
// (wd) are Will Day's notes
// - GetEntityAPI2 functions
// #define FN_GameDLLInit GameDLLInit /* pfnGameInit() */
//#define FN_DispatchSpawn DispatchSpawn /* pfnSpawn() */
// #define FN_DispatchThink DispatchThink /* pfnThink() */
// #define FN_DispatchUse DispatchUse /* pfnUse() */
// #define FN_DispatchTouch DispatchTouch /* pfnTouch() */
// #define FN_DispatchBlocked DispatchBlocked /* pfnBlocked() */
//#define FN_DispatchKeyValue DispatchKeyValue /* pfnKeyValue() */
// #define FN_DispatchSave DispatchSave /* pfnSave() */
// #define FN_DispatchRestore DispatchRestore /* pfnRestore() */
// #define FN_DispatchObjectCollsionBox DispatchObjectCollsionBox /* pfnSetAbsBox() */
// #define FN_SaveWriteFields SaveWriteFields /* pfnSaveWriteFields() */
// #define FN_SaveReadFields SaveReadFields /* pfnSaveReadFields() */
// #define FN_SaveGlobalState SaveGlobalState /* pfnSaveGlobalState() */
// #define FN_RestoreGlobalState RestoreGlobalState /* pfnRestoreGlobalState() */
// #define FN_ResetGlobalState ResetGlobalState /* pfnResetGlobalState() */
//#define FN_ClientConnect ClientConnect /* pfnClientConnect() (wd) Client has connected */
//#define FN_ClientDisconnect ClientDisconnect /* pfnClientDisconnect() (wd) Player has left the game */
// #define FN_ClientKill ClientKill /* pfnClientKill() (wd) Player has typed "kill" */
// #define FN_ClientPutInServer ClientPutInServer /* pfnClientPutInServer() (wd) Client is entering the game */
// #define FN_ClientCommand ClientCommand /* pfnClientCommand() (wd) Player has sent a command (typed or from a bind) */
// #define FN_ClientUserInfoChanged ClientUserInfoChanged /* pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure */
//#define FN_ServerActivate ServerActivate /* pfnServerActivate() (wd) Server is starting a new map */
//#define FN_ServerDeactivate ServerDeactivate /* pfnServerDeactivate() (wd) Server is leaving the map (shutdown or changelevel); SDK2 */
// #define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */
// #define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */
// #define FN_StartFrame StartFrame /* pfnStartFrame() */
// #define FN_ParmsNewLevel ParmsNewLevel /* pfnParmsNewLevel() */
// #define FN_ParmsChangeLevel ParmsChangeLevel /* pfnParmsChangeLevel() */
// #define FN_GetGameDescription GetGameDescription /* pfnGetGameDescription() Returns string describing current .dll. E.g. "TeamFotrress 2" "Half-Life" */
// #define FN_PlayerCustomization PlayerCustomization /* pfnPlayerCustomization() Notifies .dll of new customization for player. */
// #define FN_SpectatorConnect SpectatorConnect /* pfnSpectatorConnect() Called when spectator joins server */
// #define FN_SpectatorDisconnect SpectatorDisconnect /* pfnSpectatorDisconnect() Called when spectator leaves the server */
// #define FN_SpectatorThink SpectatorThink /* pfnSpectatorThink() Called when spectator sends a command packet (usercmd_t) */
// #define FN_Sys_Error Sys_Error /* pfnSys_Error() Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. SDK2 */
// #define FN_PM_Move PM_Move /* pfnPM_Move() (wd) SDK2 */
// #define FN_PM_Init PM_Init /* pfnPM_Init() Server version of player movement initialization; (wd) SDK2 */
// #define FN_PM_FindTextureType PM_FindTextureType /* pfnPM_FindTextureType() (wd) SDK2 */
// #define FN_SetupVisibility SetupVisibility /* pfnSetupVisibility() Set up PVS and PAS for networking for this client; (wd) SDK2 */
// #define FN_UpdateClientData UpdateClientData /* pfnUpdateClientData() Set up data sent only to specific client; (wd) SDK2 */
// #define FN_AddToFullPack AddToFullPack /* pfnAddToFullPack() (wd) SDK2 */
// #define FN_CreateBaseline CreateBaseline /* pfnCreateBaseline() Tweak entity baseline for network encoding allows setup of player baselines too.; (wd) SDK2 */
// #define FN_RegisterEncoders RegisterEncoders /* pfnRegisterEncoders() Callbacks for network encoding; (wd) SDK2 */
// #define FN_GetWeaponData GetWeaponData /* pfnGetWeaponData() (wd) SDK2 */
// #define FN_CmdStart CmdStart /* pfnCmdStart() (wd) SDK2 */
// #define FN_CmdEnd CmdEnd /* pfnCmdEnd() (wd) SDK2 */
// #define FN_ConnectionlessPacket ConnectionlessPacket /* pfnConnectionlessPacket() (wd) SDK2 */
// #define FN_GetHullBounds GetHullBounds /* pfnGetHullBounds() (wd) SDK2 */
// #define FN_CreateInstancedBaselines CreateInstancedBaselines /* pfnCreateInstancedBaselines() (wd) SDK2 */
// #define FN_InconsistentFile InconsistentFile /* pfnInconsistentFile() (wd) SDK2 */
// #define FN_AllowLagCompensation AllowLagCompensation /* pfnAllowLagCompensation() (wd) SDK2 */
// - GetEntityAPI2_Post functions
// #define FN_GameDLLInit_Post GameDLLInit_Post
// #define FN_DispatchSpawn_Post DispatchSpawn_Post
// #define FN_DispatchThink_Post DispatchThink_Post
// #define FN_DispatchUse_Post DispatchUse_Post
// #define FN_DispatchTouch_Post DispatchTouch_Post
// #define FN_DispatchBlocked_Post DispatchBlocked_Post
// #define FN_DispatchKeyValue_Post DispatchKeyValue_Post
// #define FN_DispatchSave_Post DispatchSave_Post
// #define FN_DispatchRestore_Post DispatchRestore_Post
// #define FN_DispatchObjectCollsionBox_Post DispatchObjectCollsionBox_Post
// #define FN_SaveWriteFields_Post SaveWriteFields_Post
// #define FN_SaveReadFields_Post SaveReadFields_Post
// #define FN_SaveGlobalState_Post SaveGlobalState_Post
// #define FN_RestoreGlobalState_Post RestoreGlobalState_Post
// #define FN_ResetGlobalState_Post ResetGlobalState_Post
// #define FN_ClientConnect_Post ClientConnect_Post
// #define FN_ClientDisconnect_Post ClientDisconnect_Post
// #define FN_ClientKill_Post ClientKill_Post
// #define FN_ClientPutInServer_Post ClientPutInServer_Post
// #define FN_ClientCommand_Post ClientCommand_Post
// #define FN_ClientUserInfoChanged_Post ClientUserInfoChanged_Post
//#define FN_ServerActivate_Post ServerActivate_Post
// #define FN_ServerDeactivate_Post ServerDeactivate_Post
// #define FN_PlayerPreThink_Post PlayerPreThink_Post
// #define FN_PlayerPostThink_Post PlayerPostThink_Post
// #define FN_StartFrame_Post StartFrame_Post
// #define FN_ParmsNewLevel_Post ParmsNewLevel_Post
// #define FN_ParmsChangeLevel_Post ParmsChangeLevel_Post
// #define FN_GetGameDescription_Post GetGameDescription_Post
// #define FN_PlayerCustomization_Post PlayerCustomization_Post
// #define FN_SpectatorConnect_Post SpectatorConnect_Post
// #define FN_SpectatorDisconnect_Post SpectatorDisconnect_Post
// #define FN_SpectatorThink_Post SpectatorThink_Post
// #define FN_Sys_Error_Post Sys_Error_Post
// #define FN_PM_Move_Post PM_Move_Post
// #define FN_PM_Init_Post PM_Init_Post
// #define FN_PM_FindTextureType_Post PM_FindTextureType_Post
// #define FN_SetupVisibility_Post SetupVisibility_Post
// #define FN_UpdateClientData_Post UpdateClientData_Post
// #define FN_AddToFullPack_Post AddToFullPack_Post
// #define FN_CreateBaseline_Post CreateBaseline_Post
// #define FN_RegisterEncoders_Post RegisterEncoders_Post
// #define FN_GetWeaponData_Post GetWeaponData_Post
// #define FN_CmdStart_Post CmdStart_Post
// #define FN_CmdEnd_Post CmdEnd_Post
// #define FN_ConnectionlessPacket_Post ConnectionlessPacket_Post
// #define FN_GetHullBounds_Post GetHullBounds_Post
// #define FN_CreateInstancedBaselines_Post CreateInstancedBaselines_Post
// #define FN_InconsistentFile_Post InconsistentFile_Post
// #define FN_AllowLagCompensation_Post AllowLagCompensation_Post
// - GetEngineAPI functions
// #define FN_PrecacheModel PrecacheModel
// #define FN_PrecacheSound PrecacheSound
// #define FN_SetModel SetModel
// #define FN_ModelIndex ModelIndex
// #define FN_ModelFrames ModelFrames
// #define FN_SetSize SetSize
// #define FN_ChangeLevel ChangeLevel
// #define FN_GetSpawnParms GetSpawnParms
// #define FN_SaveSpawnParms SaveSpawnParms
// #define FN_VecToYaw VecToYaw
// #define FN_VecToAngles VecToAngles
// #define FN_MoveToOrigin MoveToOrigin
// #define FN_ChangeYaw ChangeYaw
// #define FN_ChangePitch ChangePitch
// #define FN_FindEntityByString FindEntityByString
// #define FN_GetEntityIllum GetEntityIllum
// #define FN_FindEntityInSphere FindEntityInSphere
// #define FN_FindClientInPVS FindClientInPVS
// #define FN_EntitiesInPVS EntitiesInPVS
// #define FN_MakeVectors MakeVectors
// #define FN_AngleVectors AngleVectors
// #define FN_CreateEntity CreateEntity
// #define FN_RemoveEntity RemoveEntity
// #define FN_CreateNamedEntity CreateNamedEntity
// #define FN_MakeStatic MakeStatic
// #define FN_EntIsOnFloor EntIsOnFloor
// #define FN_DropToFloor DropToFloor
// #define FN_WalkMove WalkMove
// #define FN_SetOrigin SetOrigin
// #define FN_EmitSound EmitSound
// #define FN_EmitAmbientSound EmitAmbientSound
// #define FN_TraceLine TraceLine
// #define FN_TraceToss TraceToss
// #define FN_TraceMonsterHull TraceMonsterHull
// #define FN_TraceHull TraceHull
// #define FN_TraceModel TraceModel
// #define FN_TraceTexture TraceTexture
// #define FN_TraceSphere TraceSphere
// #define FN_GetAimVector GetAimVector
// #define FN_ServerCommand ServerCommand
// #define FN_ServerExecute ServerExecute
// #define FN_engClientCommand engClientCommand
// #define FN_ParticleEffect ParticleEffect
// #define FN_LightStyle LightStyle
// #define FN_DecalIndex DecalIndex
// #define FN_PointContents PointContents
// #define FN_MessageBegin MessageBegin
// #define FN_MessageEnd MessageEnd
// #define FN_WriteByte WriteByte
// #define FN_WriteChar WriteChar
// #define FN_WriteShort WriteShort
// #define FN_WriteLong WriteLong
// #define FN_WriteAngle WriteAngle
// #define FN_WriteCoord WriteCoord
// #define FN_WriteString WriteString
// #define FN_WriteEntity WriteEntity
// #define FN_CVarRegister CVarRegister
// #define FN_CVarGetFloat CVarGetFloat
// #define FN_CVarGetString CVarGetString
// #define FN_CVarSetFloat CVarSetFloat
// #define FN_CVarSetString CVarSetString
// #define FN_AlertMessage AlertMessage
// #define FN_EngineFprintf EngineFprintf
// #define FN_PvAllocEntPrivateData PvAllocEntPrivateData
// #define FN_PvEntPrivateData PvEntPrivateData
// #define FN_FreeEntPrivateData FreeEntPrivateData
// #define FN_SzFromIndex SzFromIndex
// #define FN_AllocString AllocString
// #define FN_GetVarsOfEnt GetVarsOfEnt
// #define FN_PEntityOfEntOffset PEntityOfEntOffset
// #define FN_EntOffsetOfPEntity EntOffsetOfPEntity
// #define FN_IndexOfEdict IndexOfEdict
// #define FN_PEntityOfEntIndex PEntityOfEntIndex
// #define FN_FindEntityByVars FindEntityByVars
// #define FN_GetModelPtr GetModelPtr
// #define FN_RegUserMsg RegUserMsg
// #define FN_AnimationAutomove AnimationAutomove
// #define FN_GetBonePosition GetBonePosition
// #define FN_FunctionFromName FunctionFromName
// #define FN_NameForFunction NameForFunction
// #define FN_ClientPrintf ClientPrintf
// #define FN_ServerPrint ServerPrint
// #define FN_Cmd_Args Cmd_Args
// #define FN_Cmd_Argv Cmd_Argv
// #define FN_Cmd_Argc Cmd_Argc
// #define FN_GetAttachment GetAttachment
// #define FN_CRC32_Init CRC32_Init
// #define FN_CRC32_ProcessBuffer CRC32_ProcessBuffer
// #define FN_CRC32_ProcessByte CRC32_ProcessByte
// #define FN_CRC32_Final CRC32_Final
// #define FN_RandomLong RandomLong
// #define FN_RandomFloat RandomFloat
// #define FN_SetView SetView
// #define FN_Time Time
// #define FN_CrosshairAngle CrosshairAngle
// #define FN_LoadFileForMe LoadFileForMe
// #define FN_FreeFile FreeFile
// #define FN_EndSection EndSection
// #define FN_CompareFileTime CompareFileTime
// #define FN_GetGameDir GetGameDir
// #define FN_Cvar_RegisterVariable Cvar_RegisterVariable
// #define FN_FadeClientVolume FadeClientVolume
// #define FN_SetClientMaxspeed SetClientMaxspeed
// #define FN_CreateFakeClient CreateFakeClient
// #define FN_RunPlayerMove RunPlayerMove
// #define FN_NumberOfEntities NumberOfEntities
// #define FN_GetInfoKeyBuffer GetInfoKeyBuffer
// #define FN_InfoKeyValue InfoKeyValue
// #define FN_SetKeyValue SetKeyValue
// #define FN_SetClientKeyValue SetClientKeyValue
// #define FN_IsMapValid IsMapValid
// #define FN_StaticDecal StaticDecal
// #define FN_PrecacheGeneric PrecacheGeneric
// #define FN_GetPlayerUserId GetPlayerUserId
// #define FN_BuildSoundMsg BuildSoundMsg
// #define FN_IsDedicatedServer IsDedicatedServer
// #define FN_CVarGetPointer CVarGetPointer
// #define FN_GetPlayerWONId GetPlayerWONId
// #define FN_Info_RemoveKey Info_RemoveKey
// #define FN_GetPhysicsKeyValue GetPhysicsKeyValue
// #define FN_SetPhysicsKeyValue SetPhysicsKeyValue
// #define FN_GetPhysicsInfoString GetPhysicsInfoString
// #define FN_PrecacheEvent PrecacheEvent
// #define FN_PlaybackEvent PlaybackEvent
// #define FN_SetFatPVS SetFatPVS
// #define FN_SetFatPAS SetFatPAS
// #define FN_CheckVisibility CheckVisibility
// #define FN_DeltaSetField DeltaSetField
// #define FN_DeltaUnsetField DeltaUnsetField
// #define FN_DeltaAddEncoder DeltaAddEncoder
// #define FN_GetCurrentPlayer GetCurrentPlayer
// #define FN_CanSkipPlayer CanSkipPlayer
// #define FN_DeltaFindField DeltaFindField
// #define FN_DeltaSetFieldByIndex DeltaSetFieldByIndex
// #define FN_DeltaUnsetFieldByIndex DeltaUnsetFieldByIndex
// #define FN_SetGroupMask SetGroupMask
// #define FN_engCreateInstancedBaseline engCreateInstancedBaseline
// #define FN_Cvar_DirectSet Cvar_DirectSet
// #define FN_ForceUnmodified ForceUnmodified
// #define FN_GetPlayerStats GetPlayerStats
// #define FN_AddServerCommand AddServerCommand
// #define FN_Voice_GetClientListening Voice_GetClientListening
// #define FN_Voice_SetClientListening Voice_SetClientListening
// #define FN_GetPlayerAuthId GetPlayerAuthId
// - GetEngineAPI_Post functions
// #define FN_PrecacheModel_Post PrecacheModel_Post
// #define FN_PrecacheSound_Post PrecacheSound_Post
// #define FN_SetModel_Post SetModel_Post
// #define FN_ModelIndex_Post ModelIndex_Post
// #define FN_ModelFrames_Post ModelFrames_Post
// #define FN_SetSize_Post SetSize_Post
// #define FN_ChangeLevel_Post ChangeLevel_Post
// #define FN_GetSpawnParms_Post GetSpawnParms_Post
// #define FN_SaveSpawnParms_Post SaveSpawnParms_Post
// #define FN_VecToYaw_Post VecToYaw_Post
// #define FN_VecToAngles_Post VecToAngles_Post
// #define FN_MoveToOrigin_Post MoveToOrigin_Post
// #define FN_ChangeYaw_Post ChangeYaw_Post
// #define FN_ChangePitch_Post ChangePitch_Post
// #define FN_FindEntityByString_Post FindEntityByString_Post
// #define FN_GetEntityIllum_Post GetEntityIllum_Post
// #define FN_FindEntityInSphere_Post FindEntityInSphere_Post
// #define FN_FindClientInPVS_Post FindClientInPVS_Post
// #define FN_EntitiesInPVS_Post EntitiesInPVS_Post
// #define FN_MakeVectors_Post MakeVectors_Post
// #define FN_AngleVectors_Post AngleVectors_Post
// #define FN_CreateEntity_Post CreateEntity_Post
// #define FN_RemoveEntity_Post RemoveEntity_Post
// #define FN_CreateNamedEntity_Post CreateNamedEntity_Post
// #define FN_MakeStatic_Post MakeStatic_Post
// #define FN_EntIsOnFloor_Post EntIsOnFloor_Post
// #define FN_DropToFloor_Post DropToFloor_Post
// #define FN_WalkMove_Post WalkMove_Post
// #define FN_SetOrigin_Post SetOrigin_Post
// #define FN_EmitSound_Post EmitSound_Post
// #define FN_EmitAmbientSound_Post EmitAmbientSound_Post
// #define FN_TraceLine_Post TraceLine_Post
// #define FN_TraceToss_Post TraceToss_Post
// #define FN_TraceMonsterHull_Post TraceMonsterHull_Post
// #define FN_TraceHull_Post TraceHull_Post
// #define FN_TraceModel_Post TraceModel_Post
// #define FN_TraceTexture_Post TraceTexture_Post
// #define FN_TraceSphere_Post TraceSphere_Post
// #define FN_GetAimVector_Post GetAimVector_Post
// #define FN_ServerCommand_Post ServerCommand_Post
// #define FN_ServerExecute_Post ServerExecute_Post
// #define FN_engClientCommand_Post engClientCommand_Post
// #define FN_ParticleEffect_Post ParticleEffect_Post
// #define FN_LightStyle_Post LightStyle_Post
// #define FN_DecalIndex_Post DecalIndex_Post
// #define FN_PointContents_Post PointContents_Post
// #define FN_MessageBegin_Post MessageBegin_Post
// #define FN_MessageEnd_Post MessageEnd_Post
// #define FN_WriteByte_Post WriteByte_Post
// #define FN_WriteChar_Post WriteChar_Post
// #define FN_WriteShort_Post WriteShort_Post
// #define FN_WriteLong_Post WriteLong_Post
// #define FN_WriteAngle_Post WriteAngle_Post
// #define FN_WriteCoord_Post WriteCoord_Post
// #define FN_WriteString_Post WriteString_Post
// #define FN_WriteEntity_Post WriteEntity_Post
// #define FN_CVarRegister_Post CVarRegister_Post
// #define FN_CVarGetFloat_Post CVarGetFloat_Post
// #define FN_CVarGetString_Post CVarGetString_Post
// #define FN_CVarSetFloat_Post CVarSetFloat_Post
// #define FN_CVarSetString_Post CVarSetString_Post
// #define FN_AlertMessage_Post AlertMessage_Post
// #define FN_EngineFprintf_Post EngineFprintf_Post
// #define FN_PvAllocEntPrivateData_Post PvAllocEntPrivateData_Post
// #define FN_PvEntPrivateData_Post PvEntPrivateData_Post
// #define FN_FreeEntPrivateData_Post FreeEntPrivateData_Post
// #define FN_SzFromIndex_Post SzFromIndex_Post
// #define FN_AllocString_Post AllocString_Post
// #define FN_GetVarsOfEnt_Post GetVarsOfEnt_Post
// #define FN_PEntityOfEntOffset_Post PEntityOfEntOffset_Post
// #define FN_EntOffsetOfPEntity_Post EntOffsetOfPEntity_Post
// #define FN_IndexOfEdict_Post IndexOfEdict_Post
// #define FN_PEntityOfEntIndex_Post PEntityOfEntIndex_Post
// #define FN_FindEntityByVars_Post FindEntityByVars_Post
// #define FN_GetModelPtr_Post GetModelPtr_Post
// #define FN_RegUserMsg_Post RegUserMsg_Post
// #define FN_AnimationAutomove_Post AnimationAutomove_Post
// #define FN_GetBonePosition_Post GetBonePosition_Post
// #define FN_FunctionFromName_Post FunctionFromName_Post
// #define FN_NameForFunction_Post NameForFunction_Post
// #define FN_ClientPrintf_Post ClientPrintf_Post
// #define FN_ServerPrint_Post ServerPrint_Post
// #define FN_Cmd_Args_Post Cmd_Args_Post
// #define FN_Cmd_Argv_Post Cmd_Argv_Post
// #define FN_Cmd_Argc_Post Cmd_Argc_Post
// #define FN_GetAttachment_Post GetAttachment_Post
// #define FN_CRC32_Init_Post CRC32_Init_Post
// #define FN_CRC32_ProcessBuffer_Post CRC32_ProcessBuffer_Post
// #define FN_CRC32_ProcessByte_Post CRC32_ProcessByte_Post
// #define FN_CRC32_Final_Post CRC32_Final_Post
// #define FN_RandomLong_Post RandomLong_Post
// #define FN_RandomFloat_Post RandomFloat_Post
// #define FN_SetView_Post SetView_Post
// #define FN_Time_Post Time_Post
// #define FN_CrosshairAngle_Post CrosshairAngle_Post
// #define FN_LoadFileForMe_Post LoadFileForMe_Post
// #define FN_FreeFile_Post FreeFile_Post
// #define FN_EndSection_Post EndSection_Post
// #define FN_CompareFileTime_Post CompareFileTime_Post
// #define FN_GetGameDir_Post GetGameDir_Post
// #define FN_Cvar_RegisterVariable_Post Cvar_RegisterVariable_Post
// #define FN_FadeClientVolume_Post FadeClientVolume_Post
// #define FN_SetClientMaxspeed_Post SetClientMaxspeed_Post
// #define FN_CreateFakeClient_Post CreateFakeClient_Post
// #define FN_RunPlayerMove_Post RunPlayerMove_Post
// #define FN_NumberOfEntities_Post NumberOfEntities_Post
// #define FN_GetInfoKeyBuffer_Post GetInfoKeyBuffer_Post
// #define FN_InfoKeyValue_Post InfoKeyValue_Post
// #define FN_SetKeyValue_Post SetKeyValue_Post
// #define FN_SetClientKeyValue_Post SetClientKeyValue_Post
// #define FN_IsMapValid_Post IsMapValid_Post
// #define FN_StaticDecal_Post StaticDecal_Post
// #define FN_PrecacheGeneric_Post PrecacheGeneric_Post
// #define FN_GetPlayerUserId_Post GetPlayerUserId_Post
// #define FN_BuildSoundMsg_Post BuildSoundMsg_Post
// #define FN_IsDedicatedServer_Post IsDedicatedServer_Post
// #define FN_CVarGetPointer_Post CVarGetPointer_Post
// #define FN_GetPlayerWONId_Post GetPlayerWONId_Post
// #define FN_Info_RemoveKey_Post Info_RemoveKey_Post
// #define FN_GetPhysicsKeyValue_Post GetPhysicsKeyValue_Post
// #define FN_SetPhysicsKeyValue_Post SetPhysicsKeyValue_Post
// #define FN_GetPhysicsInfoString_Post GetPhysicsInfoString_Post
//#define FN_PrecacheEvent_Post PrecacheEvent_Post
// #define FN_PlaybackEvent_Post PlaybackEvent_Post
// #define FN_SetFatPVS_Post SetFatPVS_Post
// #define FN_SetFatPAS_Post SetFatPAS_Post
// #define FN_CheckVisibility_Post CheckVisibility_Post
// #define FN_DeltaSetField_Post DeltaSetField_Post
// #define FN_DeltaUnsetField_Post DeltaUnsetField_Post
// #define FN_DeltaAddEncoder_Post DeltaAddEncoder_Post
// #define FN_GetCurrentPlayer_Post GetCurrentPlayer_Post
// #define FN_CanSkipPlayer_Post CanSkipPlayer_Post
// #define FN_DeltaFindField_Post DeltaFindField_Post
// #define FN_DeltaSetFieldByIndex_Post DeltaSetFieldByIndex_Post
// #define FN_DeltaUnsetFieldByIndex_Post DeltaUnsetFieldByIndex_Post
// #define FN_SetGroupMask_Post SetGroupMask_Post
// #define FN_engCreateInstancedBaseline_Post engCreateInstancedBaseline_Post
// #define FN_Cvar_DirectSet_Post Cvar_DirectSet_Post
// #define FN_ForceUnmodified_Post ForceUnmodified_Post
// #define FN_GetPlayerStats_Post GetPlayerStats_Post
// #define FN_AddServerCommand_Post AddServerCommand_Post
// #define FN_Voice_GetClientListening_Post Voice_GetClientListening_Post
// #define FN_Voice_SetClientListening_Post Voice_SetClientListening_Post
// #define FN_GetPlayerAuthId_Post GetPlayerAuthId_Post
// #define FN_OnFreeEntPrivateData OnFreeEntPrivateData
// #define FN_GameShutdown GameShutdown
// #define FN_ShouldCollide ShouldCollide
// #define FN_OnFreeEntPrivateData_Post OnFreeEntPrivateData_Post
// #define FN_GameShutdown_Post GameShutdown_Post
// #define FN_ShouldCollide_Post ShouldCollide_Post
#endif // USE_METAMOD
#endif // __MODULECONFIG_H__

View File

@ -0,0 +1,280 @@
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "vfunc_gcc295.h"
#include "vfunc_msvc.h"
#include "NEW_Util.h"
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableBlocked
#define ThisEntries BlockedEntries
#define ThisHook VHOOK_Blocked
unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL;
unsigned int *ThisVTable::baseoffset=NULL;
unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO registernatives[] = {
{ "register_blocked", ThisVTable::RegisterNative },
{ NULL, NULL }
};
static AMX_NATIVE_INFO callnatives[] = {
{ "hs_blocked", ThisVTable::NativeCall },
{ "hs_eblocked", ThisVTable::ENativeCall },
{ NULL, NULL }
};
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
{
ThisVTable::pevoffset=poffset;
ThisVTable::pevset=pset;
ThisVTable::baseoffset=baseoffs;
ThisVTable::baseset=baseset;
ThisVTable::index=0;
ThisVTable::indexset=0;
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix("blocked",ThisVTable::KeyValue);
};
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,"blocked")==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
}
};
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
void ThisVTable::ConfigDone(void)
{
if (ThisVTable::indexset && *(ThisVTable::baseset))
{
MF_AddNatives(callnatives);
if (*(ThisVTable::pevset))
{
MF_AddNatives(registernatives);
}
}
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
// create an entity, assign it the gamedll's class, hook it and destroy it
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::NativeCall(AMX *amx, cell *params)
{
// TODO: This
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
{
VoidVCall1(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
);
return 1;
};
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
{
VTableEntryBase::CreateGenericTrampoline(manager,
vtable,
ThisVTable::index,
id,
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisHook),
1, // param count
1, // voidcall
1); // thiscall
};
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid)
{
void *ptr=vtable[ThisVTable::index];
int i=0;
int end=manager->ThisEntries.size();
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*other*/,FP_DONE);
while (i<end)
{
if (manager->ThisEntries[i]->IsTrampoline(ptr))
{
// this function is already hooked!
manager->ThisEntries[i]->AddForward(fwd);
return;
}
++i;
}
// this function is NOT hooked
void *tramp;
void *func;
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
ThisVTable *entry=new ThisVTable;
entry->Setup(&vtable[ThisVTable::index],tramp,func);
manager->ThisEntries.push_back(entry);
entry->AddForward(fwd);
}
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param activator Entity causing the opening.
* @param caller Entity controlling the caller.
* @param type USE_TYPE (USE_{ON,OFF,SET}
* @param value Use value, only seen set when USE_SET is used.
* @noreturn
*/
void ThisVTable::Execute(void *pthis, void *other)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
int iOther=PrivateToIndex(other);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iOther);
if (thisresult>result)
{
result=thisresult;
}
};
if (result>=HAM_SUPERCEDE)
{
return;
}
#if defined _WIN32
reinterpret_cast<void (__fastcall *)(void *,int, void *)>(function)(pthis,0,other);
#elif defined __linux__
reinterpret_cast<void (*)(void *,void *)>(function)(pthis,other);
#endif
};

View File

@ -0,0 +1,322 @@
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "hooks.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "vfunc_gcc295.h"
#include "vfunc_msvc.h"
#include "NEW_Util.h"
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableTakeDamage
#define ThisEntries TakeDamageEntries
#define ThisHook VHOOK_TakeDamage
unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL;
unsigned int *ThisVTable::baseoffset=NULL;
unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO registernatives[] = {
{ "register_takedamage", ThisVTable::RegisterNative },
{ NULL, NULL }
};
static AMX_NATIVE_INFO callnatives[] = {
{ "hs_takedamage", ThisVTable::NativeCall },
{ "hs_etakedamage", ThisVTable::ENativeCall },
{ NULL, NULL }
};
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
{
ThisVTable::pevoffset=poffset;
ThisVTable::pevset=pset;
ThisVTable::baseoffset=baseoffs;
ThisVTable::baseset=baseset;
ThisVTable::index=0;
ThisVTable::indexset=0;
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix("takedamage",ThisVTable::KeyValue);
};
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,"takedamage")==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
}
};
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
void ThisVTable::ConfigDone(void)
{
if (ThisVTable::indexset && *(ThisVTable::baseset))
{
MF_AddNatives(callnatives);
if (*(ThisVTable::pevset))
{
MF_AddNatives(registernatives);
}
}
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
// create an entity, assign it the gamedll's class, hook it and destroy it
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::NativeCall(AMX *amx, cell *params)
{
// scan to see if this virtual function is a trampoline
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
int i=0;
int end=VTMan.ThisEntries.size();
while (i<end)
{
if (VTMan.ThisEntries[i]->IsTrampoline(func))
{
// this function is a trampoline
// use the original function instead
func=VTMan.ThisEntries[i]->GetOriginalFunction();
break;
}
++i;
}
// TODO: Inline ASM this
#ifdef _WIN32
return reinterpret_cast<int (__fastcall *)(void *,int,void *,void *,float,int)>(func)(
pthis, /*this*/
0, /*fastcall buffer*/
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
&(INDEXENT_NEW(params[3])->v), /*attacker*/
amx_ctof2(params[4]), /*damage*/
(int)params[5] /*dmgtype*/
);
#else
return reinterpret_cast<int (*)(void *,void *,void *,float,int)>(func)(
pthis, /*this*/
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
&(INDEXENT_NEW(params[3])->v), /*attacker*/
amx_ctof2(params[4]), /*damage*/
(int)params[5] /*dmgtype*/
);
#endif
};
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
{
return VCall4<int>(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
&(INDEXENT_NEW(params[3])->v), /*attacker*/
amx_ctof2(params[4]), /*damage*/
(int)params[5] /*dmgtype*/
);
};
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
{
VTableEntryBase::CreateGenericTrampoline(manager,
vtable,
ThisVTable::index,
id,
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisHook),
4, // param count
0, // voidcall
1); // thiscall
};
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid)
{
void *ptr=vtable[ThisVTable::index];
int i=0;
int end=manager->ThisEntries.size();
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*inflictor*/,FP_CELL/*attacker*/,FP_CELL/*damage*/,FP_CELL/*type*/,FP_DONE);
while (i<end)
{
if (manager->ThisEntries[i]->IsTrampoline(ptr))
{
// this function is already hooked!
manager->ThisEntries[i]->AddForward(fwd);
return;
}
++i;
}
// this function is NOT hooked
void *tramp;
void *func;
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
ThisVTable *entry=new ThisVTable;
entry->Setup(&vtable[ThisVTable::index],tramp,func);
manager->ThisEntries.push_back(entry);
entry->AddForward(fwd);
}
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param inflictor Damage inflictor.
* @param attacker The attacker who caused the inflictor to damage the victim.
* @param damage How much damage was caused.
* @param type Damage type (usually in bitmask form).
* @return Unsure. Does not appear to be used.
*/
int ThisVTable::Execute(void *pthis, void *inflictor, void *attacker, float damage, int type)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
int iInflictor=EntvarToIndex((entvars_t *)inflictor);
int iAttacker=EntvarToIndex((entvars_t *)attacker);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iInflictor,iAttacker,amx_ftoc2(damage),type);
if (thisresult>result)
{
result=thisresult;
}
};
// stop here
if (result>=HAM_SUPERCEDE)
{
return 0;
}
#if defined _WIN32
int ireturn=reinterpret_cast<int (__fastcall *)(void *,int,void *,void *,float,int)>(function)(pthis,0,inflictor,attacker,damage,type);
#elif defined __linux__
int ireturn=reinterpret_cast<int (*)(void *,void *,void *,float,int)>(function)(pthis,inflictor,attacker,damage,type);
#endif
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};

View File

@ -0,0 +1,282 @@
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "vfunc_gcc295.h"
#include "vfunc_msvc.h"
#include "NEW_Util.h"
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableUse
#define ThisEntries UseEntries
#define ThisHook VHOOK_Use
unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL;
unsigned int *ThisVTable::baseoffset=NULL;
unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO registernatives[] = {
{ "register_use", ThisVTable::RegisterNative },
{ NULL, NULL }
};
static AMX_NATIVE_INFO callnatives[] = {
{ "hs_use", ThisVTable::NativeCall },
{ "hs_euse", ThisVTable::ENativeCall },
{ NULL, NULL }
};
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
{
ThisVTable::pevoffset=poffset;
ThisVTable::pevset=pset;
ThisVTable::baseoffset=baseoffs;
ThisVTable::baseset=baseset;
ThisVTable::index=0;
ThisVTable::indexset=0;
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix("use",ThisVTable::KeyValue);
};
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,"use")==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
}
};
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
void ThisVTable::ConfigDone(void)
{
if (ThisVTable::indexset && *(ThisVTable::baseset))
{
MF_AddNatives(callnatives);
if (*(ThisVTable::pevset))
{
MF_AddNatives(registernatives);
}
}
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
// create an entity, assign it the gamedll's class, hook it and destroy it
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::NativeCall(AMX *amx, cell *params)
{
// TODO: This
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
{
VoidVCall4(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
INDEXENT_NEW(params[2])->pvPrivateData, /*activator*/
INDEXENT_NEW(params[3])->pvPrivateData, /*caller*/
params[4], /*type*/
amx_ctof2(params[5])); /*value*/
return 1;
};
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
{
VTableEntryBase::CreateGenericTrampoline(manager,
vtable,
ThisVTable::index,
id,
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisHook),
4, // param count
1, // voidcall
1); // thiscall
};
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid)
{
void *ptr=vtable[ThisVTable::index];
int i=0;
int end=manager->ThisEntries.size();
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*inflictor*/,FP_CELL/*attacker*/,FP_CELL/*damage*/,FP_CELL/*type*/,FP_DONE);
while (i<end)
{
if (manager->ThisEntries[i]->IsTrampoline(ptr))
{
// this function is already hooked!
manager->ThisEntries[i]->AddForward(fwd);
return;
}
++i;
}
// this function is NOT hooked
void *tramp;
void *func;
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
ThisVTable *entry=new ThisVTable;
entry->Setup(&vtable[ThisVTable::index],tramp,func);
manager->ThisEntries.push_back(entry);
entry->AddForward(fwd);
}
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param activator Entity causing the opening.
* @param caller Entity controlling the caller.
* @param type USE_TYPE (USE_{ON,OFF,SET}
* @param value Use value, only seen set when USE_SET is used.
* @noreturn
*/
void ThisVTable::Execute(void *pthis, void *activator, void *caller, int type, float value)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
int iActivator=PrivateToIndex(activator);
int iCaller=PrivateToIndex(caller);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iActivator,iCaller,type,amx_ftoc2(value));
if (thisresult>result)
{
result=thisresult;
}
};
if (result>=HAM_SUPERCEDE)
{
return;
}
#if defined _WIN32
reinterpret_cast<void (__fastcall *)(void *,int,void *,void *,int,float)>(function)(pthis,0,activator,caller,type,value);
#elif defined __linux__
reinterpret_cast<void (*)(void *,void *,void *,int,float)>(function)(pthis,activator,caller,type,value);
#endif
};

View File

@ -0,0 +1,462 @@
/* Ham Sandwich
*
* by the AMX Mod X Dev Team
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#ifndef VTABLEENTRIES_H
#define VTABLEENTRIES_H
#include "CVector.h"
#include "hooks.h"
class VTableManager;
class VTableEntryBase
{
public:
void *function; /**< The pointer to the original function that is being hooked. */
void **location; /**< The location of the vtable entry that is being hooked. */
void *trampoline; /**< Our trampoline (needs to be freed when it's not hooking any more!). */
CVector<int> Forwards; /**< Vector of forwards to call for this hook.*/
/**
* Saves virtual table location, trampoline and function pointers.
*
* @param vt Pointer to the index in the virtual table.
* @param tramp Pointer to the trampoline.
* @param func Pointer to the original function.
* @noreturn
*/
void Setup(void **vt,void *tramp, void *func)
{
location=vt;
trampoline=tramp;
function=func;
};
/**
* Manually called by VTableManager at destruction. Treat this like a dtor.
*
* @see VTableManager::Cleanup()
* @noreturn
*/
void Destroy()
{
// restore original location
if (location)
{
#if defined _WIN32
DWORD OldFlags;
VirtualProtect(location,sizeof(int*),PAGE_READWRITE,&OldFlags);
#elif defined __linux__
mprotect(location,sizeof(int*),PROT_READ|PROT_WRITE);
#endif
*location=function;
}
// free the trampoline
free(trampoline);
Forwards.clear();
};
/**
* Tells whether the given pointer is this entry's trampoline.
*
* @param ptr Pointer (cast to void*) of the function in question.
* @return true: Yes, the pointer in question is this entry's trampoline.
* fase: No, the pointer in question is not this entry's trampoline.
*/
bool IsTrampoline(void *ptr)
{
return (ptr==trampoline);
};
/**
* Returns the pointer (cast to void*) of the original function which is being hooked.
*
* @return Original function pointer, cast to void*.
*/
void *GetOriginalFunction(void)
{
return function;
};
/**
* Returns the location of this entry's virtual table entry itself.
*
* @return Pointer to this entry's virtual table entry.
*/
void **GetLocation(void)
{
return location;
};
/**
* Returns a pointer to this entry's trampoline.
*
* @return Trampoline pointer, cast to void*.
*/
void *GetTrampoline(void)
{
return trampoline;
};
/**
* Adds a forward to this entry's forward vector.
*
* @param fwd Forward index to add.
* @noreturn
*/
void AddForward(int fwd)
{
Forwards.push_back(fwd);
};
/**
* Creates a generic trampoline.
*
* @param manager The VTableManager this entry belongs to.
* @param vtable Pointer to the virtual table to molest.
* @param vindex VTable index to replace.
* @param id The unique id of this trampoline.
* @param outtrampoline Gets set to the location of the trampoline.
* @param origfunc Gets set to the original function which is being hooked.
* @param calee Target function this trampoline will call.
* @param paramcount How many parameters this trampoline pushes.
* @param voidcall Set to 1, this function does not return. 0 otherwise.
* @param thiscall Set to 1, treat this function like a thiscall.
*/
static void CreateGenericTrampoline(VTableManager *manager, void **vtable, int vtableindex, int id, void **outtrampoline, void **origfunc, void *calee, int paramcount, int voidcall=1, int thiscall=1);
};
class VTableTakeDamage : public VTableEntryBase
{
public:
static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */
static unsigned int *pevset; /**< Whether or not pev entry has been set */
static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */
static unsigned int *baseset; /**< Whether or base offset value has been set. */
static unsigned int index; /**< This entry's virtual table index. */
static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset);
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
static void KeyValue(const char *key, const char *data);
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
static void ConfigDone(void);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell ENativeCall(AMX *amx, cell *params);
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid);
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param inflictor Damage inflictor.
* @param attacker The attacker who caused the inflictor to damage the victim.
* @param damage How much damage was caused.
* @param type Damage type (usually in bitmask form).
* @return Unsure. Does not appear to be used.
*/
int Execute(void *pthis, void *inflictor, void *attacker, float damage, int type);
};
class VTableUse : public VTableEntryBase
{
public:
static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */
static unsigned int *pevset; /**< Whether or not pev entry has been set */
static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */
static unsigned int *baseset; /**< Whether or base offset value has been set. */
static unsigned int index; /**< This entry's virtual table index. */
static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset);
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
static void KeyValue(const char *key, const char *data);
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
static void ConfigDone(void);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell ENativeCall(AMX *amx, cell *params);
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid);
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param activator Entity causing the opening.
* @param caller Entity controlling the caller.
* @param type USE_TYPE (USE_{ON,OFF,SET}
* @param value Use value, only seen set when USE_SET is used.
* @noreturn
*/
void Execute(void *pthis, void *activator, void *caller, int type, float value);
};
class VTableBlocked : public VTableEntryBase
{
public:
static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */
static unsigned int *pevset; /**< Whether or not pev entry has been set */
static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */
static unsigned int *baseset; /**< Whether or base offset value has been set. */
static unsigned int index; /**< This entry's virtual table index. */
static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset);
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
static void KeyValue(const char *key, const char *data);
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
static void ConfigDone(void);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell ENativeCall(AMX *amx, cell *params);
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid);
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param activator Entity that's blocking.
* @noreturn
*/
void Execute(void *pthis, void *other);
};
//TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
/*class VTableTraceAttack : public VTableEntryBase
{
public:
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid);
void Execute(void *pthis, entvars_t *attacker, float damage, float *direction, TraceResult *tr, int damagetype);
};
*/
#endif // VTABLEENTRIES_H

View File

@ -0,0 +1,104 @@
#include "sdk/amxxmodule.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "NEW_Util.h"
void *VTableManager::InsertIntoVTable(void **vtable, int index, void *trampoline)
{
void *func;
#if defined _WIN32
DWORD OldFlags;
VirtualProtect(&vtable[index],sizeof(int*),PAGE_READWRITE,&OldFlags);
#elif defined __linux__
mprotect(&vtable[index],sizeof(int*),PROT_READ|PROT_WRITE);
#endif
func=vtable[index];
vtable[index]=trampoline;
return func;
};
#define CLEAR_ENTRIES(Container) \
i=Container.size(); \
while (i--) \
{ \
Container[i]->Destroy(); \
delete Container[i]; \
} \
Container.clear()
void VTableManager::Cleanup(void)
{
int i;
CLEAR_ENTRIES(UseEntries);
CLEAR_ENTRIES(TakeDamageEntries);
};
void VTableEntryBase::CreateGenericTrampoline(VTableManager *manager, void **vtable, int vtid, int id, void **outtrampoline, void **origfunc, void *callee, int paramcount, int voidcall, int thiscall)
{
Trampolines::TrampolineMaker tramp;
if (voidcall)
{
if (thiscall)
{
tramp.ThisVoidPrologue();
}
else
{
tramp.VoidPrologue();
}
}
else
{
if (thiscall)
{
tramp.ThisReturnPrologue();
}
else
{
tramp.ReturnPrologue();
}
}
while (paramcount)
{
tramp.PushParam(paramcount--);
}
if (thiscall)
{
tramp.PushThis();
}
tramp.PushNum(id);
tramp.Call(callee);
tramp.FreeTargetStack();
if (voidcall)
{
#if defined _WIN32
tramp.VoidEpilogueAndFree();
#elif defined __linux__
tramp.VoidEpilogue();
#endif
}
else
{
#if defined _WIN32
tramp.ReturnEpilogueAndFree();
#elif defined __linux__
tramp.ReturnEpilogue();
#endif
}
void *trampoline=tramp.Finish(NULL);
*outtrampoline=trampoline;
*origfunc=manager->InsertIntoVTable(vtable,vtid,trampoline);
};

View File

@ -0,0 +1,93 @@
#ifndef VTABLEMANAGER_H
#define VTABLEMANAGER_H
#include "Trampolines.h"
#include "CVector.h"
#include "hooks.h"
#include "VTableEntries.h"
/* !!WARNING: HERE BE DRAGONS
.~))>>
.~)>>
.~))))>>>
.~))>> ___
.~))>>)))>> .-~))>>
.~)))))>> .-~))>>)>
.~)))>>))))>> .-~)>>)>
) .~))>>))))>> .-~)))))>>)>
( )@@*) //)>)))))) .-~))))>>)>
).@(@@ //))>>))) .-~))>>)))))>>)>
(( @.@). //))))) .-~)>>)))))>>)>
)) )@@*.@@ ) //)>))) //))))))>>))))>>)>
(( ((@@@.@@ |/))))) //)))))>>)))>>)>
)) @@*. )@@ ) (\_(\-\b |))>)) //)))>>)))))))>>)>
(( @@@(.@(@ . _/`-` ~|b |>))) //)>>)))))))>>)>
)* @@@ )@* (@) (@) /\b|))) //))))))>>))))>>
(( @. )@( @ . _/ / / \b)) //))>>)))))>>>_._
)@@ (@@*)@@. (6///6)- / ^ \b)//))))))>>)))>> ~~-.
( @jgs@@. @@@.*@_ VvvvvV// ^ \b/)>>))))>> _. `bb
((@@ @@@*.(@@ . - | o |' \ ( ^ \b)))>> .' b`,
((@@).*@@ )@ ) \^^^/ (( ^ ~)_ \ / b `,
(@@. (@@ ). `-' ((( ^ `\ \ \ \ \| b `.
(*.@* / (((( \| | | \ . b `.
/ / ((((( \ \ / _.-~\ Y, b ;
/ / / (((((( \ \.-~ _.`" _.-~`, b ;
/ / `(((((() ) (((((~ `, b ;
_/ _/ `"""/ /' ; b ;
_.-~_.-~ / /' _.'~bb _.'
((((~~ / /' _.'~bb.--~
(((( __.-~bb.-~
.' b .~~
:bb ,'
~~~~
*/
enum
{
HAM_UNSET = 0,
HAM_IGNORED,
HAM_HANDLED,
HAM_OVERRIDE,
HAM_SUPERCEDE
};
enum
{
HAM_TYPE_UNKNOWN = 0,
HAM_TYPE_CBASE,
HAM_TYPE_ENTVAR,
HAM_TYPE_EDICT,
HAM_TYPE_INT,
HAM_TYPE_FLOAT
};
enum
{
HAM_ERROR_BOUNDS = -2,
HAM_ERROR_TYPE = -1,
HAM_ERROR_NONE = 0
};
class VTableManager
{
public:
CVector<VTableUse *> UseEntries;
CVector<VTableTakeDamage *> TakeDamageEntries;
CVector<VTableBlocked *> BlockedEntries;
/* returns the original function */
void *InsertIntoVTable(void **vtable, int index, void *trampoline);
void Cleanup(void);
};
extern VTableManager VTMan;
//#include "VTableEntries.h"
#endif // VTABLEMANAGER_H

View File

@ -0,0 +1,105 @@
/* Ham Sandwich
*
* by sawce
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
// Calling virtual functions on binaries compiled with GCC 2.95
// 2.95 and before stores the virtual table at the end of the
// inheritable size of the base class.
// I have no idea how it does it for multiple inheritance; i don't
// really care. Everything I'm calling does it in single inheritence.
// GCC doesn't put this on a register like MSVC does, so
// just pass it like a normal parameter (the first one)
// For GCC 3.3 compiled binaries, set the "size" parameter to 0
#ifdef __linux__
#ifndef VFUNC_GCC295_H
#define VFUNC_GCC295_H
inline void *GetVTableEntry(void *pThis, int ventry, int size)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
void **vtbl=*(void ***)pcThis;
return vtbl[ventry];
}
// I only comment on the first call, because it's jut copy/paste after
// the rest are compacted for copy/paste ease
template <class PTypeA, class PTypeB, class PTypeC, class PTypeD>
inline void VoidVCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc, PTypeD pd)
{
// First move up past the size of the class
char *pcThis=*(char **)&pThis;
pcThis+=size;
void **vtbl=*(void ***)pcThis;
// now points to the vtable of this object
typedef void (*fptr)(void*,PTypeA,PTypeB,PTypeC,PTypeD);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
function(pThis,pa,pb,pc,pd);
};
template <class RetType, class PTypeA, class PTypeB, class PTypeC, class PTypeD>
inline RetType VCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc, PTypeD pd)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
int **vtbl=*(int ***)pcThis;
typedef RetType (*fptr)(void*,PTypeA,PTypeB,PTypeC,PTypeD);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
return function(pThis,pa,pb,pc,pd);
};
template <class PTypeA>
inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
int **vtbl=*(int ***)pcThis;
typedef void (*fptr)(void*,PTypeA);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
function(pThis,pa);
};
template <class RetType, class PTypeA>
inline RetType VCall1(void *pThis, int ventry, int size, PTypeA pa)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
int **vtbl=*(int ***)pcThis;
typedef RetType (*fptr)(void*,PTypeA);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
return function(pThis,pa);
};
#endif //VFUNC_GCC295_H
#endif // __linux__

View File

@ -0,0 +1,137 @@
/* Ham Sandwich
*
* by sawce
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
// MSVC stores vtable like normal at the front as well
// however these are thiscall functions
// i use inline assembly to call them
#ifdef _WIN32
#ifndef VFUNC_MSVC_H
#define VFUNC_MSVC_H
inline void *GetVTableEntry(void *pThis, int ventry, int size)
{
void **vtbl=*(void ***)pThis;
return vtbl[ventry];
}
template <class PTypeA, class PTypeB, class PTypeC, class PTypeD>
inline void VoidVCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc, PTypeD pd)
{
// vtable pointer is stored in the first dword of the object
// reference it as an array of objects
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
// Simulate a thiscall
// this on ecx, all other parameters pushed normally
_asm {
push ecx; // save ecx
push eax; // save eax - shouldn't be needed, but just incase
push pd; // push param 4
push pc; // push param 3
push pb; // push param 2
push pa; // push param 1
mov ecx, pThis; // store this in ecx
call [func]; // call function
pop eax; // restore eax
pop ecx; // restore ecx
};
};
template <class RetType, class PTypeA, class PTypeB, class PTypeC, class PTypeD>
inline RetType VCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc, PTypeD pd)
{
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
RetType _ret;
_asm {
push ecx;
push eax;
push pd;
push pc;
push pb;
push pa;
mov ecx, pThis;
call [func];
mov _ret, eax;
pop eax;
pop ecx;
};
return _ret;
};
template <class PTypeA>
inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa)
{
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
_asm {
push ecx;
push eax;
push pa;
mov ecx, pThis;
call [func];
pop eax;
pop ecx;
};
};
template <class RetType, class PTypeA>
inline RetType VCall1(void *pThis, int ventry, int size, PTypeA pa)
{
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
RetType _ret;
_asm {
push ecx;
push eax;
push pa;
mov ecx, pThis;
call [func];
mov _ret, eax;
pop eax;
pop ecx;
};
return _ret;
};
#endif //VFUNC_MSVC_H
#endif // _WIN32

View File

@ -0,0 +1,51 @@
/**
* These are the functions called by the trampolines
* I explicitly declare them as cdecl so I know exactly
* how to work the stack in the trampoline.
*/
/*
static cell AMX_NATIVE_CALL register_takedamage(AMX *amx, cell *params)
{
};
static cell AMX_NATIVE_CALL register_use(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],0,NULL);
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
VTableUse::Hook(&VTMan,EdictToVTable(Entity),amx,funcid);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
return 0;
};
static AMX_NATIVE_INFO tdhooks[] = {
{ "register_takedamage", register_takedamage },
{ "register_use", register_use },
{ NULL, NULL }
};
void VTH_Natives()
{
MF_AddNatives(tdhooks);
};
*/

View File

@ -1,39 +0,0 @@
// prevent double include
#ifndef __PDATA_H__
#define __PDATA_H__
#include <extdll.h>
#include "amxxmodule.h"
#if defined __linux__
#define EXTRAOFFSET 5 // offsets 5 higher in Linux builds
#else
#define EXTRAOFFSET 0 // no change in Windows builds
#endif // defined __linux__
inline edict_t* MF_GetEntityEdict( long& EntID )
{
if( (EntID > 0) && (EntID <= (gpGlobals->maxClients) ) )
return MF_GetPlayerEdict( EntID );
return INDEXENT( EntID );
}
template <typename ValueType>
inline void SetPData( long& targetid, long offset, ValueType value)
{
edict_t* target = MF_GetEntityEdict( targetid );
if(target == NULL) return;
*((ValueType *)target->pvPrivateData + offset + EXTRAOFFSET) = value;
};
template <typename ValueType>
inline ValueType GetPData( long& targetid, long offset, ValueType value )
{
edict_t* target = MF_GetEntityEdict( targetid );
if(target == NULL) return NULL;
return *((ValueType *)target->pvPrivateData + offset + EXTRAOFFSET);
}
#endif

413
dlls/sven/sven/CString.h Normal file
View File

@ -0,0 +1,413 @@
/* AMX Mod X
*
* by the AMX Mod X Development Team
* originally developed by OLO
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#ifndef _INCLUDE_CSTRING_H
#define _INCLUDE_CSTRING_H
#include <string.h>
#include <stdio.h>
//by David "BAILOPAN" Anderson
class String
{
public:
String()
{
v = NULL;
a_size = 0;
//assign("");
}
~String()
{
if (v)
delete [] v;
}
String(const char *src)
{
v = NULL;
a_size = 0;
assign(src);
}
const char * _fread(FILE *fp)
{
Grow(512, false);
char *ret = fgets(v, 511, fp);
return ret;
}
String(const String &src)
{
v = NULL;
a_size = 0;
assign(src.c_str());
}
const char *c_str() { return v?v:""; }
const char *c_str() const { return v?v:""; }
void append(const char *t)
{
Grow(size() + strlen(t) + 1);
strcat(v, t);
}
void append(const char c)
{
size_t len = size();
Grow(len + 2);
v[len] = c;
v[len + 1] = '\0';
}
void append(String &d)
{
append(d.c_str());
}
void assign(const String &src)
{
assign(src.c_str());
}
void assign(const char *d)
{
if (!d)
{
clear();
} else {
size_t len = strlen(d);
Grow(len + 1, false);
memcpy(v, d, len);
v[len] = '\0';
}
}
void clear()
{
if (v)
v[0] = '\0';
}
int compare (const char *d) const
{
if (!v)
return strcmp("", d);
else
return strcmp(v, d);
}
//Added this for amxx inclusion
bool empty()
{
if (!v)
return true;
if (v[0] == '\0')
return true;
return false;
}
size_t size()
{
if (v)
return strlen(v);
else
return 0;
}
int find(const char c, int index = 0)
{
int len = static_cast<int>(size());
if (len < 1)
return npos;
if (index >= len || index < 0)
return npos;
int i = 0;
for (i=index; i<len; i++)
{
if (v[i] == c)
{
return i;
}
}
return npos;
}
bool is_space(int c)
{
if (c == '\f' || c == '\n' ||
c == '\t' || c == '\r' ||
c == '\v' || c == ' ')
{
return true;
}
return false;
}
void reparse_newlines()
{
size_t len = size();
int offs = 0;
char c;
if (!len)
return;
for (size_t i=0; i<len; i++)
{
c = v[i];
if (c == '^' && (i != len-1))
{
c = v[++i];
if (c == 'n')
c = '\n';
else if (c == 't')
c = '\t';
offs++;
}
v[i-offs] = c;
}
v[len-offs] = '\0';
}
void trim()
{
if (!v)
return;
unsigned int i = 0;
unsigned int j = 0;
size_t len = strlen(v);
if (len == 1)
{
if (is_space(v[i]))
{
clear();
return;
}
}
unsigned char c0 = v[0];
if (is_space(c0))
{
for (i=0; i<len; i++)
{
if (!is_space(v[i]) || (is_space(v[i]) && ((unsigned char)i==len-1)))
{
erase(0, i);
break;
}
}
}
len = strlen(v);
if (len < 1)
{
return;
}
if (is_space(v[len-1]))
{
for (i=len-1; i>=0; i--)
{
if (!is_space(v[i])
|| (is_space(v[i]) && i==0))
{
erase(i+1, j);
break;
}
j++;
}
}
if (len == 1)
{
if (is_space(v[0]))
{
clear();
return;
}
}
}
void erase(unsigned int start, int num = npos)
{
if (!v)
return;
unsigned int i = 0;
size_t len = size();
//check for bounds
if (num == npos || start+num > len-start)
num = len - start;
//do the erasing
bool copyflag = false;
for (i=0; i<len; i++)
{
if (i>=start && i<start+num)
{
if (i+num < len)
{
v[i] = v[i+num];
} else {
v[i] = 0;
}
copyflag = true;
} else if (copyflag) {
if (i+num < len)
{
v[i] = v[i+num];
} else {
v[i] = 0;
}
}
}
len -= num;
v[len] = 0;
}
String substr(unsigned int index, int num = npos)
{
if (!v)
{
String b("");
return b;
}
String ns;
size_t len = size();
if (index >= len || !v)
return ns;
if (num == npos)
{
num = len - index;
} else if (index+num >= len) {
num = len - index;
}
unsigned int i = 0;
unsigned int nslen = num + 2;
ns.Grow(nslen);
for (i=index; i<index+num; i++)
ns.append(v[i]);
return ns;
}
void toLower()
{
if (!v)
return;
unsigned int i = 0;
size_t len = strlen(v);
for (i=0; i<len; i++)
{
if (v[i] >= 65 && v[i] <= 90)
v[i] &= ~(1<<5);
}
}
String & operator = (const String &src)
{
assign(src);
return *this;
}
String & operator = (const char *src)
{
assign(src);
return *this;
}
char operator [] (unsigned int index)
{
if (index > size() || !v)
{
return -1;
} else {
return v[index];
}
}
int at(int a)
{
if (a < 0 || a >= (int)size() || !v)
return -1;
return v[a];
}
bool at(int at, char c)
{
if (at < 0 || at >= (int)size() || !v)
return false;
v[at] = c;
return true;
}
private:
void Grow(unsigned int d, bool copy=true)
{
if (d <= a_size)
return;
char *n = new char[d + 1];
if (copy && v)
strcpy(n, v);
if (v)
delete [] v;
else
strcpy(n, "");
v = n;
a_size = d + 1;
}
char *v;
unsigned int a_size;
public:
static const int npos = -1;
};
#endif //_INCLUDE_CSTRING_H

254
dlls/sven/sven/Trie.h Normal file
View File

@ -0,0 +1,254 @@
/* ======== Simple Trie ========
* Copyright (C) 2006-2007 Kuchiki Rukia
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Radical Edward
* Notes: Generic simple trie
* ============================
*/
// Rukia: Digital trees, or tries, are a combination of vector and tree structures.
// They have garanteed O(1) worst case (literally O(m), constant for key length).
// However, unless optimized (such as in Judy Arrays), they have terrible memory performance.
// We will use a naive approach, due to time constraints.
// Judy Arrays would be a better approach, but would destroy the point of the assignment.
#ifndef __TRIE_CLASS__
#define __TRIE_CLASS__
// Rukia: HACK: Usage of assert to force metatemplates to work right.
#include <cassert>
#include <string.h>
// Rukia: Metaprogramming to aid in compile time constants and such.
template<size_t base, size_t N>
struct Exponential
{
enum { value = base * Exponential<base,N - 1>::value };
};
template <size_t base>
struct Exponential<base,0>
{
enum { value = 1 };
};
// Rukia: NOTE: This is extremely ugly for these reasons:
// 1. It relies on template metaprogramming
// 2. It is unoptimized
// 3. It was written in exactly 1 hour and 7 minutes.
// However, preliminary tests show it is faster than the STL hashmap, in current form.
// HACK: Optimize further into a patricia tree and partial specialization digital tree (Judy Array).
// Rukia: HACK: To optimize:
// 1. Add two bitvectors (vector<bool>) to each node.
// * 0 0 = nothing at all
// * 1 0 = compressed nodes 1
// * 0 1 = compressed nodes 2
// * 1 1 = uncompressed node
// 2. Add compressed node 1; a simple holder for one value
// 3. Add compressed node 2; a vector with a bitlookup table for up to 2^sizeof(C) values
// 4. Allow for hytersis in deletion for until 1 insert (will increase speed on multiple in row insert/deletes
// Rukia: Templates <Key, Value, Compare by>
template <typename K, typename V, typename C = unsigned char>
class Trie
{
public:
// Rukia: HACK: Remove this from Trie class eventually; it looks ugly and is slow.
class TrieNode
{
friend class Trie;
public:
TrieNode()
{
// Rukia: Render all pointers NULL.
// Rukia: HACK: Reformat this somehow, it is ugly.
// Rukia: Use 0, not NULL. GCC dislikes usage of NULL.
memset(reinterpret_cast<void*>(Children),0,Exponential<2,8*sizeof(C)>::value * sizeof(TrieNode*));
Value = NULL;
}
// Rukia: We can garantee this will be an OK delete; either value, or NULL.
~TrieNode()
{
if( Value != NULL) { delete Value; }
for(register long i = 0; i < Exponential<2,8*sizeof(C)>::value; i++)
{
delete Children[i];
}
}
void Clear()
{
if( Value != NULL) { delete Value; }
for(register long i = 0; i < Exponential<2,8*sizeof(C)>::value; i++)
{
delete Children[i];
Children[i] = NULL;
}
}
// Rukia: Little syntatical sugar for you. Hope you like it.
TrieNode* operator[](C size)
{
return Children[size];
}
void InOrderAlt(void(*func)(V&) )
{
if( Value != NULL) { func(*Value); }
for(register long i = 0; i < Exponential<2,8*sizeof(C)>::value; i++)
{
if(Children[i] != NULL) { (Children[i])->InOrderAlt(func); }
}
}
void Insert(V& newval)
{
if(Value == NULL) { Value = new V; }
*Value = newval;
}
// Rukia: This will be inlined out, and it is never good to expose too much.
V* Retrieve()
{
return Value;
}
// Rukia: Return true if node is redundant, so we can remove it.
// Rukia: HACK: Perhaps optimize for inserts by analyzing usage?
void Delete()
{
delete Value;
Value = NULL;
}
// Rukia: GCC doesn't like redundant friend declarations.
//friend class Trie;
private:
TrieNode* Children[Exponential<2,8*sizeof(C)>::value];
V* Value;
};
friend class TrieNode;
// Rukia: Root/stem node.
TrieNode Stem;
// Simply calls the destructor on any and all children, until everything is dead.
void Clear()
{
Stem.Clear();
}
bool IsValid(const K* key, size_t keylen)
{
return (Retrieve(key,keylen) != NULL);
}
void InOrderAlt(void(*func)(V&) )
{
Stem.InOrderAlt(func);
}
// Rukia: We use const for the key, even though we completely subvert the system.
// Rukia: Why? Because we don't CHANGE it, even if we subvert the system.
V* Retrieve(const K* key, size_t keylen)
{
// Rukia: Convert to comparison types
register C* realkey = (C*)(key);
C CurrKey = *realkey;
// Rukia: HACK: Convert to use bitwise shift operators
register size_t reallen = keylen * (sizeof(K) / sizeof(C) );
if(key == NULL) { return Stem.Retrieve(); }
// Rukia: Iterate through the nodes till we find a NULL one, or run out of key.
register TrieNode* CurrNode = Stem[CurrKey];
// Rukia: HACK: Return NULL, don't use exceptions, they are slow.
if(CurrNode == NULL) { return NULL; }
// Rukia: initialize one lower because we've already decoded one from the key.
for(reallen--;reallen != 0;reallen--)
{
realkey++;
CurrKey = *realkey;
CurrNode = (*CurrNode)[CurrKey];
if(CurrNode == NULL) { return NULL; }
}
return CurrNode->Retrieve();
};
void Insert( const K* key, size_t keylen, V& value)
{
// Rukia: Convert to comparison types
register C* realkey = (C*)(key);
C CurrKey = *realkey;
// Rukia: HACK: Convert to use bitwise shift operators
register size_t reallen = keylen * (sizeof(K) / sizeof(C) );
if(key == NULL) { Stem.Retrieve(); }
// Rukia: Iterate through the nodes till we find a NULL one, or run out of key.
register TrieNode* CurrNode = Stem[CurrKey];
register TrieNode* TmpNode = NULL;
// Rukia: HACK: Maybe an internal memory allocator?
// Rukia: HACK: Quickly resort to 'friend'; reduces encapsulation, but worth the cost.
if(CurrNode == NULL) { CurrNode = new TrieNode(); Stem.Children[CurrKey] = CurrNode; }
// Rukia: initialize one lower because we've already decoded one from the key.
for(reallen--;reallen != 0;reallen--)
{
realkey++;
CurrKey = *realkey;
TmpNode = (*CurrNode)[CurrKey];
if(TmpNode == NULL) { TmpNode = new TrieNode; CurrNode->Children[CurrKey] = TmpNode; }
CurrNode = TmpNode;
}
CurrNode->Insert(value);
}
// Rukia: HACK HACK HACK: Fix this SOON. Delete will NOT delete nodes, and has no hystersis operandi.
void Delete( const K* key, size_t keylen)
{
// Rukia: Convert to comparison types
register C* realkey = (C*)(key);
C CurrKey = *realkey;
// Rukia: HACK: Convert to use bitwise shift operators
register size_t reallen = keylen * (sizeof(K) / sizeof(C) );
if(key == NULL) { Stem.Delete(); return; }
// Rukia: Iterate through the nodes till we find a NULL one, or run out of key.
register TrieNode* CurrNode = Stem[CurrKey];
// Rukia: HACK: Return NULL, don't use exceptions, they are slow.
if(CurrNode == NULL) { return; }
// Rukia: initialize one lower because we've already decoded one from the key.
for(reallen--;reallen != 0;reallen--)
{
realkey++;
CurrKey = *realkey;
CurrNode = (*CurrNode)[CurrKey];
if(CurrNode == NULL) { return; }
}
CurrNode->Delete();
}
};
#endif

File diff suppressed because it is too large Load Diff

2454
dlls/sven/sven/amxxmodule.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,344 @@
/* AMX Mod X
* Sven Co-op Module
*
* by the AMX Mod X Development Team
*
* This file is part of AMX Mod X.
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#include "svencoop.h"
//
// EXTERNS
//
int gmsgScoreInfo;
KeyValueData g_kvd;
Trie<char,String> g_allyNameTrie, g_enemyNameTrie;
//
// GLOBALS
//
int g_lastDeadflag[33] = { 0 }, g_grenadeCount = 0,
g_spawnFwd = -1, g_healFwd = -1, g_grenadeFwd = -1;
edict_t *g_grenadeList[32] = { NULL };
//
// AMXX HOOKS
//
void OnAmxxAttach()
{
MF_AddNatives(svencoop_Exports);
// sc_set_displayname
g_kvd.szClassName = "";
g_kvd.szKeyName = "";
g_kvd.szValue = "";
g_kvd.fHandled = 0;
// sc_get_displayname, default displaynames
g_allyNameTrie.Insert("monster_alien_babyvoltigore", 27, String("Friendly Baby Voltigore"));
g_enemyNameTrie.Insert("monster_alien_babyvoltigore", 27, String("Baby Voltigore"));
g_allyNameTrie.Insert("monster_alien_controller", 24, String("Friendly Alien Controller"));
g_enemyNameTrie.Insert("monster_alien_controller", 24, String("Alien Controller"));
g_allyNameTrie.Insert("monster_alien_grunt", 19, String("Friendly Alien Grunt"));
g_enemyNameTrie.Insert("monster_alien_grunt", 19, String("Alien Grunt"));
g_allyNameTrie.Insert("monster_alien_slave", 19, String("Friendly Alien Slave"));
g_enemyNameTrie.Insert("monster_alien_slave", 19, String("Alien Slave"));
g_allyNameTrie.Insert("monster_vortigaunt", 18, String("Friendly Alien Slave"));
g_enemyNameTrie.Insert("monster_vortigaunt", 18, String("Alien Slave"));
g_allyNameTrie.Insert("monster_alien_voltigore", 23, String("Friendly Voltigore"));
g_enemyNameTrie.Insert("monster_alien_voltigore", 23, String("Voltigore"));
g_allyNameTrie.Insert("monster_apache", 14, String("Apache"));
g_enemyNameTrie.Insert("monster_apache", 14, String("Apache"));
g_allyNameTrie.Insert("monster_blkop_apache", 20, String("Apache"));
g_enemyNameTrie.Insert("monster_blkop_apache", 20, String("Apache"));
g_allyNameTrie.Insert("monster_assassin_repel", 22, String("Friendly Male Assassin"));
g_enemyNameTrie.Insert("monster_assassin_repel", 22, String("Male Assassin"));
g_allyNameTrie.Insert("monster_male_assassin", 21, String("Friendly Male Assassin"));
g_enemyNameTrie.Insert("monster_male_assassin", 21, String("Male Assassin"));
g_allyNameTrie.Insert("monster_babycrab", 16, String("Friendly Head Crab"));
g_enemyNameTrie.Insert("monster_babycrab", 16, String("Head Crab"));
g_allyNameTrie.Insert("monster_headcrab", 16, String("Friendly Head Crab"));
g_enemyNameTrie.Insert("monster_headcrab", 16, String("Head Crab"));
g_allyNameTrie.Insert("monster_babygarg", 16, String("Friendly Baby Gargantua"));
g_enemyNameTrie.Insert("monster_babygarg", 16, String("Baby Gargantua"));
g_allyNameTrie.Insert("monster_barnacle", 16, String("Barnacle"));
g_enemyNameTrie.Insert("monster_barnacle", 16, String("Barnacle"));
g_allyNameTrie.Insert("monster_barney", 14, String("Barney"));
g_enemyNameTrie.Insert("monster_barney", 14, String("Barnabus"));
g_allyNameTrie.Insert("monster_bigmomma", 16, String("Friendly Big Momma"));
g_enemyNameTrie.Insert("monster_bigmomma", 16, String("Big Momma"));
g_allyNameTrie.Insert("monster_blkop_osprey", 20, String("Friendly Black Ops Osprey"));
g_enemyNameTrie.Insert("monster_blkop_osprey", 20, String("Black Ops Osprey"));
g_allyNameTrie.Insert("monster_bloater", 15, String("Friendly Bloater"));
g_enemyNameTrie.Insert("monster_bloater", 15, String("Bloater"));
g_allyNameTrie.Insert("monster_bullchicken", 19, String("Friendly Bull Squid"));
g_enemyNameTrie.Insert("monster_bullchicken", 19, String("Bull Squid"));
g_allyNameTrie.Insert("monster_chumtoad", 16, String("Chubby"));
g_enemyNameTrie.Insert("monster_chumtoad", 16, String("Chumtoad"));
g_allyNameTrie.Insert("monster_cleansuit_scientist", 27, String("Cleansuit Scientist"));
g_enemyNameTrie.Insert("monster_cleansuit_scientist", 27, String("Cleansuit Scientist"));
g_allyNameTrie.Insert("monster_cockroach", 17, String("Roach"));
g_enemyNameTrie.Insert("monster_cockroach", 17, String("Roach"));
g_allyNameTrie.Insert("monster_gargantua", 17, String("Friendly Gargantua"));
g_enemyNameTrie.Insert("monster_gargantua", 17, String("Gargantua"));
g_allyNameTrie.Insert("monster_gman", 12, String("Government Man"));
g_enemyNameTrie.Insert("monster_gman", 12, String("Government Man"));
g_allyNameTrie.Insert("monster_gonome", 14, String("Friendly Gonome"));
g_enemyNameTrie.Insert("monster_gonome", 14, String("Gonome"));
g_allyNameTrie.Insert("monster_houndeye", 16, String("Friendly Hound Eye"));
g_enemyNameTrie.Insert("monster_houndeye", 16, String("Hound Eye"));
g_allyNameTrie.Insert("monster_human_assassin", 22, String("Friendly Female Assassin"));
g_enemyNameTrie.Insert("monster_human_assassin", 22, String("Female Assassin"));
g_allyNameTrie.Insert("monster_human_grunt", 19, String("Friendly Human Grunt"));
g_enemyNameTrie.Insert("monster_human_grunt", 19, String("Human Grunt"));
g_allyNameTrie.Insert("monster_grunt_repel", 19, String("Friendly Human Grunt"));
g_enemyNameTrie.Insert("monster_grunt_repel", 19, String("Human Grunt"));
g_allyNameTrie.Insert("monster_human_grunt_ally", 24, String("Ally Grunt"));
g_enemyNameTrie.Insert("monster_human_grunt_ally", 24, String("Enemy Grunt"));
g_allyNameTrie.Insert("monster_grunt_ally_repel", 24, String("Ally Grunt"));
g_enemyNameTrie.Insert("monster_grunt_ally_repel", 24, String("Enemy Grunt"));
g_allyNameTrie.Insert("monster_human_medic_ally", 24, String("Medic Grunt"));
g_enemyNameTrie.Insert("monster_human_medic_ally", 24, String("Enemy Medic Grunt"));
g_allyNameTrie.Insert("monster_medic_ally_repel", 24, String("Medic Grunt"));
g_enemyNameTrie.Insert("monster_medic_ally_repel", 24, String("Enemy Medic Grunt"));
g_allyNameTrie.Insert("monster_human_torch_ally", 24, String("Torch Grunt"));
g_enemyNameTrie.Insert("monster_human_torch_ally", 24, String("Enemy Torch Grunt"));
g_allyNameTrie.Insert("monster_torch_ally_repel", 24, String("Torch Grunt"));
g_enemyNameTrie.Insert("monster_torch_ally_repel", 24, String("Enemy Torch Grunt"));
g_allyNameTrie.Insert("monster_hwgrunt", 15, String("Friendly Heavy Weapons Grunt"));
g_enemyNameTrie.Insert("monster_hwgrunt", 15, String("Heavy Weapons Grunt"));
g_allyNameTrie.Insert("monster_hwgrunt_repel", 21, String("Friendly Heavy Weapons Grunt"));
g_enemyNameTrie.Insert("monster_hwgrunt_repel", 21, String("Heavy Weapons Grunt"));
g_allyNameTrie.Insert("monster_ichthyosaur", 19, String("Friendly Ichthyosaur"));
g_enemyNameTrie.Insert("monster_ichthyosaur", 19, String("Ichthyosaur"));
g_allyNameTrie.Insert("monster_leech", 13, String("Leech"));
g_enemyNameTrie.Insert("monster_leech", 13, String("Leech"));
g_allyNameTrie.Insert("monster_miniturret", 18, String("Mini-Turret"));
g_enemyNameTrie.Insert("monster_miniturret", 18, String("Mini-Turret"));
g_allyNameTrie.Insert("monster_nihilanth", 17, String(""));
g_enemyNameTrie.Insert("monster_nihilanth", 17, String(""));
g_allyNameTrie.Insert("monster_osprey", 14, String("Friendly Osprey Helicopter"));
g_enemyNameTrie.Insert("monster_osprey", 14, String("Osprey Helicopter"));
g_allyNameTrie.Insert("monster_otis", 12, String("Otis"));
g_enemyNameTrie.Insert("monster_otis", 12, String("Enemy Otis"));
g_allyNameTrie.Insert("monster_pitdrone", 16, String("Friendly Pit Drone"));
g_enemyNameTrie.Insert("monster_pitdrone", 16, String("Pit Drone"));
g_allyNameTrie.Insert("monster_rat", 11, String("Rat"));
g_enemyNameTrie.Insert("monster_rat", 11, String("Rat"));
g_allyNameTrie.Insert("monster_robogrunt", 17, String("Friendly Robo Grunt"));
g_enemyNameTrie.Insert("monster_robogrunt", 17, String("Robo Grunt"));
g_allyNameTrie.Insert("monster_robogrunt_repel", 23, String("Friendly Robo Grunt"));
g_enemyNameTrie.Insert("monster_robogrunt_repel", 23, String("Robo Grunt"));
g_allyNameTrie.Insert("monster_scientist", 17, String("Scientist"));
g_enemyNameTrie.Insert("monster_scientist", 17, String("Scientist"));
g_allyNameTrie.Insert("monster_sitting_scientist", 25, String("Scientist"));
g_enemyNameTrie.Insert("monster_sitting_scientist", 25, String("Scientist"));
g_allyNameTrie.Insert("monster_sentry", 14, String("Sentry Turret"));
g_enemyNameTrie.Insert("monster_sentry", 14, String("Sentry Turret"));
g_allyNameTrie.Insert("monster_shockroach", 18, String("Friendly Shock Roach"));
g_enemyNameTrie.Insert("monster_shockroach", 18, String("Shock Roach"));
g_allyNameTrie.Insert("monster_shocktrooper", 20, String("Friendly Shock Trooper"));
g_enemyNameTrie.Insert("monster_shocktrooper", 20, String("Shock Trooper"));
g_allyNameTrie.Insert("monster_snark", 13, String("Snark"));
g_enemyNameTrie.Insert("monster_snark", 13, String("Snark"));
g_allyNameTrie.Insert("monster_tentacle", 16, String("Tentacle"));
g_enemyNameTrie.Insert("monster_tentacle", 16, String("Tentacle"));
g_allyNameTrie.Insert("monster_tentaclemaw", 19, String("Tentacle"));
g_enemyNameTrie.Insert("monster_tentaclemaw", 19, String("Tentacle"));
g_allyNameTrie.Insert("monster_turret", 14, String("Turret"));
g_enemyNameTrie.Insert("monster_turret", 14, String("Turret"));
g_allyNameTrie.Insert("monster_zombie", 14, String("Friendly Zombie"));
g_enemyNameTrie.Insert("monster_zombie", 14, String("Zombie"));
g_allyNameTrie.Insert("monster_zombie_barney", 21, String("Friendly Zombie Barney"));
g_enemyNameTrie.Insert("monster_zombie_barney", 21, String("Zombie Barney"));
g_allyNameTrie.Insert("monster_zombie_soldier", 22, String("Friendly Zombie Soldier"));
g_enemyNameTrie.Insert("monster_zombie_soldier", 22, String("Zombie Soldier"));
}
void OnPluginsLoaded()
{
g_spawnFwd = MF_RegisterForward("sc_client_spawn", ET_IGNORE, FP_CELL, FP_DONE);
g_healFwd = MF_RegisterForward("sc_client_heal", ET_IGNORE, FP_CELL, FP_CELL, FP_FLOAT, FP_CELL, FP_CELL, FP_DONE);
g_grenadeFwd = MF_RegisterForward("sc_grenade_throw", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
}
//
// METAMOD HOOKS
//
/***GetEntityAPI2******************/
// sc_client_heal
void DispatchThink(edict_t *pEntity)
{
if(g_healFwd != -1 && UTIL_IsMonster(pEntity))
*((float *)pEntity->pvPrivateData + OFFSET_LAST_HEALTH) = pEntity->v.health;
RETURN_META(MRES_IGNORED);
}
// sc_get_displayname
void DispatchKeyValue(edict_t *pentKeyvalue, KeyValueData *pkvd)
{
// catch displayname and store it ourselves for our native
// TODO: store this somewhere else besides in the pev
if(FStrEq(pkvd->szKeyName, "displayname"))
pentKeyvalue->v.message = ALLOC_STRING(pkvd->szValue);
RETURN_META(MRES_IGNORED);
}
// sc_client_spawn
void ClientPutInServer(edict_t *pPlayer)
{
g_lastDeadflag[ENTINDEX(pPlayer)] = -1;
RETURN_META(MRES_IGNORED);
}
// sc_client_spawn / sc_client_heal
void PlayerPreThink(edict_t *pPlayer)
{
if(g_spawnFwd != -1)
{
int index = ENTINDEX(pPlayer);
if(g_lastDeadflag[index] == -1 || (g_lastDeadflag[index] != DEAD_NO && pPlayer->v.deadflag == DEAD_NO))
MF_ExecuteForward(g_spawnFwd, index);
g_lastDeadflag[index] = pPlayer->v.deadflag;
}
if(g_healFwd != -1)
*((float *)pPlayer->pvPrivateData + OFFSET_LAST_HEALTH) = pPlayer->v.health;
RETURN_META(MRES_IGNORED);
}
// sc_grenade_throw
void StartFrame()
{
if(g_grenadeFwd == -1 || !g_grenadeCount)
RETURN_META(MRES_IGNORED);
edict_t *pGrenade = g_grenadeList[0];
if(!FNullEnt(pGrenade) && pGrenade->v.owner)
{
const char *model = STRING(pGrenade->v.model);
int wId = 0;
switch(model[7])
{
case 'g': wId = SCW_ARGRENADE; break; // models/grenade.mdl
case 'w': wId = SCW_HANDGRENADE; break; // models/w_grenade.mdl
//case 'c': wId = SCW_BANANA; break; // models/cretegibs.mdl
}
if(wId) MF_ExecuteForward(g_grenadeFwd, ENTINDEX(pGrenade->v.owner),
ENTINDEX(pGrenade), wId, UTIL_IsPlayer(pGrenade->v.owner));
}
// shift the list
g_grenadeList[0] = NULL;
if(--g_grenadeCount)
{
for(int i=1;i<=g_grenadeCount;i++) g_grenadeList[i-1] = g_grenadeList[i];
g_grenadeList[g_grenadeCount] = NULL;
}
RETURN_META(MRES_IGNORED);
}
/***GetEntityAPI2_Post*************/
// sc_set_frags
void ServerActivate_Post(struct edict_s *, int, int)
{
gmsgScoreInfo = GET_USER_MSG_ID(PLID, "ScoreInfo", NULL);
RETURN_META(MRES_IGNORED);
}
/***GetEngineAPI*******************/
// sc_client_heal
void EmitSound(edict_t *pEntity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch)
{
if(g_healFwd == -1 || !UTIL_IsPlayer(pEntity) || channel != CHAN_WEAPON || strcmp(sample, "items/medshot4.wav") != 0)
RETURN_META(MRES_IGNORED);
Vector trStart = pEntity->v.origin;
if(pEntity->v.flags & FL_DUCKING) trStart.z += 12.0;
else trStart.z += 28.0;
Vector trEnd = trStart + gpGlobals->v_forward * 32;
TraceResult tr;
TRACE_LINE(trStart, trEnd, dont_ignore_monsters, pEntity, &tr);
if(tr.flFraction == 1.0)
TRACE_HULL(trStart, trEnd, dont_ignore_monsters, head_hull, pEntity, &tr);
if(!FNullEnt(tr.pHit))
{
float amount = tr.pHit->v.health - *((float *)tr.pHit->pvPrivateData + OFFSET_LAST_HEALTH);
if(UTIL_IsPlayer(tr.pHit))
MF_ExecuteForward(g_healFwd, ENTINDEX(pEntity), ENTINDEX(tr.pHit), amount, 1, 1);
else if(UTIL_IsMonster(tr.pHit))
MF_ExecuteForward(g_healFwd, ENTINDEX(pEntity), ENTINDEX(tr.pHit), amount, 0, *((int *)tr.pHit->pvPrivateData + OFFSET_MONSTER_ALLY));
}
RETURN_META(MRES_IGNORED);
}
/***GetEngineAPI_Post**************/
// sc_grenade_throw
void SetModel_Post(edict_t *pEntity, const char *model)
{
if(g_grenadeFwd == -1)
RETURN_META(MRES_IGNORED);
const char *classname = STRING(pEntity->v.classname);
if(!pEntity->v.owner && classname[0] == 'g' && classname[2] == 'e' && model[7] == 'g')
{
if(g_grenadeCount < sizeof g_grenadeList)
g_grenadeList[g_grenadeCount++] = pEntity;
}
RETURN_META(MRES_IGNORED);
}

View File

@ -4,11 +4,13 @@
#define __MODULECONFIG_H__
// Module info
#define MODULE_NAME "SvenFun"
#define MODULE_VERSION "1.65"
#define MODULE_AUTHOR "Sanji"
#define MODULE_URL "www.amxmodx.org"
#define MODULE_LOGTAG "SF"
#define MODULE_NAME "SvenCoop"
#define MODULE_VERSION "1.77"
#define MODULE_AUTHOR "AMX Mod X Dev Team"
#define MODULE_URL "http://www.amxmodx.org"
#define MODULE_LOGTAG "SVEN"
#define MODULE_LIBRARY "svencoop"
#define MODULE_LIBCLASS ""
// If you want the module not to be reloaded on mapchange, remove / comment out the next line
#define MODULE_RELOAD_ON_MAPCHANGE
@ -31,18 +33,36 @@
// It allows you to compile without libstdc++.so as a dependency
// #define NO_ALLOC_OVERRIDES
// - AMXX Init functions
// Also consider using FN_META_*
// AMXX query
// Uncomment this if you are using MSVC8 or greater and want to fix some of the compatibility issues yourself
// #define NO_MSVC8_AUTO_COMPAT
/**
* AMXX Init functions
* Also consider using FN_META_*
*/
/** AMXX query */
//#define FN_AMXX_QUERY OnAmxxQuery
// AMXX attach
// Do native functions init here (MF_AddNatives)
/** AMXX attach
* Do native functions init here (MF_AddNatives)
*/
#define FN_AMXX_ATTACH OnAmxxAttach
// AMXX detach
/** AMXX Detach (unload) */
//#define FN_AMXX_DETACH OnAmxxDetach
// All plugins loaded
// Do forward functions init here (MF_RegisterForward)
// #define FN_AMXX_PLUGINSLOADED OnPluginsLoaded
/** All plugins loaded
* Do forward functions init here (MF_RegisterForward)
*/
#define FN_AMXX_PLUGINSLOADED OnPluginsLoaded
/** All plugins are about to be unloaded */
//#define FN_AMXX_PLUGINSUNLOADING OnPluginsUnloading
/** All plugins are now unloaded */
//#define FN_AMXX_PLUGINSUNLOADED OnPluginsUnloaded
/**** METAMOD ****/
// If your module doesn't use metamod, you may close the file now :)
@ -65,11 +85,11 @@
// - GetEntityAPI2 functions
// #define FN_GameDLLInit GameDLLInit /* pfnGameInit() */
// #define FN_DispatchSpawn DispatchSpawn /* pfnSpawn() */
// #define FN_DispatchThink DispatchThink /* pfnThink() */
#define FN_DispatchThink DispatchThink /* pfnThink() */
// #define FN_DispatchUse DispatchUse /* pfnUse() */
// #define FN_DispatchTouch DispatchTouch /* pfnTouch() */
// #define FN_DispatchBlocked DispatchBlocked /* pfnBlocked() */
// #define FN_DispatchKeyValue DispatchKeyValue /* pfnKeyValue() */
#define FN_DispatchKeyValue DispatchKeyValue /* pfnKeyValue() */
// #define FN_DispatchSave DispatchSave /* pfnSave() */
// #define FN_DispatchRestore DispatchRestore /* pfnRestore() */
// #define FN_DispatchObjectCollsionBox DispatchObjectCollsionBox /* pfnSetAbsBox() */
@ -81,14 +101,14 @@
// #define FN_ClientConnect ClientConnect /* pfnClientConnect() (wd) Client has connected */
// #define FN_ClientDisconnect ClientDisconnect /* pfnClientDisconnect() (wd) Player has left the game */
// #define FN_ClientKill ClientKill /* pfnClientKill() (wd) Player has typed "kill" */
// #define FN_ClientPutInServer ClientPutInServer /* pfnClientPutInServer() (wd) Client is entering the game */
#define FN_ClientPutInServer ClientPutInServer /* pfnClientPutInServer() (wd) Client is entering the game */
// #define FN_ClientCommand ClientCommand /* pfnClientCommand() (wd) Player has sent a command (typed or from a bind) */
// #define FN_ClientUserInfoChanged ClientUserInfoChanged /* pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure */
// #define FN_ServerActivate ServerActivate /* pfnServerActivate() (wd) Server is starting a new map */
// #define FN_ServerDeactivate ServerDeactivate /* pfnServerDeactivate() (wd) Server is leaving the map (shutdown or changelevel); SDK2 */
// #define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */
#define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */
// #define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */
// #define FN_StartFrame StartFrame /* pfnStartFrame() */
#define FN_StartFrame StartFrame /* pfnStartFrame() */
// #define FN_ParmsNewLevel ParmsNewLevel /* pfnParmsNewLevel() */
// #define FN_ParmsChangeLevel ParmsChangeLevel /* pfnParmsChangeLevel() */
// #define FN_GetGameDescription GetGameDescription /* pfnGetGameDescription() Returns string describing current .dll. E.g. "TeamFotrress 2" "Half-Life" */
@ -136,7 +156,7 @@
// #define FN_ClientPutInServer_Post ClientPutInServer_Post
// #define FN_ClientCommand_Post ClientCommand_Post
// #define FN_ClientUserInfoChanged_Post ClientUserInfoChanged_Post
// #define FN_ServerActivate_Post ServerActivate_Post
#define FN_ServerActivate_Post ServerActivate_Post
// #define FN_ServerDeactivate_Post ServerDeactivate_Post
// #define FN_PlayerPreThink_Post PlayerPreThink_Post
// #define FN_PlayerPostThink_Post PlayerPostThink_Post
@ -196,7 +216,7 @@
// #define FN_DropToFloor DropToFloor
// #define FN_WalkMove WalkMove
// #define FN_SetOrigin SetOrigin
// #define FN_EmitSound EmitSound
#define FN_EmitSound EmitSound
// #define FN_EmitAmbientSound EmitAmbientSound
// #define FN_TraceLine TraceLine
// #define FN_TraceToss TraceToss
@ -315,7 +335,7 @@
// - GetEngineAPI_Post functions
// #define FN_PrecacheModel_Post PrecacheModel_Post
// #define FN_PrecacheSound_Post PrecacheSound_Post
// #define FN_SetModel_Post SetModel_Post
#define FN_SetModel_Post SetModel_Post
// #define FN_ModelIndex_Post ModelIndex_Post
// #define FN_ModelFrames_Post ModelFrames_Post
// #define FN_SetSize_Post SetSize_Post

View File

@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "svencoop", "svencoop.vcproj", "{AB148B92-4F47-42E6-8268-AB4E588EC6A2}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Profile = Profile
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{AB148B92-4F47-42E6-8268-AB4E588EC6A2}.Debug.ActiveCfg = Debug|Win32
{AB148B92-4F47-42E6-8268-AB4E588EC6A2}.Debug.Build.0 = Debug|Win32
{AB148B92-4F47-42E6-8268-AB4E588EC6A2}.Profile.ActiveCfg = Release|Win32
{AB148B92-4F47-42E6-8268-AB4E588EC6A2}.Profile.Build.0 = Release|Win32
{AB148B92-4F47-42E6-8268-AB4E588EC6A2}.Release.ActiveCfg = Release|Win32
{AB148B92-4F47-42E6-8268-AB4E588EC6A2}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,204 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="svencoop"
ProjectGUID="{AB148B92-4F47-42E6-8268-AB4E588EC6A2}"
RootNamespace="svencoop"
SccProjectName=""
SccLocalPath="">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SVENCOOP_EXPORTS"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Debug/svencoop.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="Debug/svencoop_amxx.dll"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
ModuleDefinitionFile=""
GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Debug/svencoop_amx_debug.pdb"
ImportLibrary=".\Debug/svencoop_amx_debug.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Debug/cstrike.tlb"
HeaderFileName=""/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1053"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories=""
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SVENCOOP_EXPORTS"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Release/svencoop.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="Release/svencoop_amxx.dll"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
ModuleDefinitionFile=""
ProgramDatabaseFile=".\Release/svencoop_amx.pdb"
ImportLibrary=".\Release/svencoop_amx.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Release/cstrike.tlb"
HeaderFileName=""/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1053"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File
RelativePath="..\moduleconfig.cpp">
</File>
<File
RelativePath="..\svencoop.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl">
<File
RelativePath="..\CString.h">
</File>
<File
RelativePath="..\svencoop.h">
</File>
<File
RelativePath="..\Trie.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
</Filter>
<Filter
Name="AMXX module"
Filter="">
<File
RelativePath="..\amxxmodule.cpp">
</File>
<File
RelativePath="..\amxxmodule.h">
</File>
<File
RelativePath="..\moduleconfig.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

567
dlls/sven/sven/svencoop.cpp Normal file
View File

@ -0,0 +1,567 @@
/* AMX Mod X
* Sven Co-op Module
*
* by the AMX Mod X Development Team
*
* This file is part of AMX Mod X.
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#include "svencoop.h"
//
// GLOBALS
//
const char g_weapon_names[24][24] =
{
"",
"weapon_crowbar",
"weapon_9mmhandgun",
"weapon_357",
"weapon_9mmAR",
"",
"weapon_crossbow",
"weapon_shotgun",
"weapon_rpg",
"weapon_gauss",
"weapon_egon",
"weapon_hornetgun",
"weapon_handgrenade",
"weapon_tripmine",
"weapon_satchel",
"weapon_snark",
"weapon_uziakimbo",
"weapon_uzi",
"weapon_medkit",
"weapon_crowbar_electric",
"weapon_pipewrench",
"weapon_minigun",
"weapon_grapple",
"weapon_sniperrifle"
};
const int g_ammo_offsets[25] =
{
-1, // NONE = 0
0, // SCW_CROWBAR = 1
OFFSET_9MM_AMMO, // SCW_9MMHANDGUN = 2
OFFSET_357_AMMO, // SCW_357 = 3
OFFSET_9MM_AMMO, // SCW_9MMAR = 4
-1, // NONE = 5
OFFSET_CROSSBOW_AMMO, // SCW_CROSSBOW = 6
OFFSET_SHOTGUN_AMMO, // SCW_SHOTGUN = 7
OFFSET_RPG_AMMO, // SCW_RPG = 8
OFFSET_ENERGY_AMMO, // SCW_GAUSS = 9
OFFSET_ENERGY_AMMO, // SCW_EGON = 10
OFFSET_HORNETGUN_AMMO, // SCW_HORNETGUN = 11
OFFSET_HANDGRENADE_AMMO,// SCW_HANDGRENADE = 12
OFFSET_TRIPMINE_AMMO, // SCW_TRIPMINE = 13
OFFSET_SATCHEL_AMMO, // SCW_SATCHEL = 14
OFFSET_SNARK_AMMO, // SCW_SNARK = 15
OFFSET_9MM_AMMO, // SCW_UZIAKIMBO = 16
OFFSET_9MM_AMMO, // SCW_UZI = 17
OFFSET_MEDKIT_AMMO, // SCW_MEDKIT = 18
0, // SCW_CROWBAR_ELECTRIC = 19
0, // SCW_PIPEWRENCH = 20
OFFSET_MINIGUN_AMMO, // SCW_MINIGUN = 21
0, // SCW_GRAPPLE = 22
OFFSET_SNIPERRIFLE_AMMO,// SCW_SNIPERRIFLE = 23
OFFSET_ARGRENADE_AMMO // SCW_ARGRENADE = 24
};
//
// MONSTER NATIVES
//
static cell AMX_NATIVE_CALL sc_get_frags(AMX *amx, cell *params) // sc_get_frags(index); = 1 arguments
{
// Gets a monster's or player's frags
// params[1] = monster/player index
// not CHECK_MONSTER because this works for players
CHECK_ENTITY(params[1]);
edict_t *pEdict = GETEDICT(params[1]);
if(!UTIL_IsPlayer(pEdict) && !UTIL_IsMonster(pEdict))
{
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a player or monster_* entity", params[1], STRING(pEdict->v.classname));
return 0;
}
return amx_ftoc(*((float *)pEdict->pvPrivateData + OFFSET_MONSTER_FRAGS));
}
static cell AMX_NATIVE_CALL sc_set_frags(AMX *amx, cell *params) // sc_set_frags(index, Float:value); = 2 arguments
{
// Sets a monster's or player's frags
// params[1] = index = monster/player index
// params[2] = (float) new frags
// not CHECK_MONSTER because this works for players
CHECK_ENTITY(params[1]);
edict_t *pEdict = GETEDICT(params[1]);
if(!UTIL_IsPlayer(pEdict) && !UTIL_IsMonster(pEdict))
{
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a player or monster_* entity", params[1], STRING(pEdict->v.classname));
return 0;
}
float fValue = amx_ctof(params[2]);
*((float *)pEdict->pvPrivateData + OFFSET_MONSTER_FRAGS) = fValue;
if(UTIL_IsPlayer(pEdict))
{
pEdict->v.frags = fValue;
// update scoreboard
if(gmsgScoreInfo)
{
MESSAGE_BEGIN(MSG_ALL, gmsgScoreInfo);
WRITE_BYTE(params[1]);
WRITE_SHORT((int)fValue);
WRITE_SHORT(*((int *)pEdict->pvPrivateData + OFFSET_PLAYER_DEATHS));
MESSAGE_END();
}
}
return 1;
}
static cell AMX_NATIVE_CALL sc_get_displayname(AMX *amx, cell *params) // sc_get_displayname(index, displayname[], len); = 3 arguments
{
// Gets a monster's displayname
// params[1] = monster index
// params[2] = return variable
// params[3] = variable len
// check non-player (could be squadmaker)
CHECK_NONPLAYER(params[1]);
edict_t *pEdict = INDEXENT(params[1]);
// check valid types
const char *classname = STRING(pEdict->v.classname);
if(strcmp(classname, "squadmaker") != 0 && strncmp(classname, "monster", 7) != 0)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a monstermaker, squadmaker, or monster_* entity", params[1], classname);
return 0;
}
// check for a custom one
const char *displayname = STRING(pEdict->v.message);
if(displayname[0])
{
MF_SetAmxString(amx, params[2], displayname, params[3]);
return 1; // 1 means custom displayname
}
// maybe from a monstermaker? use its displayname.
if(!strncmp(classname, "monster_", 8) && !FNullEnt(pEdict->v.owner))
{
const char *ownerclass = STRING(pEdict->v.owner->v.classname);
if(!strcmp(ownerclass, "squadmaker") || !strcmp(ownerclass, "monstermaker"))
{
displayname = STRING(pEdict->v.owner->v.message);
if(displayname[0])
{
return MF_SetAmxString(amx, params[2], displayname, params[3]);
return 1; // 1 means custom displayname
}
}
}
String *name = NULL;
if(*((int *)pEdict->pvPrivateData + OFFSET_MONSTER_ALLY))
name = g_allyNameTrie.Retrieve(classname, strlen(classname));
else
name = g_enemyNameTrie.Retrieve(classname, strlen(classname));
if(name != NULL)
{
MF_SetAmxString(amx, params[2], name->c_str(), params[3]);
return -1; // -1 means default displayname
}
return 0; // invalid monster
}
static cell AMX_NATIVE_CALL sc_set_displayname(AMX *amx, cell *params) // sc_set_displayname(index, displayname[], {Float,Sql,Result,_}:...); = 2 arguments
{
// Sets a monster's displayname
// params[1] = monster index
// params[2] = new displayname
// params[3...] = formatting
// check non-player (could be squadmaker)
CHECK_NONPLAYER(params[1]);
edict_t *pEdict = INDEXENT(params[1]);
// check valid types
const char *classname = STRING(pEdict->v.classname);
if(strcmp(classname, "squadmaker") != 0 && strncmp(classname, "monster", 7) != 0)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a monstermaker, squadmaker, or monster_* entity", params[1], classname);
return 0;
}
// fetch string
int len = 0;
char *displayname = MF_FormatAmxString(amx, params, 2, &len);
// set_kvd
KeyValueData *kvd = &g_kvd;
kvd->szClassName = const_cast<char *>(classname);
kvd->szKeyName = const_cast<char *>("displayname");
kvd->szValue = const_cast<char *>(displayname);
kvd->fHandled = 0;
gpGamedllFuncs->dllapi_table->pfnKeyValue(pEdict, kvd);
// remember it
pEdict->v.message = ALLOC_STRING(displayname);
return 1;
}
static cell AMX_NATIVE_CALL sc_is_player_ally(AMX *amx, cell *params) // sc_is_player_ally(index); = 1 arguments
{
// Checks if a monster is a player ally
// params[1] = monster index
CHECK_MONSTER(params[1]);
edict_t *pEdict = INDEXENT(params[1]);
return *((int *)pEdict->pvPrivateData + OFFSET_MONSTER_ALLY);
}
//
// PLAYER NATIVES
// (ammo excluded)
//
static cell AMX_NATIVE_CALL sc_get_user_longjump(AMX *amx, cell *params) // sc_get_user_longjump(index); = 1 arguments
{
// Checks if a player can longjump
// params[1] = player index
CHECK_PLAYER(params[1]);
edict_t *pEdict = MF_GetPlayerEdict(params[1]);
const char *buffer = (*g_engfuncs.pfnGetPhysicsKeyValue)(pEdict, "slj");
if(buffer[0] == '1') return 1;
return 0;
}
static cell AMX_NATIVE_CALL sc_set_user_longjump(AMX *amx, cell *params) // sc_set_user_longjump(index, value); = 2 arguments
{
// Sets if a player can longjump
// params[1] = player index
// params[2] = new value
CHECK_PLAYER(params[1]);
edict_t *pEdict = MF_GetPlayerEdict(params[1]);
if(params[2]) (*g_engfuncs.pfnSetPhysicsKeyValue)(pEdict, "slj", "1");
else (*g_engfuncs.pfnSetPhysicsKeyValue)(pEdict, "slj", "0");
return 1;
}
static cell AMX_NATIVE_CALL sc_get_user_deaths(AMX *amx, cell *params) // sc_get_user_deaths(index); = 1 arguments
{
// Gets the number of times a player has died (duh!)
// params[1] = player index
CHECK_PLAYER(params[1]);
edict_t *pEdict = MF_GetPlayerEdict(params[1]);
return *((int *)pEdict->pvPrivateData + OFFSET_PLAYER_DEATHS);
}
static cell AMX_NATIVE_CALL sc_set_user_deaths(AMX *amx, cell *params) // sc_set_user_deaths(index, value); = 2 arguments
{
// Sets the number of times a player has died
// params[1] = player index
// params[2] = new death amount
CHECK_PLAYER(params[1]);
edict_t *pEdict = MF_GetPlayerEdict(params[1]);
*((int *)pEdict->pvPrivateData + OFFSET_PLAYER_DEATHS) = params[2];
// update scoreboard
if(gmsgScoreInfo)
{
MESSAGE_BEGIN(MSG_ALL, gmsgScoreInfo);
WRITE_BYTE(params[1]);
WRITE_SHORT((int)pEdict->v.frags);
WRITE_SHORT(params[2]);
MESSAGE_END();
}
*static_cast<int *>(MF_PlayerPropAddr(params[1], Player_Deaths)) = params[2];
return 1;
}
//
// AMMO NATIVES
//
static cell AMX_NATIVE_CALL sc_get_wbox_ammo(AMX *amx, cell *params) // sc_get_wbox_ammo(index); = 1 arguments
{
// Gets the amount of ammo in dropped ammo weaponbox
// params[1] = weaponbox entity index
CHECK_NONPLAYER(params[1]);
edict_t *pEdict = INDEXENT(params[1]);
if(strcmp(STRING(pEdict->v.classname), "weaponbox") != 0)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a weaponbox entity", params[1], STRING(pEdict->v.classname));
return 0;
}
return *((int *)pEdict->pvPrivateData + OFFSET_WBOX_AMMO);
}
static cell AMX_NATIVE_CALL sc_set_wbox_ammo(AMX *amx, cell *params) // sc_set_wbox_ammo(index, value); = 1 arguments
{
// Sets the amount of ammo in dropped ammo weaponbox
// params[1] = weaponbox entity index
// params[2] = new ammo amount
CHECK_NONPLAYER(params[1]);
edict_t *pEdict = INDEXENT(params[1]);
if(strcmp(STRING(pEdict->v.classname), "weaponbox") != 0)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a weaponbox entity", params[1], STRING(pEdict->v.classname));
return 0;
}
*((int *)pEdict->pvPrivateData + OFFSET_WBOX_AMMO) = params[2];
return 1;
}
static cell AMX_NATIVE_CALL sc_get_weapon_id(AMX *amx, cell *params) // sc_get_weapon_id(index); = 1 arguments
{
// Gets the SCW_* constant of a weapon_* entity
// params[1] = weapon_* entity index
CHECK_NONPLAYER(params[1]);
edict_t *pEdict = INDEXENT(params[1]);
// not a valid weapon_*
if(strncmp(STRING(pEdict->v.classname), "weapon_", 7) != 0)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a weapon_* entity", params[1], STRING(pEdict->v.classname));
return 0;
}
return *((int *)pEdict->pvPrivateData + OFFSET_WEAPON_TYPE);
}
static cell AMX_NATIVE_CALL sc_get_weapon_ammo(AMX *amx, cell *params) // sc_get_weapon_ammo(index1, index2=0); = 2 arguments
{
// Gets the amount of ammo in weapon's clip
// params[1] = weapon_* entity index OR player index
// params[2] = (optional) SCW_* constant if using player index
CHECK_ENTITY(params[1]);
edict_t *pEdict = GETEDICT(params[1]);
// sc_get_weapon_ammo(id, SCW_9MMAR);
if(params[2])
{
if(params[2] < 1 || params[2] > 23 || params[2] == 5)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid weapon index %d", params[2]);
return 0;
}
CHECK_PLAYER(params[1]);
edict_t *pWeapon = NULL;
const char *weaponname = g_weapon_names[params[2]];
while(true)
{
pWeapon = FIND_ENTITY_BY_STRING(pWeapon, "classname", weaponname);
if(FNullEnt(pWeapon) || pWeapon->v.owner == pEdict) break;
}
if(FNullEnt(pWeapon))
{
MF_LogError(amx, AMX_ERR_NATIVE, "Player %d does not have a \"%s\" (index %d)", params[1], weaponname, params[2]);
return 0;
}
return *((int *)pWeapon->pvPrivateData + OFFSET_WEAPON_CLIP);
}
if(strncmp(STRING(pEdict->v.classname), "weapon_", 7) != 0)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a weapon_* entity", params[1], STRING(pEdict->v.classname));
return 0;
}
return *((int *)pEdict->pvPrivateData + OFFSET_WEAPON_CLIP);
}
static cell AMX_NATIVE_CALL sc_set_weapon_ammo(AMX *amx, cell *params) // sc_set_weapon_ammo(index1, value, index2=0); = 3 arguments
{
// Sets the amount of ammo in weapon's clip
// params[1] = weapon_* entity index OR player index
// params[2] = new clip ammo
// params[3] = (optional) SCW_* constant if using player index
CHECK_ENTITY(params[1]);
edict_t *pEdict = GETEDICT(params[1]);
// sc_set_weapon_ammo(id, SCW_9MMAR, 50);
if(params[3])
{
if(params[3] < 1 || params[3] > 23 || params[3] == 5)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid weapon index %d", params[3]);
return 0;
}
CHECK_PLAYER(params[1]);
edict_t *pWeapon = NULL;
const char *weaponname = g_weapon_names[params[3]];
while(true)
{
pWeapon = FIND_ENTITY_BY_STRING(pWeapon, "classname", weaponname);
if(FNullEnt(pWeapon) || pWeapon->v.owner == pEdict) break;
}
if(FNullEnt(pWeapon))
{
MF_LogError(amx, AMX_ERR_NATIVE, "Player %d does not have a \"%s\" (index %d)", params[1], weaponname, params[3]);
return 0;
}
*((int *)pWeapon->pvPrivateData + OFFSET_WEAPON_CLIP) = params[2];
return 1;
}
if(strncmp(STRING(pEdict->v.classname), "weapon_", 7) != 0)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a weapon_* entity", params[1], STRING(pEdict->v.classname));
return 0;
}
*((int *)pEdict->pvPrivateData + OFFSET_WEAPON_CLIP) = params[2];
return 1;
}
static cell AMX_NATIVE_CALL sc_get_user_bpammo(AMX *amx, cell *params) // sc_get_user_bpammo(index, weapon); = 2 arguments
{
// Gets the amount of ammo in player's backpack for a specific weapon
// params[1] = player index
// params[2] = SCW_* constant
CHECK_PLAYER(params[1]);
edict_t *pEdict = MF_GetPlayerEdict(params[1]);
if(params[2] < 1 || params[2] > 23 || params[2] == 5)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid weapon index %d", params[2]);
return 0;
}
// invalid weapon or no bpammo
if(g_ammo_offsets[params[2]] <= 0)
return 0;
return *((int *)pEdict->pvPrivateData + g_ammo_offsets[params[2]]);
}
static cell AMX_NATIVE_CALL sc_set_user_bpammo(AMX *amx, cell *params) // sc_set_user_bpammo(index, weapon, value); = 3 arguments
{
// Gets the amount of ammo in player's backpack for a specific weapon
// params[1] = player index
// params[2] = SCW_* constant
// params[3] = new backpack ammo
CHECK_PLAYER(params[1]);
edict_t *pEdict = MF_GetPlayerEdict(params[1]);
if(params[2] < 1 || params[2] > 23 || params[2] == 5)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid weapon index %d", params[2]);
return 0;
}
// invalid weapon or no bpammo
if(g_ammo_offsets[params[2]] <= 0)
return 0;
*((int *)pEdict->pvPrivateData + g_ammo_offsets[params[2]]) = params[3];
return 1;
}
//
// EXPORT LIST
//
AMX_NATIVE_INFO svencoop_Exports[] =
{
// monster natives
{"sc_get_frags", sc_get_frags},
{"sc_set_frags", sc_set_frags},
{"sc_get_displayname", sc_get_displayname},
{"sc_set_displayname", sc_set_displayname},
{"sc_is_player_ally", sc_is_player_ally},
// player natives
{"sc_get_user_longjump", sc_get_user_longjump},
{"sc_set_user_longjump", sc_set_user_longjump},
{"sc_get_user_deaths", sc_get_user_deaths},
{"sc_set_user_deaths", sc_set_user_deaths},
// ammo natives
{"sc_get_wbox_ammo", sc_get_wbox_ammo},
{"sc_set_wbox_ammo", sc_set_wbox_ammo},
{"sc_get_weapon_id", sc_get_weapon_id},
{"sc_get_weapon_ammo", sc_get_weapon_ammo},
{"sc_set_weapon_ammo", sc_set_weapon_ammo},
{"sc_get_user_bpammo", sc_get_user_bpammo},
{"sc_set_user_bpammo", sc_set_user_bpammo},
//------------------- <-- max 19 characters?? bleh!
{NULL, NULL}
};

239
dlls/sven/sven/svencoop.h Normal file
View File

@ -0,0 +1,239 @@
/* AMX Mod X
* Sven Co-op Module
*
* by the AMX Mod X Development Team
*
* This file is part of AMX Mod X.
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
#include <extdll.h>
#include <meta_api.h>
#include "amxxmodule.h"
#include "CString.h"
#include "Trie.h"
// right now there is no Linux Sven Co-op, but for the future...
#if defined __linux__
#define EXTRAOFFSET_MONSTER 0
#define EXTRAOFFSET_WEAPON 0
#define EXTRAOFFSET_WBOX 0
#define EXTRAOFFSET_PLAYER 0
#else
#define EXTRAOFFSET_MONSTER 0
#define EXTRAOFFSET_WEAPON 0
#define EXTRAOFFSET_WBOX 0
#define EXTRAOFFSET_PLAYER 0
#endif // defined __linux__
// 32-bit
#if !defined __amd64__
#define OFFSET_LAST_HEALTH 834 // arbitrary, our own storage
// monster offsets
#define OFFSET_MONSTER_FRAGS 9 + EXTRAOFFSET_MONSTER
#define OFFSET_MONSTER_ALLY 10 + EXTRAOFFSET_MONSTER
// player offsets (non-ammo)
#define OFFSET_PLAYER_DEATHS 8624 + EXTRAOFFSET_PLAYER
// weapon offsets
#define OFFSET_WEAPON_TYPE 8224 + EXTRAOFFSET_WEAPON
#define OFFSET_WEAPON_CLIP 8233 + EXTRAOFFSET_WBOX
#define OFFSET_WBOX_AMMO 8255 + EXTRAOFFSET_WBOX
// ammo offsets
#define OFFSET_357_AMMO 8563 + EXTRAOFFSET_PLAYER
#define OFFSET_9MM_AMMO 8557 + EXTRAOFFSET_PLAYER
#define OFFSET_CROSSBOW_AMMO 8566 + EXTRAOFFSET_PLAYER
#define OFFSET_SHOTGUN_AMMO 8558 + EXTRAOFFSET_PLAYER
#define OFFSET_RPG_AMMO 8565 + EXTRAOFFSET_PLAYER
#define OFFSET_ENERGY_AMMO 8564 + EXTRAOFFSET_PLAYER
#define OFFSET_HORNETGUN_AMMO 8571 + EXTRAOFFSET_PLAYER
#define OFFSET_HANDGRENADE_AMMO 8569 + EXTRAOFFSET_PLAYER
#define OFFSET_TRIPMINE_AMMO 8567 + EXTRAOFFSET_PLAYER
#define OFFSET_SATCHEL_AMMO 8568 + EXTRAOFFSET_PLAYER
#define OFFSET_SNARK_AMMO 8570 + EXTRAOFFSET_PLAYER
#define OFFSET_MEDKIT_AMMO 8559 + EXTRAOFFSET_PLAYER
#define OFFSET_MINIGUN_AMMO 8560 + EXTRAOFFSET_PLAYER
#define OFFSET_SNIPERRIFLE_AMMO 8561 + EXTRAOFFSET_PLAYER
#define OFFSET_ARGRENADE_AMMO 8562 + EXTRAOFFSET_PLAYER
// 64-bit (no amd64 Sven Co-op, but thinking ahead)
#else
#define OFFSET_OLD_HEALTH 834
// monster offsets
#define OFFSET_MONSTER_FRAGS 9 + EXTRAOFFSET_MONSTER
#define OFFSET_MONSTER_ALLY 10 + EXTRAOFFSET_MONSTER
// player offsets (non-ammo)
#define OFFSET_PLAYER_DEATHS 8624 + EXTRAOFFSET_PLAYER
// weapon offsets
#define OFFSET_WEAPON_TYPE 8224 + EXTRAOFFSET_WEAPON
#define OFFSET_WEAPON_CLIP 8233 + EXTRAOFFSET_WBOX
#define OFFSET_WBOX_AMMO 8255 + EXTRAOFFSET_WBOX
// ammo offsets
#define OFFSET_357_AMMO 8563 + EXTRAOFFSET_PLAYER
#define OFFSET_9MM_AMMO 8557 + EXTRAOFFSET_PLAYER
#define OFFSET_CROSSBOW_AMMO 8566 + EXTRAOFFSET_PLAYER
#define OFFSET_SHOTGUN_AMMO 8558 + EXTRAOFFSET_PLAYER
#define OFFSET_RPG_AMMO 8565 + EXTRAOFFSET_PLAYER
#define OFFSET_ENERGY_AMMO 8564 + EXTRAOFFSET_PLAYER
#define OFFSET_HORNETGUN_AMMO 8571 + EXTRAOFFSET_PLAYER
#define OFFSET_HANDGRENADE_AMMO 8569 + EXTRAOFFSET_PLAYER
#define OFFSET_TRIPMINE_AMMO 8567 + EXTRAOFFSET_PLAYER
#define OFFSET_SATCHEL_AMMO 8568 + EXTRAOFFSET_PLAYER
#define OFFSET_SNARK_AMMO 8570 + EXTRAOFFSET_PLAYER
#define OFFSET_MEDKIT_AMMO 8559 + EXTRAOFFSET_PLAYER
#define OFFSET_MINIGUN_AMMO 8560 + EXTRAOFFSET_PLAYER
#define OFFSET_SNIPERRIFLE_AMMO 8561 + EXTRAOFFSET_PLAYER
#define OFFSET_ARGRENADE_AMMO 8562 + EXTRAOFFSET_PLAYER
#endif
// weapon ids
enum
{
SCW_CROWBAR = 1,
SCW_9MMHANDGUN = 2,
SCW_357 = 3,
SCW_9MMAR = 4,
SCW_CROSSBOW = 6,
SCW_SHOTGUN = 7,
SCW_RPG = 8,
SCW_GAUSS = 9,
SCW_EGON = 10,
SCW_HORNETGUN = 11,
SCW_HANDGRENADE = 12,
SCW_TRIPMINE = 13,
SCW_SATCHEL = 14,
SCW_SNARK = 15,
SCW_UZIAKIMBO = 16,
SCW_UZI = 17,
SCW_MEDKIT = 18,
SCW_CROWBAR_ELECTRIC = 19,
SCW_PIPEWRENCH = 20,
SCW_MINIGUN = 21,
SCW_GRAPPLE = 22,
SCW_SNIPERRIFLE = 23,
SCW_ARGRENADE = 24
};
//
// externs
//
extern AMX_NATIVE_INFO svencoop_Exports[];
extern int gmsgScoreInfo;
extern KeyValueData g_kvd;
extern Trie<char,String> g_allyNameTrie, g_enemyNameTrie;
//
// inline functions
//
inline bool UTIL_IsPlayer(edict_t *pPlayer)
{
if(strcmp(STRING(pPlayer->v.classname), "player") == 0)
return true;
return false;
}
inline bool UTIL_IsMonster(edict_t *pMonster)
{
if(strncmp(STRING(pMonster->v.classname), "monster_", 8) == 0)
return true;
return false;
}
//
// entity checking defines
//
#define CHECK_ENTITY(x) \
if (x <= 0 || x > gpGlobals->maxEntities) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Entity out of range (%d)", x); \
return 0; \
} else { \
if (x <= gpGlobals->maxClients) { \
if (!MF_IsPlayerIngame(x)) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d (not in-game)", x); \
return 0; \
} \
} else { \
if (x != 0 && FNullEnt(INDEXENT(x))) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid entity %d", x); \
return 0; \
} \
} \
}
#define CHECK_PLAYER(x) \
if (x < 1 || x > gpGlobals->maxClients) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Player out of range (%d)", x); \
return 0; \
} else { \
if (!MF_IsPlayerIngame(x) || FNullEnt(MF_GetPlayerEdict(x))) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d", x); \
return 0; \
} \
}
#define CHECK_NONPLAYER(x) \
if (x < 1 || x <= gpGlobals->maxClients || x > gpGlobals->maxEntities) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Non-player entity %d out of range", x); \
return 0; \
} else { \
if (FNullEnt(INDEXENT(x))) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid non-player entity %d", x); \
return 0; \
} \
}
#define CHECK_MONSTER(x) \
if (x < 1 || x <= gpGlobals->maxClients || x > gpGlobals->maxEntities) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Monster entity %d out of range", x); \
return 0; \
} else { \
if (FNullEnt(INDEXENT(x))) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid monster entity %d", x); \
return 0; \
} else { \
if(strncmp(STRING(GETEDICT(x)->v.classname),"monster_",8) != 0) { \
MF_LogError(amx, AMX_ERR_NATIVE, "Entity %d (\"%s\") is not a monster_* entity", x, STRING(GETEDICT(x)->v.classname)); \
return 0; \
} \
} \
}
#define GETEDICT(n) \
((n >= 1 && n <= gpGlobals->maxClients) ? MF_GetPlayerEdict(n) : INDEXENT(n))

104
dlls/sven/sven/svencoop.inc Normal file
View File

@ -0,0 +1,104 @@
/* Sven Co-op functions
*
* by the AMX Mod X Development Team
*
* This file is provided as is (no warranties).
*/
#if defined _svencoop_included
#endinput
#endif
#define _svencoop_included
#include <svencoop_const>
/* Gets a monster's or player's frags */
native Float:sc_get_frags(index);
/* Sets a monster's or player's frags */
native sc_set_frags(index, Float:value);
/* Gets a monster's displayname
Returns 1 if custom displayname, 0 if displayname unavailable, -1 if default displayname
*/
native sc_get_displayname(index, displayname[], len);
/* Sets a monster's displayname */
native sc_set_displayname(index, displayname[], {Float,Sql,Result,_}:...);
/* Checks if a monster is a player ally or not */
native sc_is_player_ally(index);
/* Gets if a player has longjump */
native sc_get_user_longjump(index);
/* Sets if a player has longjump */
native sc_set_user_longjump(index, value);
/* Gets a player's deaths */
native sc_get_user_deaths(index);
/* Sets a player's deaths */
native sc_set_user_deaths(index, value);
/* Gets the amount of ammo in dropped ammo weaponbox */
native sc_get_wbox_ammo(index);
/* Sets the amount of ammo in dropped ammo weaponbox */
native sc_set_wbox_ammo(index, value);
/* Gets a weapon's type (in the form of SCW_* constants)
"index" = weapon_* entity
*/
native sc_get_weapon_id(index);
/* Gets the amount of ammo in weapon's clip
Usage 1:
new weapon = find_ent_by_owner(-1,"weapon_9mmAR",id);
sc_get_weapon_ammo(weapon);
Usage 2:
sc_get_weapon_ammo(id,SCW_9MMAR);
*/
native sc_get_weapon_ammo(index1, index2=0);
/* Sets the amount of ammo in weapon's clip
Usage 1:
new weapon = find_ent_by_owner(-1,"weapon_9mmAR",id);
sc_set_weapon_ammo(weapon,50);
Usage 2:
sc_set_weapon_ammo(id,50,SCW_9MMAR);
*/
native sc_set_weapon_ammo(index1, newammo, index2=0);
/* Gets the amount of ammo in players's backpack for a specific weapon
"weapon" = SCW_* constant
*/
native sc_get_user_bpammo(index, weapon);
/* Sets the amount of ammo in players's backpack for a specific weapon
"weapon" = SCW_* constant
*/
native sc_set_user_bpammo(index, weapon, value);
/* Called whenever a player respawns */
forward sc_client_spawn(index);
/* Called whenever a player or monster throws a grenade
"isplayer" is 1 if the thrower is a player, 0 if a monster
*/
forward sc_grenade_throw(index, greindex, wId, isplayer);
/* Called whenever a player ATTEMPTS to heal another player or monster
(so, they could be healing for 0.0 health, or trying to heal an enemy)
"isplayer" is 1 if the healed entity is a player, 0 if a monster
"isally" is 1 if the healed entity is an ally, 0 if an enemy
*/
forward sc_client_heal(healer, healed, Float:amount, isplayer, isally);

View File

@ -0,0 +1,98 @@
/* Sven Co-op functions
*
* (c) 2007, XxAvalanchexX
* This file is provided as is (no warranties).
*/
#if defined _svencoop_const_included
#endinput
#endif
#define _svencoop_const_included
/* SvenCoop weapons */
enum
{
SCW_CROWBAR = 1,
SCW_9MMHANDGUN = 2, // ammo_9mmAR, ammo_9mmbox, ammo_9mmclip, ammo_glockclip, ammo_mp5clip
SCW_357 = 3, // ammo_357
SCW_9MMAR = 4, // ammo_9mmAR, ammo_9mmbox, ammo_9mmclip, ammo_glockclip, ammo_mp5clip,
SCW_CROSSBOW = 6, // ammo_crossbow
SCW_SHOTGUN = 7, // ammo_buckshot
SCW_RPG = 8, // ammo_rpgclip
SCW_GAUSS = 9, // ammo_egonclip, ammo_gaussclip
SCW_EGON = 10, // ammo_egonclip, ammo_gaussclip
SCW_HORNETGUN = 11,
SCW_HANDGRENADE = 12,
SCW_TRIPMINE = 13,
SCW_SATCHEL = 14,
SCW_SNARK = 15,
SCW_UZIAKIMBO = 16, // ammo_9mmAR, ammo_9mmbox, ammo_9mmclip, ammo_glockclip, ammo_mp5clip
SCW_UZI = 17, // ammo_9mmAR, ammo_9mmbox, ammo_9mmclip, ammo_glockclip, ammo_mp5clip
SCW_MEDKIT = 18,
SCW_CROWBAR_ELECTRIC = 19, // item_battery
SCW_PIPEWRENCH = 20,
SCW_MINIGUN = 21, // ammo_556
SCW_GRAPPLE = 22,
SCW_SNIPERRIFLE = 23, // ammo_762
// USE ONLY FOR sc_*et_user_bpammo NATIVES!
SCW_ARGRENADE = 24 // ammo_ARgrenades, ammo_mp5grenades
};
stock const SCW_MAX_CLIP[25] =
{
-1, // NONE = 0
0, // SCW_CROWBAR = 1
17, // SCW_9MMHANDGUN = 2
6, // SCW_357 = 3
50, // SCW_9MMAR = 4
-1, // NONE = 5
5, // SCW_CROSSBOW = 6
8, // SCW_SHOTGUN = 7
1, // SCW_RPG = 8
0, // SCW_GAUSS = 9
0, // SCW_EGON = 10
0, // SCW_HORNETGUN = 11
0, // SCW_HANDGRENADE = 12
0, // SCW_TRIPMINE = 13
0, // SCW_SATCHEL = 14
0, // SCW_SNARK = 15
32, // SCW_UZIAKIMBO = 16
32, // SCW_UZI = 17
0, // SCW_MEDKIT = 18
0, // SCW_CROWBAR_ELECTRIC = 19
0, // SCW_PIPEWRENCH = 20
0, // SCW_MINIGUN = 21
0, // SCW_GRAPPLE = 22
5, // SCW_SNIPERRIFLE = 23
0 // SCW_ARGRENADE = 24
}
stock const SCW_MAX_AMMO[25] =
{
-1, // NONE = 0
0, // SCW_CROWBAR = 1
250, // SCW_9MMHANDGUN = 2
36, // SCW_357 = 3
250, // SCW_9MMAR = 4
-1, // NONE = 5
50, // SCW_CROSSBOW = 6
125, // SCW_SHOTGUN = 7
5, // SCW_RPG = 8
100, // SCW_GAUSS = 9
100, // SCW_EGON = 10
8, // SCW_HORNETGUN = 11
10, // SCW_HANDGRENADE = 12
5, // SCW_TRIPMINE = 13
5, // SCW_SATCHEL = 14
15, // SCW_SNARK = 15
250, // SCW_UZIAKIMBO = 16
250, // SCW_UZI = 17
100, // SCW_MEDKIT = 18
0, // SCW_CROWBAR_ELECTRIC = 19
0, // SCW_PIPEWRENCH = 20
999, // SCW_MINIGUN = 21
0, // SCW_GRAPPLE = 22
15, // SCW_SNIPERRIFLE = 23
10 // SCW_ARGRENADE = 24
}

View File

@ -1,78 +0,0 @@
#include "svencoop.h"
static cell AMX_NATIVE_CALL sc_get_frags(AMX *amx, cell *params)
{
return GetFrags(params[1]);
}
static cell AMX_NATIVE_CALL sc_set_frags(AMX *amx, cell *params)
{
SetFrags(params[1], params[2]);
return 1;
}
static cell AMX_NATIVE_CALL sc_get_user_deaths(AMX *amx, cell *params)
{
return GetDeaths(params[1]);
}
static cell AMX_NATIVE_CALL sc_set_user_deaths(AMX *amx, cell *params)
{
SetDeaths(params[1], params[2] );
return 1;
}
static cell AMX_NATIVE_CALL sc_is_player_ally(AMX *amx, cell *params)
{
return IsEntAlly(params[1]);
}
static cell AMX_NATIVE_CALL sc_get_weapon_ammo(AMX *amx, cell *params)
{
switch(params[2])
{
case SVEN_WEP_9MM: return GetSvenWeapon(params[1], sven_9mm);
case SVEN_WEP_SHOTGUN: return GetSvenWeapon(params[1], sven_shotgun);
case SVEN_WEP_RPG: return GetSvenWeapon(params[1], sven_rpg);
case SVEN_WEP_RADIO: return GetSvenWeapon(params[1], sven_radio);
case SVEN_WEP_SNARK: return GetSvenWeapon(params[1], sven_snark);
default: MF_LogError(amx, AMX_ERR_NATIVE,"Incorrect weapon specified in SvenCoop Get Weapon Native");
}
return 0;
}
static cell AMX_NATIVE_CALL sc_set_weapon_ammo(AMX *amx, cell *params)
{
switch(params[3])
{
case SVEN_WEP_9MM: return SetSvenWeapon(params[1], params[2], sven_9mm);
case SVEN_WEP_SHOTGUN: return SetSvenWeapon(params[1], params[2], sven_shotgun);
case SVEN_WEP_RPG: return SetSvenWeapon(params[1], params[2], sven_rpg);
case SVEN_WEP_RADIO: return SetSvenWeapon(params[1], params[2], sven_radio);
case SVEN_WEP_SNARK: return SetSvenWeapon(params[1], params[2], sven_snark);
default: MF_LogError(amx, AMX_ERR_NATIVE,"Incorrect weapon specified in SvenCoop Set Weapon Native");
}
return 0;
}
AMX_NATIVE_INFO sven_Natives[] = {
{ "sc_get_frags", sc_get_frags },
{ "sc_set_frags", sc_set_frags },
{ "sc_get_user_deaths", sc_get_user_deaths },
{ "sc_set_user_deaths", sc_set_user_deaths },
{ "sc_is_player_ally", sc_is_player_ally },
{ "sc_get_weapon_ammo", sc_get_weapon_ammo },
{ "sc_set_weapon_ammo", sc_set_weapon_ammo },
{ NULL, NULL }
};
void OnAmxxAttach()
{
MF_AddNatives(sven_Natives);
}

View File

@ -1,48 +0,0 @@
// prevent double include
#ifndef __SVEN_H__
#define __SVEN_H__
#include "amxxmodule.h"
#include "pdata.h"
#include "svencoop_const.h"
inline void SetFrags( long& targetid, long val)
{
SetPData(targetid, PDATA_FRAGS, static_cast<float>(val) );
};
inline long GetFrags( long& targetid)
{
return static_cast<long>( GetPData(targetid, PDATA_FRAGS, float(NULL) ) );
};
inline long GetDeaths( long& targetid)
{
return GetPData(targetid, PDATA_DEATHS, int(NULL) );
};
inline void SetDeaths( long& targetid, long val)
{
SetPData(targetid, PDATA_DEATHS, static_cast<int>(val) );
};
inline long IsEntAlly( long& targetid)
{
return GetPData(targetid, PDATA_ALLY, unsigned char( NULL ) );
};
inline long SetSvenWeapon(long& targetid, long val, const long sven_wep[2])
{
SetPData(targetid, sven_wep[0], static_cast<int>(val) );
SetPData(targetid, sven_wep[1], static_cast<int>(val) );
return 1;
}
inline long GetSvenWeapon(long& targetid, const long sven_wep[2])
{
return GetPData(targetid, sven_wep[0], int(NULL) );
}
#endif

View File

@ -1,33 +0,0 @@
/* Sven Coop Natives
*
* This file is provided as is (no warranties).
*/
#if defined _svencoop_included
#endinput
#endif
#define _svencoop_included
#include <svencoop_const>
#include <svencoop_stocks>
#pragma library svenfun
// Gets/sets the amount of frags a monster or player has.
native Float:sc_get_frags(id);
native sc_set_frags(id,Float:frags);
// Gets/sets the deaths a player has.
native sc_get_user_deaths(id);
native sc_set_user_deaths(id,deaths);
// returns 1 if entity (non-player) is an ally.
native sc_is_player_ally(id);
// Gets the amount of ammo an ent has.
// Use the SVEN_WEP_* defines for type
native sc_get_weapon_ammo(id, type)
// Sets the amount of ammo an ent has.
// Use the SVEN_WEP_* defines for type
native sc_set_weapon_ammo(id, amount, type)

View File

@ -1,34 +0,0 @@
// prevent double include
#ifndef __CONST_H__
#define __CONST_H__
#define PDATA_FRAGS 0x9
#define PDATA_DEATHS 0x21B0
#define PDATA_ALLY 0x28
#define SVEN_WEP_9MM 0
#define PDATA_9MM 0x216D
#define PDATA_9MM2 0x218D
const long sven_9mm[2] = {PDATA_9MM, PDATA_9MM2};
#define SVEN_WEP_SHOTGUN 1
#define PDATA_SHOTGUN 0x216E
#define PDATA_SHOTGUN2 0x218E
const long sven_shotgun[2] = {PDATA_9MM, PDATA_9MM2};
#define SVEN_WEP_RPG 2
#define PDATA_RPG 0x2195
#define PDATA_RPG2 0x21B5
const long sven_rpg[2] = {PDATA_9MM, PDATA_9MM2};
#define SVEN_WEP_RADIO 3
#define PDATA_RADIO 0x217A
#define PDATA_RADIO2 0x219A
const long sven_radio[2] = {PDATA_9MM, PDATA_9MM2};
#define SVEN_WEP_SNARK 4
#define PDATA_SNARK 0x217A
#define PDATA_SNARK2 0x219A
const long sven_snark[2] = {PDATA_9MM, PDATA_9MM2};
#endif

View File

@ -1,38 +0,0 @@
/* Sven Coop Constants
*
* This file is provided as is (no warranties).
*/
#if defined _svencoop_const_included
#endinput
#endif
#define _svencoop_const_included
// The PDATA defines are for using with FM
// The SVEN_WEP_* defines are for sc_ weapon natives
// Please, use the provided stocks.
#define PDATA_FRAGS 0x9
#define PDATA_DEATHS 0x21B0
#define PDATA_ALLY 0x28
#define SVEN_WEP_9MM 0
#define PDATA_9MM 0x216D
#define PDATA_9MM2 0x218D
#define SVEN_WEP_SHOTGUN 1
#define PDATA_SHOTGUN 0x216E
#define PDATA_SHOTGUN2 0x218E
#define SVEN_WEP_RPG 2
#define PDATA_RPG 0x2195
#define PDATA_RPG2 0x21B5
#define SVEN_WEP_RADIO 3
#define PDATA_RADIO 0x217A
#define PDATA_RADIO2 0x219A
#define SVEN_WEP_SNARK 4
#define PDATA_SNARK 0x217A
#define PDATA_SNARK2 0x219A

View File

@ -1,31 +0,0 @@
/* Sven Coop Stocks
*
* This file is provided as is (no warranties).
*/
#if defined _svencoop_stocks_included
#endinput
#endif
#define _svencoop_stocks_included
#include <svencoop_const>
//Stocks for 9mm ammo (mp5, uzi(akimbo))
stock sc_get_bpammo_9mm(id) { return sc_get_weapon_ammo(id,SVEN_WEP_9MM; }
stock sc_set_bpammo_9mm(id, amount) { return sc_set_weapon_ammo(id, amount, SVEN_WEP_9MM; }
//Stocks for RPG ammo (RPG launcher)
stock sc_get_bpammo_rpg(id) { return sc_get_weapon_ammo(id,SVEN_WEP_RPG; }
stock sc_set_bpammo_rpg(id, amount) { return sc_set_weapon_ammo(id, amount, SVEN_WEP_RPG; }
//Stocks for radioactive ammo (gauss, egon)
stock sc_get_bpammo_radio(id) { return sc_get_weapon_ammo(id,SVEN_WEP_RADIO; }
stock sc_set_bpammo_radio(id, amount) { return sc_set_weapon_ammo(id, amount, SVEN_WEP_RADIO; }
//Stocks for snark ammo
stock sc_get_bpammo_snark(id) { return sc_get_weapon_ammo(id,SVEN_WEP_SNARK; }
stock sc_set_bpammo_snark(id, amount) { return sc_set_weapon_ammo(id, amount, SVEN_WEP_SNARK; }
//Stocks for shotgun ammo
stock sc_get_bpammo_shot(id) { return sc_get_weapon_ammo(id,SVEN_WEP_SHOTGUN; }
stock sc_set_bpammo_shot(id, amount) { return sc_set_weapon_ammo(id, amount, SVEN_WEP_SHOTGUN; }

View File

@ -32,6 +32,8 @@
#include "amxxmodule.h"
#include "tfcx.h"
extern int g_AlliesFlags[4];
// Vexd start
// Set A TFC Player's model. This works differently then CS.
@ -429,6 +431,60 @@ static cell AMX_NATIVE_CALL register_forward(AMX *amx, cell *params)
return 1;
}
static cell AMX_NATIVE_CALL TFC_IsFeigning(AMX *amx, cell *params)
{
int index = params[1];
CHECK_PLAYER(index);
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
return (pPlayer->pEdict->v.playerclass == TFC_PC_SPY && pPlayer->pEdict->v.deadflag == 5);
};
cvar_t *mp_teamplay=NULL;
static cell AMX_NATIVE_CALL TFC_IsTeamAlly(AMX *amx, cell *params)
{
if (mp_teamplay==NULL)
{
mp_teamplay=CVAR_GET_POINTER("mp_teamplay");
}
if (mp_teamplay && mp_teamplay->value != 0.0)
{
return 0;
}
int TeamA=params[1];
int TeamB=params[2];
if (TeamA==TeamB) // same team, yes these are allies
{
return 1;
}
if (TeamA==0 || TeamB==0) // spectators
{
return 0;
}
if (TeamA < 1 || TeamA > 4) // out of bounds?
{
MF_LogError(amx,AMX_ERR_NATIVE,"Team A is out of bounds (got %d, expected 0 through 4)",TeamA);
return 0;
}
if (TeamB < 1 || TeamB > 4) // out of bounds?
{
MF_LogError(amx,AMX_ERR_NATIVE,"Team B is out of bounds (got %d, expected 0 through 4)",TeamA);
return 0;
}
if (g_AlliesFlags[--TeamA] & (1<<(--TeamB)))
{
return 1;
}
return 0;
};
// Native list.
AMX_NATIVE_INFO base_Natives[] = {
{"tfc_setmodel", TFC_SetModel},
@ -440,6 +496,10 @@ AMX_NATIVE_INFO base_Natives[] = {
{"tfc_getweaponammo", TFC_GetWeaponAmmo},
{"tfc_setweaponammo", TFC_SetWeaponAmmo},
{"tfc_is_user_feigning", TFC_IsFeigning},
{"tfc_is_team_ally", TFC_IsTeamAlly},
{"tfc_get_user_goalitem", TFC_GetUserGoalItem},
{"xmod_get_wpnname", TFC_GetWpnName},

View File

@ -58,6 +58,8 @@ int mPlayerIndex;
int g_death_info = -1;
int g_damage_info = -1;
int g_AlliesFlags[4];
RankSystem g_rank;
Grenades g_grenades;
@ -167,6 +169,12 @@ void ServerDeactivate() {
g_grenades.clear();
g_AlliesFlags[0]=0;
g_AlliesFlags[1]=0;
g_AlliesFlags[2]=0;
g_AlliesFlags[3]=0;
RETURN_META(MRES_IGNORED);
}
@ -349,6 +357,10 @@ void OnAmxxAttach() {
pdAmmo[TFC_AMMO_NADE1] = PD_AMMO_NADE1;
pdAmmo[TFC_AMMO_NADE2] = PD_AMMO_NADE2;
g_AlliesFlags[0]=0;
g_AlliesFlags[1]=0;
g_AlliesFlags[2]=0;
g_AlliesFlags[3]=0;
}
void OnPluginsLoaded()
@ -357,3 +369,37 @@ void OnPluginsLoaded()
g_death_info = MF_RegisterForward("client_death", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
}
void DispatchKeyValue(edict_t *pentKeyvalue, KeyValueData *pkvd)
{
if (pkvd->szClassName && strcmp(pkvd->szClassName,"info_tfdetect")==0)
{
if (pkvd->szKeyName && strncmp(pkvd->szKeyName,"team",4)==0)
{
if (strcmp(pkvd->szKeyName,"team1_allies")==0 && pkvd->szValue!=NULL)
{
g_AlliesFlags[0]=atoi(pkvd->szValue);
RETURN_META(MRES_IGNORED);
}
else if (strcmp(pkvd->szKeyName,"team2_allies")==0 && pkvd->szValue!=NULL)
{
g_AlliesFlags[1]=atoi(pkvd->szValue);
RETURN_META(MRES_IGNORED);
}
else if (strcmp(pkvd->szKeyName,"team3_allies")==0 && pkvd->szValue!=NULL)
{
g_AlliesFlags[2]=atoi(pkvd->szValue);
RETURN_META(MRES_IGNORED);
}
else if (strcmp(pkvd->szKeyName,"team4_allies")==0 && pkvd->szValue!=NULL)
{
g_AlliesFlags[3]=atoi(pkvd->szValue);
RETURN_META(MRES_IGNORED);
}
}
}
RETURN_META(MRES_IGNORED);
}

View File

@ -88,7 +88,7 @@
// #define FN_DispatchUse DispatchUse /* pfnUse() */
// #define FN_DispatchTouch DispatchTouch /* pfnTouch() */
// #define FN_DispatchBlocked DispatchBlocked /* pfnBlocked() */
// #define FN_DispatchKeyValue DispatchKeyValue /* pfnKeyValue() */
#define FN_DispatchKeyValue DispatchKeyValue /* pfnKeyValue() */
// #define FN_DispatchSave DispatchSave /* pfnSave() */
// #define FN_DispatchRestore DispatchRestore /* pfnRestore() */
// #define FN_DispatchObjectCollsionBox DispatchObjectCollsionBox /* pfnSetAbsBox() */

View File

@ -33,7 +33,7 @@
*/
// Uncomment for SQL version
//#define USING_SQL
// #define USING_SQL
#include <amxmodx>
#include <amxmisc>
@ -41,7 +41,8 @@
#include <sqlx>
#endif
#define MAX_ADMINS 64
new AdminCount;
new PLUGINNAME[] = "AMX Mod X"
#define ADMIN_LOOKUP (1<<0)
@ -50,13 +51,14 @@ new PLUGINNAME[] = "AMX Mod X"
#define ADMIN_IPADDR (1<<3)
#define ADMIN_NAME (1<<4)
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 = 0
new g_cmdLoopback[16]
// pcvars
new amx_mode;
new amx_password_field;
new amx_default_access;
public plugin_init()
{
#if defined USING_SQL
@ -66,9 +68,9 @@ public plugin_init()
#endif
register_dictionary("admin.txt")
register_dictionary("common.txt")
register_cvar("amx_mode", "1")
register_cvar("amx_password_field", "_pw")
register_cvar("amx_default_access", "")
amx_mode=register_cvar("amx_mode", "1")
amx_password_field=register_cvar("amx_password_field", "_pw")
amx_default_access=register_cvar("amx_default_access", "")
register_cvar("amx_vote_ratio", "0.02")
register_cvar("amx_vote_time", "10")
@ -157,13 +159,13 @@ public addadminfn(id, level, cid)
idtype |= ADMIN_LOOKUP
player = cmd_target(id, arg, 10)
} else {
new _steamid[24]
new _steamid[44]
static _players[32], _num, _pv
get_players(_players, _num)
for (new _i=0; _i<_num; _i++)
{
_pv = _players[_i]
get_user_authid(_pv, _steamid, 23)
get_user_authid(_pv, _steamid, sizeof(_steamid)-1)
if (!_steamid[0])
continue
if (equal(_steamid, arg))
@ -229,8 +231,10 @@ public addadminfn(id, level, cid)
read_argv(3, password, 63)
new auth[33]
new Comment[33]; // name of player to pass to comment field
if (idtype & ADMIN_LOOKUP)
{
get_user_name(player, Comment, sizeof(Comment)-1)
if (idtype & ADMIN_STEAM)
{
get_user_authid(player, auth, 32)
@ -259,7 +263,7 @@ public addadminfn(id, level, cid)
else
len += format(type[len], 15-len, "e")
AddAdmin(id, auth, flags, password, type)
AddAdmin(id, auth, flags, password, type, Comment)
cmdReload(id, ADMIN_CFG, 0)
if (player > 0)
@ -272,7 +276,7 @@ public addadminfn(id, level, cid)
return PLUGIN_HANDLED
}
AddAdmin(id, auth[], accessflags[], password[], flags[])
AddAdmin(id, auth[], accessflags[], password[], flags[], comment[]="")
{
#if defined USING_SQL
new error[128], errno
@ -322,7 +326,14 @@ AddAdmin(id, auth[], accessflags[], password[], flags[])
// If we came here, steamid doesn't exist in users.ini. Add it.
new linetoadd[512]
formatex(linetoadd, 511, "^r^n^"%s^" ^"%s^" ^"%s^" ^"%s^"", auth, password, accessflags, flags)
if (comment[0]==0)
{
formatex(linetoadd, 511, "^r^n^"%s^" ^"%s^" ^"%s^" ^"%s^"", auth, password, accessflags, flags)
}
else
{
formatex(linetoadd, 511, "^r^n^"%s^" ^"%s^" ^"%s^" ^"%s^" ; %s", auth, password, accessflags, flags, comment)
}
console_print(id, "Adding:^n%s", linetoadd)
if (!write_file(configsDir, linetoadd))
@ -357,49 +368,95 @@ AddAdmin(id, auth[], accessflags[], password[], flags[])
}
public plugin_cfg()
{
new configFile[64], curMap[32]
get_configsdir(configFile, 31)
get_mapname(curMap, 31)
new len = format(configFile, 63, "%s/maps/%s.cfg", configFile, curMap)
if (file_exists(configFile))
set_task(6.1, "delayed_load", 0, configFile, len + 1)
set_task(6.1, "delayed_load")
}
public delayed_load(configFile[])
public delayed_load()
{
server_cmd("exec %s", configFile)
new configFile[128], curMap[64], configDir[128]
get_configsdir(configDir, sizeof(configDir)-1)
get_mapname(curMap, sizeof(curMap)-1)
new i=0;
while (curMap[i] != '_' && curMap[i++] != '^0') {/*do nothing*/}
if (curMap[i]=='_')
{
// this map has a prefix
curMap[i]='^0';
formatex(configFile, sizeof(configFile)-1, "%s/maps/prefix_%s.cfg", configDir, curMap);
if (file_exists(configFile))
{
server_cmd("exec %s", configFile);
}
}
get_mapname(curMap, sizeof(curMap)-1)
formatex(configFile, sizeof(configFile)-1, "%s/maps/%s.cfg", configDir, curMap)
if (file_exists(configFile))
{
server_cmd("exec %s", configFile)
}
}
loadSettings(szFilename[])
{
if (!file_exists(szFilename))
return 0
new File=fopen(szFilename,"r");
new szText[256], szFlags[32], szAccess[32]
new a, pos = 0
while (g_aNum < MAX_ADMINS && read_file(szFilename, pos++, szText, 255, a))
if (File)
{
if (szText[0] == ';')
continue
new Text[512];
new Flags[32];
new Access[32]
new AuthData[44];
new Password[32];
if (parse(szText, g_aName[g_aNum], 31, g_aPassword[g_aNum], 31, szAccess, 31, szFlags, 31) < 2)
continue
while (!feof(File))
{
fgets(File,Text,sizeof(Text)-1);
g_aAccess[g_aNum] = read_flags(szAccess)
g_aFlags[g_aNum] = read_flags(szFlags)
++g_aNum
// comment
if (Text[0]==';')
{
continue;
}
Flags[0]=0;
Access[0]=0;
AuthData[0]=0;
Password[0]=0;
// not enough parameters
if (parse(Text,AuthData,sizeof(AuthData)-1,Password,sizeof(Password)-1,Access,sizeof(Access)-1,Flags,sizeof(Flags)-1) < 2)
{
continue;
}
admins_push(AuthData,Password,read_flags(Access),read_flags(Flags));
AdminCount++;
}
fclose(File);
}
if (g_aNum == 1)
server_print("[AMXX] %L", LANG_SERVER, "LOADED_ADMIN")
if (AdminCount == 1)
{
server_print("[AMXX] %L", LANG_SERVER, "LOADED_ADMIN");
}
else
server_print("[AMXX] %L", LANG_SERVER, "LOADED_ADMINS", g_aNum)
{
server_print("[AMXX] %L", LANG_SERVER, "LOADED_ADMINS", AdminCount);
}
return 1
return 1;
}
#if defined USING_SQL
@ -450,9 +507,8 @@ public adminSql()
} else if (!SQL_NumResults(query)) {
server_print("[AMXX] %L", LANG_SERVER, "NO_ADMINS")
} else {
new szFlags[32], szAccess[32]
g_aNum = 0
AdminCount = 0
/** do this incase people change the query order and forget to modify below */
new qcolAuth = SQL_FieldNameToNum(query, "auth")
@ -460,25 +516,32 @@ public adminSql()
new qcolAccess = SQL_FieldNameToNum(query, "access")
new qcolFlags = SQL_FieldNameToNum(query, "flags")
while ((g_aNum < MAX_ADMINS) && (SQL_MoreResults(query)))
new AuthData[44];
new Password[44];
new Access[32];
new Flags[32];
while (SQL_MoreResults(query))
{
SQL_ReadResult(query, qcolAuth, g_aName[g_aNum], 31)
SQL_ReadResult(query, qcolPass, g_aPassword[g_aNum], 31)
SQL_ReadResult(query, qcolAccess, szAccess, 31)
SQL_ReadResult(query, qcolFlags, szFlags, 31)
SQL_ReadResult(query, qcolAuth, AuthData, sizeof(AuthData)-1);
SQL_ReadResult(query, qcolPass, Password, sizeof(Password)-1);
SQL_ReadResult(query, qcolAccess, Access, sizeof(Access)-1);
SQL_ReadResult(query, qcolFlags, Flags, sizeof(Flags)-1);
g_aAccess[g_aNum] = read_flags(szAccess)
admins_push(AuthData,Password,read_flags(Access),read_flags(Flags));
g_aFlags[g_aNum] = read_flags(szFlags)
++g_aNum
++AdminCount;
SQL_NextRow(query)
}
if (g_aNum == 1)
if (AdminCount == 1)
{
server_print("[AMXX] %L", LANG_SERVER, "SQL_LOADED_ADMIN")
}
else
server_print("[AMXX] %L", LANG_SERVER, "SQL_LOADED_ADMINS", g_aNum)
{
server_print("[AMXX] %L", LANG_SERVER, "SQL_LOADED_ADMINS", AdminCount)
}
SQL_FreeHandle(query)
SQL_FreeHandle(sql)
@ -503,26 +566,30 @@ public cmdReload(id, level, cid)
get_configsdir(filename, 127)
format(filename, 63, "%s/users.ini", filename)
g_aNum = 0
loadSettings(filename) // Re-Load admins accounts
AdminCount = 0;
loadSettings(filename); // Re-Load admins accounts
if (id != 0)
{
if (g_aNum == 1)
console_print(id, "[AMXX] %L", LANG_SERVER, "LOADED_ADMIN")
if (AdminCount == 1)
{
console_print(id, "[AMXX] %L", LANG_SERVER, "LOADED_ADMIN");
}
else
console_print(id, "[AMXX] %L", LANG_SERVER, "LOADED_ADMINS", g_aNum)
{
console_print(id, "[AMXX] %L", LANG_SERVER, "LOADED_ADMINS", AdminCount);
}
}
#else
g_aNum = 0
AdminCount = 0
adminSql()
if (id != 0)
{
if (g_aNum == 1)
if (AdminCount == 1)
console_print(id, "[AMXX] %L", LANG_SERVER, "SQL_LOADED_ADMIN")
else
console_print(id, "[AMXX] %L", LANG_SERVER, "SQL_LOADED_ADMINS", g_aNum)
console_print(id, "[AMXX] %L", LANG_SERVER, "SQL_LOADED_ADMINS", AdminCount)
}
#endif
@ -544,43 +611,55 @@ getAccess(id, name[], authid[], ip[], password[])
new index = -1
new result = 0
for (new i = 0; i < g_aNum; ++i)
static Count;
static Flags;
static Access;
static AuthData[44];
static Password[32];
Count=admins_num();
for (new i = 0; i < Count; ++i)
{
if (g_aFlags[i] & FLAG_AUTHID)
Flags=admins_lookup(i,AdminProp_Flags);
admins_lookup(i,AdminProp_Auth,AuthData,sizeof(AuthData)-1);
if (Flags & FLAG_AUTHID)
{
if (equal(authid, g_aName[i]))
if (equal(authid, AuthData))
{
index = i
break
}
}
else if (g_aFlags[i] & FLAG_IP)
else if (Flags & FLAG_IP)
{
new c = strlen(g_aName[i])
new c = strlen(AuthData)
if (g_aName[i][c - 1] == '.') /* check if this is not a xxx.xxx. format */
if (AuthData[c - 1] == '.') /* check if this is not a xxx.xxx. format */
{
if (equal(g_aName[i], ip, c))
if (equal(AuthData, ip, c))
{
index = i
break
}
} /* in other case an IP must just match */
else if (equal(ip, g_aName[i]))
else if (equal(ip, AuthData))
{
index = i
break
}
} else {
if (g_aFlags[i] & FLAG_TAG)
}
else
{
if (Flags & FLAG_TAG)
{
if (containi(name, g_aName[i]) != -1)
if (containi(name, AuthData) != -1)
{
index = i
break
}
}
else if (equali(name, g_aName[i]))
else if (equali(name, AuthData))
{
index = i
break
@ -590,45 +669,59 @@ getAccess(id, name[], authid[], ip[], password[])
if (index != -1)
{
if (g_aFlags[index] & FLAG_NOPASS)
Access=admins_lookup(index,AdminProp_Access);
if (Flags & FLAG_NOPASS)
{
result |= 8
new sflags[32]
get_flags(g_aAccess[index], sflags, 31)
set_user_flags(id, g_aAccess[index])
get_flags(Access, sflags, 31)
set_user_flags(id, Access)
log_amx("Login: ^"%s<%d><%s><>^" became an admin (account ^"%s^") (access ^"%s^") (address ^"%s^")", name, get_user_userid(id), authid, g_aName[index], sflags, ip)
log_amx("Login: ^"%s<%d><%s><>^" became an admin (account ^"%s^") (access ^"%s^") (address ^"%s^")", name, get_user_userid(id), authid, AuthData, sflags, ip)
}
else if (equal(password, g_aPassword[index]))
else
{
result |= 12
set_user_flags(id, g_aAccess[index])
new sflags[32]
get_flags(g_aAccess[index], sflags, 31)
admins_lookup(index,AdminProp_Password,Password,sizeof(Password)-1);
log_amx("Login: ^"%s<%d><%s><>^" became 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)
if (equal(password, Password))
{
result |= 2
log_amx("Login: ^"%s<%d><%s><>^" kicked due to invalid password (account ^"%s^") (address ^"%s^")", name, get_user_userid(id), authid, g_aName[index], ip)
result |= 12
set_user_flags(id, Access)
new sflags[32]
get_flags(Access, sflags, 31)
log_amx("Login: ^"%s<%d><%s><>^" became an admin (account ^"%s^") (access ^"%s^") (address ^"%s^")", name, get_user_userid(id), authid, AuthData, sflags, ip)
}
else
{
result |= 1
if (Flags & FLAG_KICK)
{
result |= 2
log_amx("Login: ^"%s<%d><%s><>^" kicked due to invalid password (account ^"%s^") (address ^"%s^")", name, get_user_userid(id), authid, AuthData, ip)
}
}
}
}
else if (get_cvar_float("amx_mode") == 2.0)
else if (get_pcvar_float(amx_mode) == 2.0)
{
result |= 2
} else {
}
else
{
new defaccess[32]
get_cvar_string("amx_default_access", defaccess, 31)
get_pcvar_string(amx_default_access, defaccess, 31)
if (!strlen(defaccess))
{
copy(defaccess, 32, "z")
}
new idefaccess = read_flags(defaccess)
@ -660,7 +753,7 @@ accessUser(id, name[] = "")
get_user_name(id, username, 31)
}
get_cvar_string("amx_password_field", passfield, 31)
get_pcvar_string(amx_password_field, passfield, 31)
get_user_info(id, passfield, password, 31)
new result = getAccess(id, username, userauthid, userip, password)
@ -691,7 +784,7 @@ accessUser(id, name[] = "")
public client_infochanged(id)
{
if (!is_user_connected(id) || !get_cvar_num("amx_mode"))
if (!is_user_connected(id) || !get_pcvar_num(amx_mode))
{
return PLUGIN_CONTINUE
}
@ -712,15 +805,16 @@ public client_infochanged(id)
public ackSignal(id)
{
server_cmd("kick #%d ^"%L^"", get_user_userid(id), id, "NO_ENTRY")
return PLUGIN_HANDLED
}
public client_authorized(id)
return get_cvar_num("amx_mode") ? accessUser(id) : PLUGIN_CONTINUE
return get_pcvar_num(amx_mode) ? accessUser(id) : PLUGIN_CONTINUE
public client_putinserver(id)
{
if (!is_dedicated_server() && id == 1)
return get_cvar_num("amx_mode") ? accessUser(id) : PLUGIN_CONTINUE
return get_pcvar_num(amx_mode) ? accessUser(id) : PLUGIN_CONTINUE
return PLUGIN_CONTINUE
}

View File

@ -45,11 +45,16 @@ new bool:g_Paused
new bool:g_PauseAllowed = false
new g_addCvar[] = "amx_cvar add %s"
new amx_show_activity;
new pausable;
new rcon_password;
public plugin_init()
{
register_plugin("Admin Commands", AMXX_VERSION_STR, "AMXX Dev Team")
register_dictionary("admincmd.txt")
register_dictionary("common.txt")
register_dictionary("adminhelp.txt")
register_concmd("amx_kick", "cmdKick", ADMIN_KICK, "<name or #userid> [reason]")
register_concmd("amx_ban", "cmdBan", ADMIN_BAN, "<name or #userid> <minutes> [reason]")
register_concmd("amx_banip", "cmdBanIP", ADMIN_BAN, "<name or #userid> <minutes> [reason]")
@ -69,6 +74,18 @@ public plugin_init()
register_clcmd("amx_rcon", "cmdRcon", ADMIN_RCON, "<command line>")
register_clcmd("amx_showrcon", "cmdShowRcon", ADMIN_RCON, "<command line>")
register_clcmd("pauseAck", "cmdLBack")
rcon_password=get_cvar_pointer("rcon_password");
pausable=get_cvar_pointer("pausable");
amx_show_activity=get_cvar_pointer("amx_show_activity");
if (amx_show_activity==0) // cvar does not exist, register it
{
amx_show_activity=register_cvar("amx_show_activity", "2");
}
}
public plugin_cfg()
@ -108,7 +125,7 @@ public cmdKick(id, level, cid)
log_amx("Kick: ^"%s<%d><%s><>^" kick ^"%s<%d><%s><>^" (reason ^"%s^")", name, get_user_userid(id), authid, name2, userid2, authid2, reason)
switch (get_cvar_num("amx_show_activity"))
switch (get_pcvar_num(amx_show_activity))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_KICK_2", name, name2)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_KICK_1", name2)
@ -149,7 +166,7 @@ public cmdUnban(id, level, cid)
get_user_name(id, name, 31)
switch (get_cvar_num("amx_show_activity"))
switch (get_pcvar_num(amx_show_activity))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_UNBAN_2", name, arg)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_UNBAN_1", arg)
@ -183,7 +200,7 @@ public cmdAddBan(id, level, cid)
get_user_name(id, name, 31)
switch (get_cvar_num("amx_show_activity"))
switch (get_pcvar_num(amx_show_activity))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_ADDBAN_2", name, arg)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_ADDBAN_1", arg)
@ -234,7 +251,7 @@ public cmdBan(id, level, cid)
else
server_cmd("kick #%d ^"%s %s^";wait;banid ^"%s^" ^"%s^";wait;writeid", userid2, banned, temp, minutes, authid2)
new activity = get_cvar_num("amx_show_activity")
new activity = get_pcvar_num(amx_show_activity)
if (activity != 0)
{
new players[32], pnum, msg[256], len
@ -306,7 +323,7 @@ public cmdBanIP(id, level, cid)
else
server_cmd("kick #%d ^"%s %s^";wait;addip ^"%s^" ^"%s^";wait;writeip", userid2, banned, temp, minutes, address)
new activity = get_cvar_num("amx_show_activity")
new activity = get_pcvar_num(amx_show_activity)
if (activity != 0)
{
new players[32], pnum, msg[256], len
@ -362,7 +379,7 @@ public cmdSlay(id, level, cid)
log_amx("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"))
switch (get_pcvar_num(amx_show_activity))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_SLAY_2", name, name2)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_SLAY_1", name2)
@ -400,7 +417,7 @@ public cmdSlap(id, level, cid)
log_amx("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"))
switch (get_pcvar_num(amx_show_activity))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_SLAP_2", name, name2, damage)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_SLAP_1", name2, damage)
@ -434,7 +451,7 @@ public cmdMap(id, level, cid)
get_user_authid(id, authid, 31)
get_user_name(id, name, 31)
switch (get_cvar_num("amx_show_activity"))
switch (get_pcvar_num(amx_show_activity))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_MAP_2", name, arg)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_MAP_1", arg)
@ -474,6 +491,8 @@ public cmdCvar(id, level, cid)
read_argv(1, arg, 31)
read_argv(2, arg2, 63)
new pointer;
if (equal(arg, "add") && (get_user_flags(id) & ADMIN_RCON))
{
if (cvar_exists(arg2))
@ -486,7 +505,7 @@ public cmdCvar(id, level, cid)
return PLUGIN_HANDLED
}
if (!cvar_exists(arg))
if ((pointer=get_cvar_pointer(arg))==0)
{
console_print(id, "[AMXX] %L", id, "UNKNOWN_CVAR", arg)
return PLUGIN_HANDLED
@ -497,7 +516,7 @@ public cmdCvar(id, level, cid)
console_print(id, "[AMXX] %L", id, "CVAR_NO_ACC")
return PLUGIN_HANDLED
}
else if (equal(arg, "sv_password") && !(get_user_flags(id) & ADMIN_PASSWORD))
else if (equali(arg, "sv_password") && !(get_user_flags(id) & ADMIN_PASSWORD))
{
console_print(id, "[AMXX] %L", id, "CVAR_NO_ACC")
return PLUGIN_HANDLED
@ -505,7 +524,7 @@ public cmdCvar(id, level, cid)
if (read_argc() < 3)
{
get_cvar_string(arg, arg2, 63)
get_pcvar_string(pointer, arg2, 63)
console_print(id, "[AMXX] %L", id, "CVAR_IS", arg, arg2)
return PLUGIN_HANDLED
}
@ -518,7 +537,8 @@ public cmdCvar(id, level, cid)
log_amx("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")
new activity = get_pcvar_num(amx_show_activity)
if (activity != 0)
{
new players[32], pnum, admin[64], cvar_val[64], len
@ -533,12 +553,12 @@ public cmdCvar(id, level, cid)
else
len += format(admin[len], 255-len, " %s:", name)
if (equal(arg, "rcon_password") || equal(arg, "sv_password"))
if (get_pcvar_flags(pointer) & FCVAR_PROTECTED || equali(arg,"rcon_password"))
format(cvar_val, 63, "*** %L ***", players[i], "PROTECTED")
else
copy(cvar_val, 63, arg2)
client_print(players[i], print_chat, "%L", players[i], "SET_CVAR_TO", admin, arg, arg2)
client_print(players[i], print_chat, "%L", players[i], "SET_CVAR_TO", admin, arg, cvar_val)
}
}
console_print(id, "[AMXX] %L", id, "CVAR_CHANGED", arg, arg2)
@ -551,6 +571,12 @@ public cmdPlugins(id, level, cid)
if (!cmd_access(id, level, cid, 1))
return PLUGIN_HANDLED
if (id==0) // If server executes redirect this to "amxx plugins" for more in depth output
{
server_cmd("amxx plugins");
return PLUGIN_HANDLED;
}
new name[32], version[32], author[32], filename[32], status[32]
new lName[32], lVersion[32], lAuthor[32], lFile[32], lStatus[32]
@ -560,21 +586,50 @@ public cmdPlugins(id, level, cid)
format(lFile, 31, "%L", id, "FILE")
format(lStatus, 31, "%L", id, "STATUS")
new StartPLID=0;
new EndPLID;
new Temp[96]
new num = get_pluginsnum()
if (read_argc() > 1)
{
read_argv(1,Temp,sizeof(Temp)-1);
StartPLID=str_to_num(Temp)-1; // zero-based
}
EndPLID=min(StartPLID + 10, num);
new running = 0
console_print(id, "%L:", id, "LOADED_PLUGINS")
console_print(id, "----- %L -----", id, "LOADED_PLUGINS")
console_print(id, "%-18.17s %-8.7s %-17.16s %-16.15s %-9.8s", lName, lVersion, lAuthor, lFile, lStatus)
for (new i = 0; i <num; i++)
new i=StartPLID;
while (i <EndPLID)
{
get_plugin(i, filename, 31, name, 31, version, 31, author, 31, status, 31)
get_plugin(i++, filename, 31, name, 31, version, 31, author, 31, status, 31)
console_print(id, "%-18.17s %-8.7s %-17.16s %-16.15s %-9.8s", name, version, author, filename, status)
if (status[0]=='d' || status[0]=='r') // "debug" or "running"
running++
}
console_print(id, "%L", id, "PLUGINS_RUN", num, running)
console_print(id, "%L", id, "PLUGINS_RUN", EndPLID-StartPLID, running)
console_print(id, "----- %L -----",id,"HELP_ENTRIES",StartPLID + 1,EndPLID,num);
if (EndPLID < num)
{
formatex(Temp,sizeof(Temp)-1,"----- %L -----",id,"HELP_USE_MORE", EndPLID + 1);
replace_all(Temp,sizeof(Temp)-1,"amx_help","amx_plugins");
console_print(id,"%s",Temp);
}
else
{
formatex(Temp,sizeof(Temp)-1,"----- %L -----",id,"HELP_USE_BEGIN");
replace_all(Temp,sizeof(Temp)-1,"amx_help","amx_plugins");
console_print(id,"%s",Temp);
}
return PLUGIN_HANDLED
}
@ -637,7 +692,7 @@ public cmdCfg(id, level, cid)
console_print(id, "[AMXX] Executing file ^"%s^"", arg)
server_cmd("exec %s", arg)
switch(get_cvar_num("amx_show_activity"))
switch(get_pcvar_num(amx_show_activity))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_CONF_2", name, arg)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_CONF_1", arg)
@ -675,7 +730,10 @@ public cmdPause(id, level, cid)
get_user_authid(id, authid, 31)
get_user_name(id, name, 31)
g_pausAble = get_cvar_float("pausable")
if (pausable!=0)
{
g_pausAble = get_pcvar_float(pausable)
}
if (!slayer)
slayer = find_player("h")
@ -694,7 +752,7 @@ public cmdPause(id, level, cid)
console_print(id, "[AMXX] %L", id, g_Paused ? "UNPAUSING" : "PAUSING")
new activity = get_cvar_num("amx_show_activity")
new activity = get_pcvar_num(amx_show_activity)
if (activity != 0)
{
new players[32], pnum, msg[128], len
@ -725,7 +783,7 @@ public cmdShowRcon(id, level, cid)
new password[64]
get_cvar_string("rcon_password", password, 63)
get_pcvar_string(rcon_password, password, 63)
if (!password[0])
{
@ -862,7 +920,7 @@ public cmdLeave(id, level, cid)
get_user_name(id, name, 31)
log_amx("Kick: ^"%s<%d><%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"))
switch(get_pcvar_num(amx_show_activity))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_LEAVE_2", name, ltags[0], ltags[1], ltags[2], ltags[3])
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_LEAVE_1", ltags[0], ltags[1], ltags[2], ltags[3])
@ -895,7 +953,7 @@ public cmdNick(id, level, cid)
log_amx("Cmd: ^"%s<%d><%s><>^" change nick to ^"%s^" ^"%s<%d><%s><>^"", name, get_user_userid(id), authid, arg2, name2, get_user_userid(player), authid2)
switch (get_cvar_num("amx_show_activity"))
switch (get_pcvar_num(amx_show_activity))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_NICK_2", name, name2, arg2)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_NICK_1", name2, arg2)

View File

@ -72,6 +72,8 @@ public ackSignal(id)
new lReason[64]
format(lReason, 63, "%L", id, "DROPPED_RES")
server_cmd("kick #%d ^"%s^"", get_user_userid(id), lReason)
return PLUGIN_HANDLED
}
public client_authorized(id)

View File

@ -37,18 +37,20 @@
new Float:g_Flooding[33] = {0.0, ...}
new g_Flood[33] = {0, ...}
new amx_flood_time;
public plugin_init()
{
register_plugin("Anti Flood", AMXX_VERSION_STR, "AMXX Dev Team")
register_dictionary("antiflood.txt")
register_clcmd("say", "chkFlood")
register_clcmd("say_team", "chkFlood")
register_cvar("amx_flood_time", "0.75")
amx_flood_time=register_cvar("amx_flood_time", "0.75")
}
public chkFlood(id)
{
new Float:maxChat = get_cvar_float("amx_flood_time")
new Float:maxChat = get_pcvar_float(amx_flood_time)
if (maxChat)
{

View File

@ -60,6 +60,7 @@ public plugin_init()
register_dictionary("plmenu.txt")
register_dictionary("common.txt")
register_dictionary("admincmd.txt")
register_clcmd("amx_kickmenu", "cmdKickMenu", ADMIN_KICK, "- displays kick menu")
register_clcmd("amx_banmenu", "cmdBanMenu", ADMIN_BAN, "- displays ban menu")
@ -120,8 +121,32 @@ public actionBanMenu(id, key)
switch (get_cvar_num("amx_show_activity"))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_BAN_2", name, name2)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_BAN_1", name2)
case 2:
{
if (g_menuSettings[id]==0) // permanent
{
client_print(0, print_chat, "%L %s: %L %s %L", LANG_PLAYER, "ADMIN", name, LANG_PLAYER, "BAN", name2, LANG_PLAYER, "PERM");
}
else
{
new tempTime[32];
formatex(tempTime,sizeof(tempTime)-1,"%d",g_menuSettings[id]);
client_print(0, print_chat, "%L %s: %L %s %L", LANG_PLAYER, "ADMIN", name, LANG_PLAYER, "BAN", name2, LANG_PLAYER, "FOR_MIN", tempTime);
}
}
case 1:
{
if (g_menuSettings[id]==0) // permanent
{
client_print(0, print_chat, "%L: %L %s %L", LANG_PLAYER, "ADMIN", LANG_PLAYER, "BAN", name2, LANG_PLAYER, "PERM");
}
else
{
new tempTime[32];
formatex(tempTime,sizeof(tempTime)-1,"%d",g_menuSettings[id]);
client_print(0, print_chat, "%L: %L %s %L", LANG_PLAYER, "ADMIN", LANG_PLAYER, "BAN", name2, LANG_PLAYER, "FOR_MIN", tempTime);
}
}
}
if (equal("4294967295", authid2))

View File

@ -312,3 +312,11 @@ enum LibType
LibType_Library,
LibType_Class
};
enum AdminProp
{
AdminProp_Auth = 0,
AdminProp_Password,
AdminProp_Access,
AdminProp_Flags
};

View File

@ -310,3 +310,19 @@ stock constraint_offset(low, high, seed, offset)
return 0; // Makes the compiler happy -_-
}
/* Returns true if the user has ANY of the provided flags
* false if they have none
*/
stock has_flag(id, const flags[])
{
return (get_user_flags(id) & read_flags(flags));
}
/* Returns true if the user has ALL of the provided flags
* false otherwise
*/
stock has_all_flags(id, const flags[])
{
new FlagsNumber=read_flags(flags);
return ((get_user_flags(id) & FlagsNumber)==FlagsNumber);
}

View File

@ -239,7 +239,7 @@ native user_has_weapon(index,weapon,setweapon=-1);
/* Returns id of currently carried weapon. Gets also
* ammount of ammo in clip and backpack. */
native get_user_weapon(index,&clip,&ammo);
native get_user_weapon(index,&clip=0,&ammo=0);
/* Gets ammo and clip from current weapon. */
native get_user_ammo(index,weapon,&clip,&ammo);
@ -474,14 +474,18 @@ native get_user_flags(index,id=0);
native remove_user_flags(index,flags=-1,id=0);
/* Registers function which will be called from client console.
* Set FlagManager to 1 to make FlagManager always include this command
* Set FlagManager to 0 to make FlagManager never include this command
* Returns the command ID.
*/
native register_clcmd(const client_cmd[],const function[],flags=-1, const info[]="");
native register_clcmd(const client_cmd[],const function[],flags=-1, const info[]="", FlagManager=-1);
/* Registers function which will be called from any console.
* Set FlagManager to 1 to make FlagManager always include this command
* Set FlagManager to 0 to make FlagManager never include this command
* Returns the command ID.
*/
native register_concmd(const cmd[],const function[],flags=-1, const info[]="");
native register_concmd(const cmd[],const function[],flags=-1, const info[]="", FlagManager=-1);
/* Registers function which will be called from server console.
* Returns the command ID.
@ -609,7 +613,7 @@ native is_plugin_loaded(const name[]);
* Note: the [...] portion should not be used, and is only for backward compatibility.
* Use index of -1 to use the calling plugin's ID.
*/
native get_plugin(index,filename[],len1,name[],len2,version[],len3,author[],len4,status[],len5,...);
native get_plugin(index,filename[]="",len1=0,name[]="",len2=0,version[]="",len3=0,author[]="",len4=0,status[]="",len5=0,...);
/* Returns number of all loaded plugins. */
native get_pluginsnum();
@ -826,7 +830,8 @@ native menu_destroy(menu);
//Gets info about a player's menu. Returns 1 if the player is viewing a menu.
//menu will be >0 for a valid oldmenu. newmenu will be != -1 for a valid newmenu.
native player_menu_info(id, &menu, &newmenu);
//As of 1.77, there is an optional page parameter.
native player_menu_info(id, &menu, &newmenu, &menupage=0);
//adds a blank line to a menu.
//if slot is nonzero (default), the blank line will increase
@ -1080,6 +1085,7 @@ native set_pcvar_num(pcvar, num);
native Float:get_pcvar_float(pcvar);
native set_pcvar_float(pcvar, Float:num);
native get_pcvar_string(pcvar, string[], maxlen);
native set_pcvar_string(pcvar, const string[]);
/**
* Sets a whole array to a certain value.
@ -1092,5 +1098,29 @@ native arrayset(array[], value, size);
*/
native get_weaponid(const name[]);
/**
* Adds an admin to the dynamic admin storage
* for lookup at a later time
*/
native admins_push(const AuthData[], const Password[], Access, Flags);
/**
* Gets the number of admins in the dynamic admin
* storage list
*/
native admins_num();
/**
* Gets information about a dynamically stored admin
* Use the enum AdminProp
* Returns an integer value: AdminProp_Access, AdminProp_Flags
* Sets the buffer string: AdminProp_Auth, AdminProp_Password
*/
native admins_lookup(num, AdminProp:Property, Buffer[]="", BufferSize=0);
/**
* Clears the list of dynamically stored admins
*/
native admins_flush();
// Keep this always at the bottom of this file
#include <message_stocks>

View File

@ -24,6 +24,27 @@
#define DODMAX_WEAPONS 46 // 5 slots for custom weapons
// DoD Weapon Types
enum
{
DODWT_PRIMARY = 0,
DODWT_SECONDARY,
DODWT_MELEE,
DODWT_GRENADE,
DODWT_OTHER
};
// Ammo Channels
#define AMMO_SMG 1 // thompson, greasegun, sten, mp40
#define AMMO_ALTRIFLE 2 // carbine, k43, mg34
#define AMMO_RIFLE 3 // garand, enfield, scoped enfield, k98, scoped k98
#define AMMO_PISTOL 4 // colt, webley, luger
#define AMMO_SPRING 5 // springfield
#define AMMO_HEAVY 6 // bar, bren, stg44, fg42, scoped fg42
#define AMMO_MG42 7 // mg42
#define AMMO_30CAL 8 // 30cal
#define AMMO_GREN 9 // grenades (should be all 3 types)
#define AMMO_ROCKET 13 // bazooka, piat, panzerschreck
enum {
PS_NOPRONE =0,
PS_PRONE,

View File

@ -23,6 +23,9 @@
/* Function is called after grenade throw */
forward grenade_throw(index,greindex,wId);
/* Function is called after a rocket is shot */
forward rocket_shoot(index,rocketindex,wId);
/* Example: for full stamina use dod_player_stamina(1,STAMINA_SET,100,100) */
/* value is from 0 - 100 */
native dod_set_stamina(index,set=STAMINA_SET,minvalue=0,maxvalue=100);

View File

@ -53,6 +53,44 @@ forward dod_client_changeclass(id, class, oldclass);
/* This Forward is called when a player spawns */
forward dod_client_spawn(id);
/* This will be called whenever a player scopes or unscopes
value = 1 scope up
value = 0 scope down */
forward dod_client_scope(id, value);
/* This will be called whenever a player drops a weapon
weapon is weapon dropped or picked up
value = 1 picked up
value = 0 dropped */
forward dod_client_weaponpickup(id, weapon, value);
/* Called whenever the the player goes to or comes from prone position
value = 1 going down
value = 0 getting up */
forward dod_client_prone(id, value);
/* This will be called whenever a player switches a weapon */
forward dod_client_weaponswitch(id, wpnew, wpnold);
/* Forward for when a grenade explodes and its location */
forward dod_grenade_explosion(id, pos[3], wpnid);
/* Forward for when a rocket explodes and its location */
forward dod_rocket_explosion(id, pos[3], wpnid);
/* Forward for when a player picks up a object */
forward dod_client_objectpickup(id, objid, pos[3], value);
/* Forward for when a users stamina decreases */
forward dod_client_stamina(id, stamina);
/* We want to get just the weapon of whichever type that the player is on him
Use DODWT_* in dodconst.inc for type */
native dod_weapon_type(id, type);
/* This native will change the position of a weapon within the users slots and its ammo ammount */
native dod_set_weaponlist(id, wpnID, slot, dropslot, totalrds);
/* Sets the model for a player */
native dod_set_model(id, const model[]);
@ -102,7 +140,7 @@ native dod_get_map_info( info );
/* Returns id of currently carried weapon. Gets also
* ammount of ammo in clip and backpack. */
native dod_get_user_weapon(index,&clip,&ammo);
native dod_get_user_weapon(index,&clip=0,&ammo=0);
/* Returns team score */
native dod_get_team_score(teamId);

View File

@ -177,3 +177,37 @@ stock bool:operator!(Float:oper)
forward operator%(Float:oper1, Float:oper2);
forward operator%(Float:oper1, oper2);
forward operator%(oper1, Float:oper2);
stock Float:floatmin(Float:ValueA, Float:ValueB)
{
if (ValueA<=ValueB)
{
return ValueA;
}
return ValueB;
}
stock Float:floatmax(Float:ValueA, Float:ValueB)
{
if (ValueA>=ValueB)
{
return ValueA;
}
return ValueB;
}
stock Float:floatclamp(Float:Value, Float:MinValue, Float:MaxValue)
{
if (Value<=MinValue)
{
return MinValue;
}
if (Value>=MaxValue)
{
return MaxValue;
}
return Value;
}

View File

@ -466,3 +466,16 @@
#define HLW_SNARK 15
#define HLW_SUIT 31
#define HLW_ALLWEAPONS (~(1<<HLW_SUIT))
#define FEV_NOTHOST (1<<0) // Skip local host for event send.
#define FEV_RELIABLE (1<<1) // Send the event reliably. You must specify the origin and angles
// for this to work correctly on the server for anything
// that depends on the event origin/angles. I.e., the origin/angles are not
// taken from the invoking edict for reliable events.
#define FEV_GLOBAL (1<<2) // Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC
// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ).
#define FEV_UPDATE (1<<3) // If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate
#define FEV_HOSTONLY (1<<4) // Only send to entity specified as the invoker
#define FEV_SERVER (1<<5) // Only send if the event was created on the server.
#define FEV_CLIENT (1<<6) // Only issue event client side ( from shared code )

View File

@ -23,15 +23,64 @@
#define MSG_ONE_UNRELIABLE 8 // Send to one client, but don't put in reliable stream, put in unreliable datagram (could be dropped)
#define MSG_SPEC 9 // Sends to all spectator proxies
/* Message types for message_begin() */
#define SVC_TEMPENTITY 23
#define SVC_INTERMISSION 30
#define SVC_CDTRACK 32
#define SVC_WEAPONANIM 35
#define SVC_ROOMTYPE 37
#define SVC_ADDANGLE 38 // [vec3] add this angle to the view angle
#define SVC_NEWUSERMSG 39
#define SVC_HLTV 50
/* Hardcoded message types for message_begin()
* Look in the actual HLSDK for details!
*/
#define SVC_NOP 1
#define SVC_DISCONNECT 2
#define SVC_EVENT 3
#define SVC_VERSION 4
#define SVC_SETVIEW 5
#define SVC_SOUND 6
#define SVC_TIME 7
#define SVC_PRINT 8
#define SVC_STUFFTEXT 9
#define SVC_SETANGLE 10
#define SVC_SERVERINFO 11
#define SVC_LIGHTSTYLE 12
#define SVC_UPDATEUSERINFO 13
#define SVC_DELTADESCRIPTION 14
#define SVC_CLIENTDATA 15
#define SVC_STOPSOUND 16
#define SVC_PINGS 17
#define SVC_PARTICLE 18
#define SVC_DAMAGE 19
#define SVC_SPAWNSTATIC 20
#define SVC_EVENT_RELIABLE 21
#define SVC_SPAWNBASELINE 22
#define SVC_TEMPENTITY 23
#define SVC_SETPAUSE 24
#define SVC_SIGNONNUM 25
#define SVC_CENTERPRINT 26
#define SVC_KILLEDMONSTER 27
#define SVC_FOUNDSECRET 28
#define SVC_SPAWNSTATICSOUND 29
#define SVC_INTERMISSION 30
#define SVC_FINALE 31
#define SVC_CDTRACK 32
#define SVC_RESTORE 33
#define SVC_CUTSCENE 34
#define SVC_WEAPONANIM 35
#define SVC_DECALNAME 36
#define SVC_ROOMTYPE 37
#define SVC_ADDANGLE 38
#define SVC_NEWUSERMSG 39
#define SVC_PACKETENTITIES 40
#define SVC_DELTAPACKETENTITIES 41
#define SVC_CHOKE 42
#define SVC_RESOURCELIST 43
#define SVC_NEWMOVEVARS 44
#define SVC_RESOURCEREQUEST 45
#define SVC_CUSTOMIZATION 46
#define SVC_CROSSHAIRANGLE 47
#define SVC_SOUNDFADE 48
#define SVC_FILETXFERFAILED 49
#define SVC_HLTV 50
#define SVC_DIRECTOR 51
#define SVC_VOICEINIT 52
#define SVC_VOICEDATA 53
#define SVC_SENDEXTRAINFO 54
#define SVC_TIMESCALE 55
/* Message flags for set_msg_block() */
#define BLOCK_NOT 0
@ -323,8 +372,6 @@ enum
// write_coord(position.z)
// write_short(model index)
// write_byte(scale / 10)
// write_byte(size)
// write_byte(brightness)
#define TE_BEAMRING 24 // Connect a beam ring to two entities
// write_byte(TE_BEAMRING)
@ -364,6 +411,7 @@ enum
// write_byte(red)
// write_byte(green)
// write_byte(blue)
// write_byte(brightness)
// write_byte(life in 10's)
// write_byte(decay rate in 10's)
@ -649,7 +697,7 @@ enum
#define TE_PLAYERSPRITES 121 // Sprites emit from a player's bounding box (ONLY use for players!)
// write_byte(TE_PLAYERSPRITES)
// write_short(playernum)
// write_byte(playernum)
// write_short(sprite modelindex)
// write_byte(count)
// write_byte(variance) (0 = no variance in size) (10 = 10% variance in size)
@ -719,3 +767,35 @@ enum
// write_byte(life * 10)
// write_byte(color) this is an index into an array of color vectors in the engine. (0 - )
// write_byte(length * 10)
// From hltv.h from the HLSDK, these are used in conjunction with SVC_DIRECTOR
// sub commands of svc_director:
#define DRC_CMD_NONE 0 // NULL director command
#define DRC_CMD_START 1 // start director mode
#define DRC_CMD_EVENT 2 // informs about director command
#define DRC_CMD_MODE 3 // switches camera modes
#define DRC_CMD_CAMERA 4 // sets camera registers
#define DRC_CMD_TIMESCALE 5 // sets time scale
#define DRC_CMD_MESSAGE 6 // send HUD centerprint
#define DRC_CMD_SOUND 7 // plays a particular sound
#define DRC_CMD_STATUS 8 // status info about broadcast
#define DRC_CMD_BANNER 9 // banner file name for HLTV gui
#define DRC_CMD_FADE 10 // send screen fade command
#define DRC_CMD_SHAKE 11 // send screen shake command
#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command
#define DRC_CMD_LAST 12
// HLTV_EVENT event flags
#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important)
#define DRC_FLAG_SIDE (1<<4) //
#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene
#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo
#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc)
#define DRC_FLAG_INTRO (1<<8) // is a introduction scene
#define DRC_FLAG_FINAL (1<<9) // is a final scene
#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data
#define MAX_DIRECTOR_CMD_PARAMETERS 4
#define MAX_DIRECTOR_CMD_STRING 128

View File

@ -133,3 +133,13 @@ native tfc_setweaponammo(index, value);
* Use the TFC_GOALITEM_* constants to determine the owning team.
*/
native tfc_get_user_goalitem(index, &team);
/* Returns 1 if the player is a spy and is currently feigning death */
native tfc_is_user_feigning(index);
/* Returns 1 if the two teams are allies, 0 otherwise
* Note: Team must be 1->4
* Team 0 will always return 0
* Any other team will result in an error
*/
native tfc_is_team_ally(TeamA,TeamB);

View File

@ -67,7 +67,7 @@ native ts_getuserslots( index );
native ts_setuserslots( index, slots );
native ts_getuserstate( index );
native ts_getuserwpn( index,&clip,&ammo,&mode,&extra );
native ts_getuserwpn( index,&clip=0,&ammo=0,&mode=0,&extra=0 );
native ts_getuserspace( index );
native ts_getuserkillflags(killer);

View File

@ -154,10 +154,33 @@ public actionBanMenu(id, key)
switch (get_cvar_num("amx_show_activity"))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_BAN_2", name, name2)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_BAN_1", name2)
case 2:
{
if (g_menuSettings[id]==0) // permanent
{
client_print(0, print_chat, "%L %s: %L %s %L", LANG_PLAYER, "ADMIN", name, LANG_PLAYER, "BAN", name2, LANG_PLAYER, "PERM");
}
else
{
new tempTime[32];
formatex(tempTime,sizeof(tempTime)-1,"%d",g_menuSettings[id]);
client_print(0, print_chat, "%L %s: %L %s %L", LANG_PLAYER, "ADMIN", name, LANG_PLAYER, "BAN", name2, LANG_PLAYER, "FOR_MIN", tempTime);
}
}
case 1:
{
if (g_menuSettings[id]==0) // permanent
{
client_print(0, print_chat, "%L: %L %s %L", LANG_PLAYER, "ADMIN", LANG_PLAYER, "BAN", name2, LANG_PLAYER, "PERM");
}
else
{
new tempTime[32];
formatex(tempTime,sizeof(tempTime)-1,"%d",g_menuSettings[id]);
client_print(0, print_chat, "%L: %L %s %L", LANG_PLAYER, "ADMIN", LANG_PLAYER, "BAN", name2, LANG_PLAYER, "FOR_MIN", tempTime);
}
}
}
/* ---------- check for Steam ID added by MistaGee --------------------
IF AUTHID == 4294967295 OR VALVE_ID_LAN OR HLTV, BAN PER IP TO NOT BAN EVERYONE */
@ -173,7 +196,9 @@ public actionBanMenu(id, key)
server_cmd("addip %d %s;writeip", g_menuSettings[id], ipa)
}
else
{
server_cmd("banid %d #%d kick;writeid", g_menuSettings[id], userid2)
}
server_exec()

View File

@ -0,0 +1,123 @@
#include <amxmodx>
new __testnumber;
new errcount;
enum TestType
{
TT_Equal = 0,
TT_LessThan,
TT_GreaterThan,
TT_LessThanEqual,
TT_GreaterThanEqual,
TT_NotEqual
};
new TestWords[6][] = {
"==",
"<",
">",
"<=",
">=",
"!="
};
stock test(A,B=0,TestType:Type=TT_Equal)
{
++__testnumber;
new passed=0;
switch (Type)
{
case TT_Equal: if (A==B) passed=1;
case TT_LessThan: if (A<B) passed=1;
case TT_GreaterThan: if (A>B) passed=1;
case TT_LessThanEqual: if (A<=B) passed=1;
case TT_GreaterThanEqual: if (A>=B) passed=1;
case TT_NotEqual: if (A!=B) passed=1;
}
if (!passed)
{
log_amx("Failed test #%d (%d %s %d)",__testnumber,A,TestWords[_:Type],B);
errcount++;
}
}
public plugin_init()
{
register_srvcmd("testadmins","testadmins");
}
public testadmins()
{
new AuthData[44];
new Password[32];
new Access;
new Flags;
new id;
__testnumber=0;
errcount=0;
test(admins_num(),0);
admins_push("STEAM_0:1:23456","",read_flags("abcdefghijklmnopqrstu"),read_flags("ce"));
test(admins_num(),1);
admins_push("ABCDEFGHIJKLMNOP","abcdefghijklmnop",read_flags("z"),read_flags("a"));
test(admins_num(),2);
admins_push("ZYXWVUTSRQPONMLKJIHGFEDCBA","plop",read_flags("a"),read_flags("b"));
test(admins_num(),3);
id=0;
admins_lookup(id,AdminProp_Auth,AuthData,sizeof(AuthData)-1);
admins_lookup(id,AdminProp_Password,Password,sizeof(Password)-1);
Access=admins_lookup(id,AdminProp_Access);
Flags=admins_lookup(id,AdminProp_Flags);
test(strcmp(AuthData,"STEAM_0:1:23456"),0);
test(strcmp(Password,""),0);
test(Access,read_flags("abcdefghijklmnopqrstu"));
test(Flags,read_flags("ce"));
id++;
admins_lookup(id,AdminProp_Auth,AuthData,sizeof(AuthData)-1);
admins_lookup(id,AdminProp_Password,Password,sizeof(Password)-1);
Access=admins_lookup(id,AdminProp_Access);
Flags=admins_lookup(id,AdminProp_Flags);
test(strcmp(AuthData,"ABCDEFGHIJKLMNOP"),0);
test(strcmp(Password,"abcdefghijklmnop"),0);
test(Access,read_flags("z"));
test(Flags,read_flags("a"));
id++;
admins_lookup(id,AdminProp_Auth,AuthData,sizeof(AuthData)-1);
admins_lookup(id,AdminProp_Password,Password,sizeof(Password)-1);
Access=admins_lookup(id,AdminProp_Access);
Flags=admins_lookup(id,AdminProp_Flags);
test(strcmp(AuthData,"ZYXWVUTSRQPONMLKJIHGFEDCBA"),0);
test(strcmp(Password,"plop"),0);
test(Access,read_flags("a"));
test(Flags,read_flags("b"));
admins_flush();
test(admins_num(),0);
server_print("test complete, %d errors",errcount);
}

View File

@ -62,6 +62,7 @@ public plugin_init()
register_dictionary("plmenu.txt")
register_dictionary("common.txt")
register_dictionary("admincmd.txt")
register_clcmd("amx_kickmenu","cmdKickMenu",ADMIN_KICK,"- displays kick menu")
register_clcmd("amx_banmenu","cmdBanMenu",ADMIN_BAN,"- displays ban menu")
@ -122,8 +123,32 @@ public actionBanMenu(id, key)
switch (get_cvar_num("amx_show_activity"))
{
case 2: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_BAN_2", name, name2)
case 1: client_print(0, print_chat, "%L", LANG_PLAYER, "ADMIN_BAN_1", name2)
case 2:
{
if (g_menuSettings[id]==0) // permanent
{
client_print(0, print_chat, "%L %s: %L %s %L", LANG_PLAYER, "ADMIN", name, LANG_PLAYER, "BAN", name2, LANG_PLAYER, "PERM");
}
else
{
new tempTime[32];
formatex(tempTime,sizeof(tempTime)-1,"%d",g_menuSettings[id]);
client_print(0, print_chat, "%L %s: %L %s %L", LANG_PLAYER, "ADMIN", name, LANG_PLAYER, "BAN", name2, LANG_PLAYER, "FOR_MIN", tempTime);
}
}
case 1:
{
if (g_menuSettings[id]==0) // permanent
{
client_print(0, print_chat, "%L: %L %s %L", LANG_PLAYER, "ADMIN", LANG_PLAYER, "BAN", name2, LANG_PLAYER, "PERM");
}
else
{
new tempTime[32];
formatex(tempTime,sizeof(tempTime)-1,"%d",g_menuSettings[id]);
client_print(0, print_chat, "%L: %L %s %L", LANG_PLAYER, "ADMIN", LANG_PLAYER, "BAN", name2, LANG_PLAYER, "FOR_MIN", tempTime);
}
}
}
if (equal("4294967295", authid2))