From c604eefde0adfc3a88d8f794994d14ca4db97b1f Mon Sep 17 00:00:00 2001 From: Steve Dudenhoeffer Date: Thu, 2 Aug 2007 16:20:32 +0000 Subject: [PATCH] Merge of rewritten NS module into trunk --- dlls/ns/AllocString.h | 122 +++++++ dlls/ns/CPlayer.cpp | 111 ------ dlls/ns/CPlayer.h | 462 +++++++++++++++++++++++-- dlls/ns/CSpawn.cpp | 46 --- dlls/ns/CSpawn.h | 21 -- dlls/ns/CString.h | 428 +++++++++++++++++++++++ dlls/ns/CVector.h | 491 ++++++++++++++++++++++++++ dlls/ns/GameManager.cpp | 120 +++++++ dlls/ns/GameManager.h | 318 +++++++++++++++++ dlls/ns/Hash.h | 164 +++++++++ dlls/ns/LocationManager.h | 121 +++++++ dlls/ns/Makefile | 56 ++- dlls/ns/MessageHandler.cpp | 204 +++++++++++ dlls/ns/MessageHandler.h | 178 ++++++++++ dlls/ns/NEW_Util.h | 100 ++++++ dlls/ns/NMisc.cpp | 496 --------------------------- dlls/ns/NPData.cpp | 389 --------------------- dlls/ns/ParticleManager.cpp | 121 +++++++ dlls/ns/ParticleManager.h | 152 ++++++++ dlls/ns/SpawnManager.h | 128 +++++++ dlls/ns/TitleManager.cpp | 142 ++++++++ dlls/ns/TitleManager.h | 79 +++++ dlls/ns/amxxapi.cpp | 107 ++++++ dlls/ns/amxxapi.h | 7 - dlls/ns/dllapi.cpp | 234 +++++++++++++ dlls/ns/engineapi.cpp | 317 +++++++++++++++++ dlls/ns/hookedfunctions.cpp | 487 -------------------------- dlls/ns/msvc8/ns.sln | 2 +- dlls/ns/msvc8/ns.vcproj | 165 ++++++--- dlls/ns/natives/general.cpp | 553 ++++++++++++++++++++++++++++++ dlls/ns/natives/memberfuncs.cpp | 275 +++++++++++++++ dlls/ns/natives/particles.cpp | 276 +++++++++++++++ dlls/ns/natives/player.cpp | 222 ++++++++++++ dlls/ns/natives/player_memory.cpp | 355 +++++++++++++++++++ dlls/ns/natives/structure.cpp | 405 ++++++++++++++++++++++ dlls/ns/natives/weapons.cpp | 479 ++++++++++++++++++++++++++ dlls/ns/ns.h | 88 +++-- dlls/ns/ns_const.h | 269 +++++++++++---- dlls/ns/sdk/amxxmodule.cpp | 6 +- dlls/ns/sdk/amxxmodule.h | 18 +- dlls/ns/sdk/moduleconfig.h | 26 +- dlls/ns/sh_list.h | 297 ++++++++++++++++ dlls/ns/utilfunctions.h | 272 ++++++++++++--- dlls/ns/utils.cpp | 192 +++++++++++ 44 files changed, 7697 insertions(+), 1804 deletions(-) create mode 100644 dlls/ns/AllocString.h delete mode 100755 dlls/ns/CPlayer.cpp delete mode 100755 dlls/ns/CSpawn.cpp delete mode 100755 dlls/ns/CSpawn.h create mode 100644 dlls/ns/CString.h create mode 100644 dlls/ns/CVector.h create mode 100644 dlls/ns/GameManager.cpp create mode 100644 dlls/ns/GameManager.h create mode 100644 dlls/ns/Hash.h create mode 100644 dlls/ns/LocationManager.h create mode 100644 dlls/ns/MessageHandler.cpp create mode 100644 dlls/ns/MessageHandler.h create mode 100644 dlls/ns/NEW_Util.h delete mode 100755 dlls/ns/NMisc.cpp delete mode 100755 dlls/ns/NPData.cpp create mode 100644 dlls/ns/ParticleManager.cpp create mode 100644 dlls/ns/ParticleManager.h create mode 100644 dlls/ns/SpawnManager.h create mode 100644 dlls/ns/TitleManager.cpp create mode 100644 dlls/ns/TitleManager.h create mode 100644 dlls/ns/amxxapi.cpp delete mode 100755 dlls/ns/amxxapi.h create mode 100644 dlls/ns/dllapi.cpp create mode 100644 dlls/ns/engineapi.cpp delete mode 100755 dlls/ns/hookedfunctions.cpp create mode 100644 dlls/ns/natives/general.cpp create mode 100644 dlls/ns/natives/memberfuncs.cpp create mode 100644 dlls/ns/natives/particles.cpp create mode 100644 dlls/ns/natives/player.cpp create mode 100644 dlls/ns/natives/player_memory.cpp create mode 100644 dlls/ns/natives/structure.cpp create mode 100644 dlls/ns/natives/weapons.cpp create mode 100644 dlls/ns/sh_list.h create mode 100644 dlls/ns/utils.cpp diff --git a/dlls/ns/AllocString.h b/dlls/ns/AllocString.h new file mode 100644 index 00000000..ca7c6abc --- /dev/null +++ b/dlls/ns/AllocString.h @@ -0,0 +1,122 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* This file is a replacement for the engine call of ALLOC_STRING + * The main difference is that a string will not be allocated twice + * as to try to avoid wasting the HL zone space. + * + * NOTE: The lookup uses strcmp() in a linked list! It is not fast + * Its implementation in the NS module is on rarely used + * natives. + */ + +#ifndef ALLOCSTRING_H +#define ALLOCSTRING_H + +#include "CString.h" +#include "sh_list.h" + +class StringManager +{ +private: + List m_StringList; + +public: + /** + * sh_list.h does not delete objects put into + * the list, so I need to delete those and clear() + */ + inline void Clear(void) + { + List::iterator end; + List::iterator iter; + + iter=m_StringList.begin(); + end=m_StringList.end(); + + while (iter!=end) + { + delete (*iter++); + } + + m_StringList.clear(); + } + + /** + * Iterate the list to see if the string exists + * This is slow and not very ideal, however + * this is *very* rarely used so it won't matter + */ + inline int Allocate(const char *str) + { + List::iterator end; + List::iterator iter; + + iter=m_StringList.begin(); + end=m_StringList.end(); + + while (iter!=end) + { + if (strcmp(str,(*iter)->c_str())) + { + // String is already in the list, do not allocate it again + return MAKE_STRING((*iter)->c_str()); + } + ++iter; + } + + // Was not found in the linked list, allocate it and add it to the list + String *AllocStr = new String; + + AllocStr->assign(str); + + m_StringList.push_back(AllocStr); + + return MAKE_STRING(AllocStr->c_str()); + + }; + +}; + +extern StringManager AllocStringList; + +/** + * Simple wrapper to make conversion easier + */ +inline int ALLOC_STRING2(const char *InputString) +{ + return AllocStringList.Allocate(InputString); +} + + +#endif // ALLOCSTRING_H diff --git a/dlls/ns/CPlayer.cpp b/dlls/ns/CPlayer.cpp deleted file mode 100755 index 2da2fd4b..00000000 --- a/dlls/ns/CPlayer.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "ns.h" - -void CPlayer::PreThink() -{ - if (!connected) - { - // This usually means it's a bot... - // So just emulate connections - Connect(); - bot=true; - } - if (olddeadflag && pev->deadflag == 0 && SpawnForward != -1) - MF_ExecuteForward(SpawnForward,index()); - - if (oldteam != pev->team && TeamForward != -1) - MF_ExecuteForward(TeamForward,index(),pev->team,oldteam); - - int tClass = GetClass(); - if (tClass != iclass) - ChangeClass(tClass); - oldimpulse=pev->impulse; - olddeadflag = pev->deadflag; - oldteam = pev->team; -} -void CPlayer::PreThink_Post() -{ - // Trying to incorperate this into PostThink_Post led to really *weird* results (i don't think it was propagated to the client properly). - // Change the users speed here - maxspeed=(int)pev->maxspeed; - pev->maxspeed+=speedchange; -} - -void CPlayer::PostThink_Post() -{ - // Change the player's models... - if (custommodel) - SET_MODEL(edict,model); - if (customskin) - pev->skin=skin; - if (custombody) - pev->body=body; -} -void CPlayer::ChangeClass(int newclass) -{ - if (ChangeclassForward != -1) - MF_ExecuteForward(ChangeclassForward, index(), newclass, iclass, oldimpulse); - iclass=newclass; -} - -int CPlayer::GetClass() -{ - if (pev->deadflag) - return CLASS_DEAD; - if (!pev->team) - return CLASS_NOTEAM; - switch (pev->iuser3) - { - case 1: - // Light armor marine.. - if (pev->iuser4 & MASK_HEAVYARMOR) - return CLASS_HEAVY; - if (pev->iuser4 & MASK_JETPACK) - return CLASS_JETPACK; - return CLASS_MARINE; - case 2: - return CLASS_COMMANDER; - case 3: - return CLASS_SKULK; - case 4: - return CLASS_GORGE; - case 5: - return CLASS_LERK; - case 6: - return CLASS_FADE; - case 7: - return CLASS_ONOS; - case 8: - return CLASS_GESTATE; - } - return CLASS_UNKNOWN; - -} -void CPlayer::Connect() -{ - connected=true; - bot=false; - - Reset(); -} -void CPlayer::Disconnect() -{ - connected=false; - bot=false; - Reset(); -} -void CPlayer::Reset() -{ - this->custombody=false; - this->custommodel=false; - this->customskin=false; - this->maxspeed=0; - this->speedchange=0; - this->model[0]='\0'; - this->skin=0; - this->body=0; - this->fov=0.0; - this->foved=false; - olddeadflag=0; - oldteam=0; - -} diff --git a/dlls/ns/CPlayer.h b/dlls/ns/CPlayer.h index 7568cb63..921d6c7c 100755 --- a/dlls/ns/CPlayer.h +++ b/dlls/ns/CPlayer.h @@ -1,44 +1,438 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* This is the basic data stored for players */ #ifndef CPLAYER_H #define CPLAYER_H + +#include + +#include "GameManager.h" + class CPlayer { +private: + edict_t *m_pEdict; + entvars_t *m_pev; + + int m_iIndex; + + int m_iIsBot; + int m_iIsConnected; + + int m_iOldTeam; + int m_iOldImpulse; + int m_iOldDeadFlag; + + int m_iSpeedChange; + REAL m_fMaxSpeed; + + int m_iClass; + + int m_iHasCustomModel; + int m_iHasCustomSkin; + int m_iHasCustomBody; + + char m_szModel[128]; + int m_iSkin; + int m_iBody; + + int m_iHasFOV; + REAL m_fFOV; + + int m_iInitialized; + + + + public: - void PreThink(); - void PreThink_Post(); - void PostThink_Post(); - void Spawn(); - void ChangeTeam(); - void ChangeClass(int newclass); - void Connect(); - void Disconnect(); - void Reset(); - void Die(); - int GetClass(); - bool bot; - // Basic engine stuff. - edict_t *edict; - entvars_t *pev; - int oldimpulse; // Store the previous impulse. - int olddeadflag; - int oldteam; - int index() { return ENTINDEX(pev->pContainingEntity); }; - bool connected; - REAL fov; - bool foved; - // Custom model/body/skin - bool custommodel; - bool customskin; - bool custombody; - char model[128]; - int skin; - int body; + CPlayer() + { + memset(this,0x0,sizeof(*this)); + } + + inline void SetEdict(edict_t *Ent) + { + m_pEdict=Ent; + + m_pev=&(Ent->v); + + m_iIndex=ENTINDEX_NEW(Ent); + }; + + inline edict_t *GetEdict(void) + { + return m_pEdict; + }; + inline entvars_t *GetPev(void) + { + return m_pev; + }; + inline int IsBot(void) + { + return m_iIsBot; + }; + inline void SetBot(int onoff) + { + m_iIsBot=onoff; + }; + inline int IsConnected(void) + { + return m_iIsConnected; + }; + + inline BOOL HasPrivateData(void) + { + if (m_pEdict && m_pEdict->pvPrivateData != NULL) + { + return TRUE; + } + + return FALSE; + }; + + inline int IsInitialized() + { + return m_iInitialized; + }; + inline void Initialize() + { + if (!IsConnected()) + { + // This usually means it's a bot... + // So just emulate connections + Connect(); + SetBot(1); + } + + + + m_iInitialized=1; + }; + inline void PreThink() + { + if (!IsInitialized()) + { + Initialize(); + } + if (m_iOldTeam != m_pev->team) + { + GameMan.ExecuteClientChangeTeam(index(),m_pev->team,m_iOldTeam); + } + + + if (m_iOldDeadFlag && m_pev->deadflag == 0) + { + GameMan.ExecuteClientSpawn(index()); + } + + + int tClass = GetClass(); + + if (tClass != m_iClass) + { + ChangeClass(tClass); + } + + m_iOldImpulse=m_pev->impulse; + m_iOldDeadFlag=m_pev->deadflag; + m_iOldTeam=m_pev->team; + }; + + inline void PreThink_Post() + { + // Trying to incorperate this into PostThink_Post led to really *weird* results (i don't think it was propagated to the client properly). + // Change the users speed here + m_fMaxSpeed=m_pev->maxspeed; + m_pev->maxspeed+=m_iSpeedChange; + }; + + /** + * This is only hooked if at least 1 + * player has custom skins/models/bodies + */ + inline void PostThink_Post() + { + if (m_iHasCustomModel) + { + SET_MODEL(m_pEdict,m_szModel); + } + if (m_iHasCustomSkin) + { + m_pev->skin=m_iSkin; + } + if (m_iHasCustomBody) + { + m_pev->body=m_iBody; + } + }; + + void ChangeClass(int newclass) + { + GameMan.ExecuteClientChangeClass(index(), newclass, m_iClass); + + m_iClass=newclass; + } + void Connect() + { + m_iIsConnected=1; + m_iIsBot=0; + + Reset(); + } + void Disconnect(int scanhooks=0) + { + // If this client had any hooks upon disconnect + // then rescan the hooks to see if we can stop + // intercepting any of them. + if (scanhooks!=0) + { + if (this->NeedPreThink_Post()) + { + GameMan.HookPreThink_Post(); + } + if (this->NeedPostThink_Post()) + { + GameMan.HookPostThink_Post(); + } + if (this->NeedUpdateClientData()) + { + GameMan.HookUpdateClientData(); + } + } + m_iIsConnected=0; + m_iIsBot=0; + + Reset(); + } + void FullReset() + { + memset(this,0x0,sizeof(*this)); + }; + void Reset() + { + m_iHasCustomModel=0; + m_iHasCustomSkin=0; + m_iHasCustomBody=0; + + m_iOldTeam=0; + m_iOldDeadFlag=0; + m_iSpeedChange=0; + m_iClass=0; + }; + + int GetClass() + { + if (m_pev->deadflag) + { + return CLASS_DEAD; + } + + if (!m_pev->team) + { + return CLASS_NOTEAM; + } + switch (m_pev->iuser3) + { + case 1: + // Light armor marine.. + if (m_pev->iuser4 & MASK_HEAVYARMOR) + { + return CLASS_HEAVY; + } + if (m_pev->iuser4 & MASK_JETPACK) + { + return CLASS_JETPACK; + } + + return CLASS_MARINE; + + case 2: + return CLASS_COMMANDER; + + case 3: + return CLASS_SKULK; + + case 4: + return CLASS_GORGE; + + case 5: + return CLASS_LERK; + + case 6: + return CLASS_FADE; + + case 7: + return CLASS_ONOS; + + case 8: + return CLASS_GESTATE; + + } + + return CLASS_UNKNOWN; + }; + + inline int &index() + { + return m_iIndex; + }; + + inline int &GetSpeedChange(void) + { + return m_iSpeedChange; + }; + inline int GetMaxSpeed(void) + { + return (int)m_fMaxSpeed; + }; + inline void SetSpeedChange(cell &SpeedChange) + { + m_iSpeedChange=SpeedChange; + }; + + inline void SetModel(char *Model) + { + if (strcmp(Model,"")!=0) + { + PRECACHE_MODEL(Model); + + strncpy(m_szModel,Model,sizeof(m_szModel)-1); + + m_iHasCustomModel=1; + + } + else + { + m_iHasCustomModel=0; + } + }; + + inline void SetSkin(cell &skin) + { + if (skin<0) + { + m_iHasCustomSkin=0; + return; + } + + m_iHasCustomSkin=1; + m_iSkin=skin; + }; + + inline void SetBody(cell &body) + { + if (body<0) + { + m_iHasCustomBody=0; + return; + } + + m_iHasCustomBody=1; + m_iBody=body; + }; + + /** + * Called during pfnUpdateClientData() + * Sets the player's FOV continuously + */ + inline void UpdateFOV(void) + { + if (m_iHasFOV) + { + GetPev()->fov=m_fFOV; + } + }; + + /** + * Called from the native directly. + * Changes members, and gets the SetFOV + * message id if needed. + */ + inline int SetFOV(REAL &Amount) + { + + GameMan.UpdateSetFOV(); + if (Amount == 0.0) + { + m_iHasFOV=0; + m_fFOV=0.0; + + MESSAGE_BEGIN(MSG_ONE,GameMan.GetSetFOV(),NULL,GetEdict()); + WRITE_BYTE(0); + MESSAGE_END(); + return 1; + } + if (Amount > 0) + { + m_iHasFOV=1; + m_fFOV=Amount; + MESSAGE_BEGIN(MSG_ONE,GameMan.GetSetFOV(),NULL,GetEdict()); + WRITE_BYTE((int)Amount); + MESSAGE_END(); + return 1; + } + return 0; + + }; + + /** + * Returns 1 if this entity needs PreThink_Post hooked + * (eg: this entity has custom max speeds) + */ + inline int NeedPreThink_Post(void) + { + return m_iSpeedChange != 0; + }; + + /** + * Returns 1 if this entity needs PostThink_Post + * eg: This entity has a custom model/skin/body + */ + inline int NeedPostThink_Post(void) + { + return (m_iHasCustomModel != 0 || m_iHasCustomSkin != 0 || m_iHasCustomBody != 0); + }; + /** + * Returns 1 if this entity needs UpdateClientData + * eg: This entity has a custom FOV set + */ + inline int NeedUpdateClientData(void) + { + return m_iHasFOV != 0; + }; - // Speed change - int speedchange; - int maxspeed; - - int iclass; }; #endif diff --git a/dlls/ns/CSpawn.cpp b/dlls/ns/CSpawn.cpp deleted file mode 100755 index 2622ac61..00000000 --- a/dlls/ns/CSpawn.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "ns.h" - -void CSpawn::clear() -{ - while (spawnpointinfo) - { - spawnpointInfo* a = spawnpointinfo->next; - delete spawnpointinfo; - spawnpointinfo = a; - } - -} -void CSpawn::put(int type, vec3_t location) -{ - spawnpointinfo = new spawnpointInfo(type, location, spawnpointinfo); -} -float CSpawn::getnum(int type) -{ - float iTemp=0.0; - spawnpointInfo *a = spawnpointinfo; - while (a) - { - if (a->type == type) - iTemp+=1.0; - a = a->next; - } - return iTemp; -} -vec3_t CSpawn::getpoint(int type, int num) -{ - int iTemp=0; - spawnpointInfo *a = spawnpointinfo; - while (a) - { - if (a->type == type) - { - iTemp++; - if (iTemp == num) - { - return a->location; - } - } - a=a->next; - } - return Vector(0.0,0.0,0.0); -} diff --git a/dlls/ns/CSpawn.h b/dlls/ns/CSpawn.h deleted file mode 100755 index 02bb7d92..00000000 --- a/dlls/ns/CSpawn.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CSPAWN_H -#define CSPAWN_H -class CSpawn -{ - struct spawnpointInfo - { - int type; // 0 = Ready room, 1 = Marine, 2 = Alien - vec3_t location; - spawnpointInfo* next; - spawnpointInfo(int type, vec3_t location, spawnpointInfo* next): type(type), location(location), next(next) {} - } *spawnpointinfo; -public: - CSpawn() { spawnpointinfo = 0; } - ~CSpawn() { clear(); } - void clear(); - void put(int type, vec3_t location); - float getnum(int type); - vec3_t getpoint(int type, int num); -}; -#endif - diff --git a/dlls/ns/CString.h b/dlls/ns/CString.h new file mode 100644 index 00000000..efed1b59 --- /dev/null +++ b/dlls/ns/CString.h @@ -0,0 +1,428 @@ +/* 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 +#include +#include + +//by David "BAILOPAN" Anderson +class String +{ +public: + String() + { + v = new char[33]; + v[0]='\0'; + a_size = 0; + //assign(""); + } + + ~String() + { + 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(size()); + if (len < 1) + return npos; + if (index >= len || index < 0) + return npos; + int i = 0; + for (i=index; 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=start && i= 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= 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 diff --git a/dlls/ns/CVector.h b/dlls/ns/CVector.h new file mode 100644 index 00000000..d0fef2be --- /dev/null +++ b/dlls/ns/CVector.h @@ -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 + +// Vector +template 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_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 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() + { + m_Size = 0; + m_CurrentUsedSize = 0; + m_Data = NULL; + } + + CVector(const CVector & 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() + { + 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__ + diff --git a/dlls/ns/GameManager.cpp b/dlls/ns/GameManager.cpp new file mode 100644 index 00000000..eabaf84c --- /dev/null +++ b/dlls/ns/GameManager.cpp @@ -0,0 +1,120 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* This holds the functions which determine which hooks I need forwareded */ + +#include "sdk/amxxmodule.h" + +#include "ns.h" + +#include "utilfunctions.h" + +#include "GameManager.h" +#include "CPlayer.h" + +void GameManager::HookPreThink(void) +{ + // Only need to hook prethink if at least 1 plugins has any of these forwards: + // client_spawn, client_changeteam, client_changeclass + + if (UTIL_CheckForPublic("client_spawn") || + UTIL_CheckForPublic("client_changeteam") || + UTIL_CheckForPublic("client_changeclass")) + { + g_pFunctionTable->pfnPlayerPreThink=PlayerPreThink; + return; + } + + g_pFunctionTable->pfnPlayerPreThink=NULL; +}; + +void GameManager::HookPostThink_Post(void) +{ + int i=0; + while (i++maxClients) + { + if (GET_PLAYER_I(i)->NeedPostThink_Post()) + { + g_pFunctionTable_Post->pfnPlayerPostThink=PlayerPostThink_Post; + return; + } + } + + g_pFunctionTable_Post->pfnPlayerPostThink=NULL; +}; +void GameManager::HookPreThink_Post(void) +{ + int i=1; + while (imaxClients) + { + if (GET_PLAYER_I(i++)->NeedPreThink_Post()) + { + g_pFunctionTable_Post->pfnPlayerPreThink=PlayerPreThink_Post; + return; + } + } + + g_pFunctionTable_Post->pfnPlayerPreThink=NULL; +}; +void GameManager::HookUpdateClientData(void) +{ + int i=1; + while (imaxClients) + { + if (GET_PLAYER_I(i++)->NeedUpdateClientData()) + { + g_pFunctionTable->pfnUpdateClientData=UpdateClientData; + return; + } + } + + g_pFunctionTable->pfnUpdateClientData=NULL; +}; +void GameManager::HookLogs() +{ + // These forwards only are needed in classic NS + if (!IsCombat() && UTIL_CheckForPublic("client_built")) + { + // Only hook if this public exists (wasteful otherwise) + m_BuiltForward = MF_RegisterForward("client_built", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE); + g_pengfuncsTable_Post->pfnAlertMessage=AlertMessage_Post; + g_pengfuncsTable_Post->pfnCreateNamedEntity=CreateNamedEntity_Post; + } + else + { + // no need for these hooks in co + g_pengfuncsTable_Post->pfnAlertMessage=NULL; + g_pengfuncsTable_Post->pfnCreateNamedEntity=NULL; + } + +}; diff --git a/dlls/ns/GameManager.h b/dlls/ns/GameManager.h new file mode 100644 index 00000000..924b2fd8 --- /dev/null +++ b/dlls/ns/GameManager.h @@ -0,0 +1,318 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* This file includes game-related stuff, such as message IDs + * and forwards + */ +#ifndef GAMEMANAGER_H +#define GAMEMANAGER_H + +#include "CString.h" + +class GameManager +{ +private: + // Basic game variables + int m_IsCombat; + + int m_HudText2; // Message IDS + int m_SetFOV; + + // Forwards + int m_ChangeclassForward; + int m_BuiltForward; + int m_SpawnForward; + int m_TeamForward; + int m_RoundStartForward; + int m_RoundEndForward; + int m_MapResetForward; + + REAL m_fRoundStartTime; // Time the match should start + int m_RoundInProgress; // Whether or not there is a match in progress + + edict_t *m_SavedEdict; // saved edict for client_built + + int m_iTitlesMap; + + bool m_SendMapReset; + +public: + GameManager() + { + m_SendMapReset = true; + m_IsCombat=0; + m_HudText2=0; + m_SetFOV=0; + + m_SavedEdict=NULL; + + m_RoundInProgress=0; + + ResetForwards(); + }; + inline void CheckMap(void) + { + String MapName; + + MapName.assign(STRING(gpGlobals->mapname)); + + MapName.ToLower(); + + m_iTitlesMap=0; + + if (strcmp(MapName.c_str(),"ns_bast")==0 || + strcmp(MapName.c_str(),"ns_bast_classic")==0 || + strcmp(MapName.c_str(),"ns_hera")==0 || + strcmp(MapName.c_str(),"ns_nothing")==0 || + strcmp(MapName.c_str(),"ns_caged")==0 || + strcmp(MapName.c_str(),"ns_tanith")==0 || + strcmp(MapName.c_str(),"ns_eclipse")==0 || + strcmp(MapName.c_str(),"ns_veil")==0 || + strcmp(MapName.c_str(),"ns_nancy")==0) + { + m_iTitlesMap=1; + } + + + }; + inline int &TitleMap(void) + { + return m_iTitlesMap; + }; + inline void SetCombat(int value) + { + m_IsCombat=value; + }; + inline int &IsCombat(void) + { + return m_IsCombat; + }; + + inline void UpdateHudText2(void) + { + if (!m_HudText2) + { + GetMessageIDs(); + } + }; + inline void UpdateSetFOV(void) + { + if (!m_SetFOV) + { + GetMessageIDs(); + } + }; + inline int &GetHudText2(void) + { + return m_HudText2; + }; + inline int &GetSetFOV(void) + { + return m_SetFOV; + }; + inline void GetMessageIDs(void) + { + m_HudText2=GET_USER_MSG_ID(&Plugin_info,"HudText2",NULL); + m_SetFOV=GET_USER_MSG_ID(&Plugin_info,"SetFOV",NULL); + }; + + inline void EvaluateCombat(void) + { + const char *Map=STRING(gpGlobals->mapname); + + // if map starts with co_ it is combat + // otherwise it is classic gameplay + if ((Map[0]=='c' || Map[0]=='C') && + (Map[1]=='o' || Map[1]=='O') && + (Map[2]=='_')) + { + SetCombat(1); + return; + } + + SetCombat(0); + }; + + inline void ResetForwards(void) + { + m_ChangeclassForward=-1; + m_BuiltForward=-1; + m_SpawnForward=-1; + m_TeamForward=-1; + m_RoundStartForward=-1; + m_RoundEndForward=-1; + m_MapResetForward=-1; + }; + inline void RegisterForwards(void) + { + ResetForwards(); + + + m_SpawnForward = MF_RegisterForward("client_spawn",ET_IGNORE,FP_CELL/*id*/,FP_DONE); + m_TeamForward = MF_RegisterForward("client_changeteam",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*new team*/,FP_CELL/*old team*/,FP_DONE); + m_ChangeclassForward = MF_RegisterForward("client_changeclass", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE); + m_RoundStartForward = MF_RegisterForward("round_start", ET_IGNORE, FP_DONE); + m_RoundEndForward = MF_RegisterForward("round_end", ET_IGNORE, FP_FLOAT, FP_DONE); + m_MapResetForward = MF_RegisterForward("map_reset", ET_IGNORE, FP_CELL, FP_DONE); + + + }; + + inline void StartFrame(void) + { + if (gpGlobals->time >= m_fRoundStartTime) + { + g_pFunctionTable->pfnStartFrame=NULL; + RoundStart(); + } + }; + + /** + * This is called from MessageHandler's Countdown + * hook. It passes the only byte sent (time) + */ + inline void HandleCountdown(int &Time) + { + // Begin hooking start frame + g_pFunctionTable->pfnStartFrame=::StartFrame; + + // set time of round start + m_fRoundStartTime=gpGlobals->time + Time; + + m_SendMapReset = true; + }; + + /** + * This is called from MessageHandler's GameStatus + * hook. It passes the first byte sent. + * 2 = Round End + */ + inline void HandleGameStatus(int &FirstByte) + { + switch (FirstByte) + { + case 0: + if (m_SendMapReset) + { + MF_ExecuteForward(m_MapResetForward, 0); + } + m_SendMapReset = false; + break; + + case 1: + MF_ExecuteForward(m_MapResetForward, 1); + break; + + case 2: + RoundEnd(); + break; + } + }; + + inline void RoundStart() + { + m_RoundInProgress=1; + MF_ExecuteForward(m_RoundStartForward); + }; + inline void RoundEnd() + { + m_RoundInProgress=0; + + MF_ExecuteForward(m_RoundEndForward,gpGlobals->time - m_fRoundStartTime); + }; + inline int &RoundInProgress() + { + return m_RoundInProgress; + }; + // no need to check -1 forwards in these + // amxmodx checks it anyway + inline void ExecuteClientBuilt(int &PlayerID, int StructureID, int &StructureType, int &Impulse) + { + MF_ExecuteForward(m_BuiltForward,PlayerID, StructureID, StructureType, Impulse); + }; + inline void ExecuteClientSpawn(int &PlayerID) + { + MF_ExecuteForward(m_SpawnForward,PlayerID); + }; + inline void ExecuteClientChangeTeam(int &PlayerID, int &NewTeam, int &OldTeam) + { + MF_ExecuteForward(m_TeamForward,PlayerID,OldTeam,NewTeam); + }; + inline void ExecuteClientChangeClass(int &PlayerID, int &NewClass, int &OldClass) + { + MF_ExecuteForward(m_ChangeclassForward,PlayerID,NewClass,OldClass); + }; + inline void ExecuteRoundStart(void) + { + MF_ExecuteForward(m_RoundStartForward); + }; + inline void ExecuteRoundEnd(void) + { + MF_ExecuteForward(m_RoundEndForward); + }; + + + /** + * The next few functions tell the module what metamod hooks + * i need. This tries to run-time optimize out what we + * do not need. + */ + void HookPreThink(void); + void HookPostThink_Post(void); + void HookPreThink_Post(void); + void HookUpdateClientData(void); + void HookLogs(void); // AlertMessage AND CreateNamedEntity + + inline void CheckAllHooks(void) + { + HookPreThink(); + HookPostThink_Post(); + HookPreThink_Post(); + HookUpdateClientData(); + HookLogs(); + }; + + inline void SetTemporaryEdict(edict_t *Edict) + { + m_SavedEdict=Edict; + }; + inline edict_t *GetTemporaryEdict(void) + { + return m_SavedEdict; + }; + +}; + +extern GameManager GameMan; + +#endif // GAMEMANAGER_H diff --git a/dlls/ns/Hash.h b/dlls/ns/Hash.h new file mode 100644 index 00000000..5e099e22 --- /dev/null +++ b/dlls/ns/Hash.h @@ -0,0 +1,164 @@ +#ifndef _HASH_H_ +#define _HASH_H_ + +#include "CVector.h" + + +// Just a very simple hash map, no iteration or anything of the like (not needed) + + +inline int HashFunction(const String& name) +{ + static const int kHashNumTable[128] = + { + 0x1148FC3E, 0x0577C975, 0x3BED3AED, 0x62FBBD5F, 0x07DE2DA0, 0x6555C5E5, 0x24DB841A, 0x2AF3F568, + 0x01EA1B65, 0x46F7D976, 0x18172B99, 0x394B2A58, 0x1ED39AA8, 0x1214E706, 0x5DD47295, 0x53574932, + 0x2CE25D5C, 0x7A2E5BB4, 0x0F2F0153, 0x33888669, 0x729AC55F, 0x2A7BCA9E, 0x36C60816, 0x40F9A7E3, + 0x2A37DF30, 0x3D81BB17, 0x6450B311, 0x75FA2DC9, 0x2A2678A5, 0x4C5E3675, 0x743F4486, 0x3B6F74E3, + 0x51D5FFEA, 0x302C7F74, 0x1E6B3243, 0x59B42D8A, 0x15824559, 0x4346B65D, 0x04A822F2, 0x176C60BF, + 0x0A3E8FD3, 0x1CBF4E8B, 0x50B78B17, 0x29122A7B, 0x2ED43591, 0x2E8BFDAC, 0x7C6973AE, 0x5BB692EE, + 0x28BA5960, 0x0B987501, 0x0F3F1957, 0x1B551EBF, 0x36143F9F, 0x4605216D, 0x5C4EC6A2, 0x604C1ECF, + 0x0386DC84, 0x409F79B4, 0x56464C99, 0x2DAD5529, 0x0CFDB029, 0x4A85911F, 0x691CCA0D, 0x5ED3B013, + 0x7AB21093, 0x0787FC50, 0x3887DD9D, 0x103455ED, 0x4ACEB2AD, 0x3D30008F, 0x27A0B6AC, 0x550D4280, + 0x59EF4F1B, 0x785841C3, 0x7E1F6CFC, 0x08C384AC, 0x26E43F70, 0x7A88E0AA, 0x647A179A, 0x4F9E98D0, + 0x062155AB, 0x73B930F1, 0x6AF3B790, 0x3C35954B, 0x39BE525E, 0x47427E32, 0x1C81B41A, 0x3D452EE2, + 0x07E1F7E6, 0x72C800B3, 0x6AF2840C, 0x14DFA80F, 0x3D4D91D3, 0x540F4E19, 0x73B35822, 0x37FFA266, + 0x5B974A69, 0x2C3B35BF, 0x4833F853, 0x2665FD16, 0x696B364F, 0x6FD4AEFF, 0x7B733F96, 0x435A856A, + 0x682CF0C3, 0x7992AC92, 0x4C1E0A16, 0x0F113033, 0x741B8D3C, 0x309821B1, 0x5EAFC903, 0x7A3CE2E8, + 0x245152A2, 0x49A38093, 0x36727833, 0x5E0FA501, 0x10E5FEC6, 0x52F42C4D, 0x1B54D3E3, 0x18C7F6AC, + 0x45BC2D01, 0x064757EF, 0x2DA79EBC, 0x0309BED4, 0x5A56A608, 0x215AF6DE, 0x3B09613A, 0x35EDF071 + }; + size_t size = name.size(); + + if (size == 0) + { + return 0; + } + + int hasha = kHashNumTable[(*(name.c_str() + (size - 1))) & 0x7F]; + int hashb = kHashNumTable[size % 128]; + + + unsigned char c = 0; + for (size_t i = 0; i < size; i++) + { + c = (*(name.c_str() + (size - 1))) & 0x7F; + + hasha = (hasha + hashb) ^ kHashNumTable[c]; + hashb = hasha + hashb + c + (hasha << 8) + (hashb & 0xFF); + } + + + return hasha; +} + +/** + * @param K Key type. + * @param D Data type. + * @param F Hash function. + * @param B Bucket count. + */ + + + +template +class Hash +{ +protected: + CVector m_HashBuckets[B]; + CVector m_KeyBuckets[B]; + CVector m_DataBuckets[B]; + + inline int GetBucket(int hash) + { + return (*reinterpret_cast(&hash)) % B; + }; + + +public: + + // prints bucket distribution + inline void printbuckets() const + { + for (int i = 0; i < B; i++) + { + if (i % 32 == 0 && i != 0) + { + printf("\n"); + } + printf("%d ", m_HashBuckets[i].size()); + } + printf("\n"); + } + inline void insert(const K& key, const D& value) + { + D* ptr; + if ((ptr = this->find(key)) != NULL) + { + *ptr = value; + return; + } + + int hash = F(key); + + int bucketnum = GetBucket(hash); + + m_HashBuckets[bucketnum].push_back(hash); + m_KeyBuckets[bucketnum].push_back(key); + m_DataBuckets[bucketnum].push_back(value); + + return; + + } + inline D& lookup_or_add(const K& key) + { + D* ptr; + if ((ptr = this->find(key)) != NULL) + { + return *ptr; + } + + int hash = F(key); + + int bucketnum = GetBucket(hash); + + m_HashBuckets[bucketnum].push_back(hash); + m_KeyBuckets[bucketnum].push_back(key); + m_DataBuckets[bucketnum].push_back(D()); + + return m_DataBuckets[bucketnum].at(m_DataBuckets[bucketnum].size() - 1); + + } + inline bool exists(const K& key) + { + return this->find(key) != NULL; + } + inline D* find(const K& key) + { + int hash = F(key); + + int bucketnum = GetBucket(hash); + + // TODO: Possibly make this binary search? + // insertion would be annoying, don't think it is worth it + CVector* hashbucket = &m_HashBuckets[bucketnum]; + CVector* keybucket = &m_KeyBuckets[bucketnum]; + + size_t bucketsize = hashbucket->size(); + + for (size_t i = 0; i < bucketsize; i++) + { + if (hashbucket->at(i) == hash) + { + if (key.compare(keybucket->at(i).c_str()) == 0) + { + return &(m_DataBuckets[bucketnum].at(i)); + } + } + } + + return NULL; + }; +}; + +#endif diff --git a/dlls/ns/LocationManager.h b/dlls/ns/LocationManager.h new file mode 100644 index 00000000..f1ec240e --- /dev/null +++ b/dlls/ns/LocationManager.h @@ -0,0 +1,121 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +#ifndef LOCATIONMANAGER_H +#define LOCATIONMANAGER_H + +#include "CVector.h" +#include "GameManager.h" +#include "TitleManager.h" + + +typedef struct location_data_s +{ + char name[128]; + vec3_t mins; + vec3_t maxs; + + const char *titlelookup; +} location_data_t; + + +class LocationManager +{ +private: + CVector m_LocationList; + +public: + LocationManager() + { + Clear(); + }; + + inline void Clear(void) + { + m_LocationList.clear(); + m_LocationList.reserve(32); + }; + + inline void Add(const char *Name, edict_t *Entity) + { + location_data_t Temp; + + Temp.mins=Entity->v.mins; + Temp.maxs=Entity->v.maxs; + + strncpy(Temp.name,Name,sizeof(Temp.name)-1); + + String NameString(Name); + + NameString.toLower(); + + Temp.titlelookup=TitleMan.Lookup(NameString); + + m_LocationList.push_back(Temp); + }; + inline const char *Lookup(vec3_t origin, cell titlelookup) + { + unsigned int i=0; + location_data_t Temp; + while (i= Temp.mins.x && + origin.y >= Temp.mins.y) + { + if (titlelookup==0) + { + return &(m_LocationList[i-1].name[0]); + } + else + { + if (m_LocationList[i-1].titlelookup!=NULL) + { + return m_LocationList[i-1].titlelookup; + } + + return &(m_LocationList[i-1].name[0]); + } + } + } + return ""; + }; + +}; + +extern LocationManager LocationMan; + +#endif // LOCATIONMANAGER_H diff --git a/dlls/ns/Makefile b/dlls/ns/Makefile index 3269f04f..4d800183 100755 --- a/dlls/ns/Makefile +++ b/dlls/ns/Makefile @@ -1,40 +1,60 @@ #(C)2004-2005 AMX Mod X Development Team # Makefile written by David "BAILOPAN" Anderson -HLSDK = ../../../hlsdk -MM_ROOT = ../../metamod/metamod +HLSDK = ../../../../hlsdk +MM_ROOT = ../../../metamod/metamod ### EDIT BELOW FOR OTHER PROJECTS ### -OPT_FLAGS = -O3 -funroll-loops -s -pipe -fomit-frame-pointer -fno-strict-aliasing + +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 NAME = ns BIN_SUFFIX = amxx_i386.so -OBJECTS = sdk/amxxmodule.cpp CPlayer.cpp CSpawn.cpp NMisc.cpp NPData.cpp hookedfunctions.cpp +OBJECTS = sdk/amxxmodule.cpp dllapi.cpp utils.cpp amxxapi.cpp engineapi.cpp \ +TitleManager.cpp ParticleManager.cpp MessageHandler.cpp GameManager.cpp \ +natives/general.cpp natives/player.cpp natives/player_memory.cpp \ +natives/structure.cpp natives/weapons.cpp natives/particles.cpp \ +natives/memberfuncs.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 -Isdk + -I$(MM_ROOT) -I$(HLSDK)/common -I$(HLSDK)/pm_shared GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) -ifeq "$(GCC_VERSION)" "4" - OPT_FLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -endif - ifeq "$(DEBUG)" "true" BIN_DIR = Debug CFLAGS = $(DEBUG_FLAGS) else - BIN_DIR = Release + 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 += -DNDEBUG -fPIC -Wall -Wno-non-virtual-dtor -Werror -fno-exceptions -DHAVE_STDINT_H -static-libgcc -fno-rtti +CFLAGS += -fPIC -Wall -Wno-non-virtual-dtor -Werror -fno-exceptions -DHAVE_STDINT_H -static-libgcc -fno-rtti BINARY = $(NAME)_$(BIN_SUFFIX) CFLAGS += -DPAWN_CELL_SIZE=32 -DJIT -DASM32 @@ -48,6 +68,7 @@ $(BIN_DIR)/%.o: %.cpp all: mkdir -p $(BIN_DIR) mkdir -p $(BIN_DIR)/sdk + mkdir -p $(BIN_DIR)/natives $(MAKE) ns ns: $(OBJ_LINUX) @@ -58,11 +79,20 @@ debug: default: all +crazy: + $(MAKE) all CRAZY=true + clean: - rm -rf Release/sdk/*.o rm -rf Release/*.o + rm -rf Release/sdk/*.o + rm -rf Release/natives/*.o rm -rf Release/$(NAME)_$(BIN_SUFFIX) - rm -rf Debug/sdk/*.o rm -rf Debug/*.o + rm -rf Debug/sdk/*.o + rm -rf Debug/natives/*.o rm -rf Debug/$(NAME)_$(BIN_SUFFIX) + rm -rf Optimized/*.o + rm -rf Optimized/sdk/*.o + rm -rf Optimized/natives/*.o + rm -rf Optimized/$(NAME)_$(BIN_SUFFIX) diff --git a/dlls/ns/MessageHandler.cpp b/dlls/ns/MessageHandler.cpp new file mode 100644 index 00000000..17f05dac --- /dev/null +++ b/dlls/ns/MessageHandler.cpp @@ -0,0 +1,204 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* This file contains the initialization routine and message hooks + * for the message handler. Note that all of the message hooks + * except for MessageBegin_Post are NOT hooked unless the gameDLL + * is sending a message we care about. + */ + +#include "sdk/amxxmodule.h" + +#include "ns.h" +#include "utilfunctions.h" + +#include "GameManager.h" +#include "MessageHandler.h" + +MessageHandler *MessageLists[256]; + +MessageHandler *HookedMessage; + +bool MessageHandler_Initialized=false; + +// This is called through ServerActivate_Post +void Initialize_MessageHandler(void) +{ + if (MessageHandler_Initialized) + { + return; + } + + MessageHandler_Initialized=true; + + int i=0; + + while (i<255) + { + MessageLists[i++]=NULL; + }; + + // Hook our messages + int index; + + index=GET_USER_MSG_ID(&Plugin_info,"Countdown",NULL); + + if (index) + { + MessageLists[index]=new MessageCountDown; + } + + index=GET_USER_MSG_ID(&Plugin_info,"GameStatus",NULL); + + if (index) + { + MessageLists[index]=new MessageGameStatus; + } + +#if 0 + index=GET_USER_MSG_ID(&Plugin_info,"Particles",NULL); + + if (index) + { + MessageLists[index]=new MessageDebug; + } +#endif + // Start hooking messagebegin_post + g_pengfuncsTable_Post->pfnMessageBegin=MessageBegin_Post; + +}; + +void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +{ + // Sanity check, should never matter + if (msg_type < 0 || msg_type > 255) + { + RETURN_META(MRES_IGNORED); + } + + // Has a hooked message? + if (MessageLists[msg_type]!=NULL) + { + // Should this message be hooked? + if (MessageLists[msg_type]->Begin(msg_dest,msg_type,pOrigin,ed)==1) + { + // This message is going to all be hooked + + // save pointer to our class + HookedMessage=MessageLists[msg_type]; + + // Tell metamod to forward + g_pengfuncsTable_Post->pfnWriteByte=WriteByte_Post; + g_pengfuncsTable_Post->pfnWriteChar=WriteChar_Post; + g_pengfuncsTable_Post->pfnWriteShort=WriteShort_Post; + g_pengfuncsTable_Post->pfnWriteLong=WriteLong_Post; + g_pengfuncsTable_Post->pfnWriteAngle=WriteAngle_Post; + g_pengfuncsTable_Post->pfnWriteCoord=WriteCoord_Post; + g_pengfuncsTable_Post->pfnWriteString=WriteString_Post; + g_pengfuncsTable_Post->pfnWriteEntity=WriteEntity_Post; + g_pengfuncsTable_Post->pfnMessageEnd=MessageEnd_Post; + + + } + } + RETURN_META(MRES_IGNORED); +} + +void MessageEnd_Post(void) +{ + HookedMessage->End(); + + HookedMessage=NULL; + + // Stop metamod forwarding + g_pengfuncsTable_Post->pfnWriteByte=NULL; + g_pengfuncsTable_Post->pfnWriteChar=NULL; + g_pengfuncsTable_Post->pfnWriteShort=NULL; + g_pengfuncsTable_Post->pfnWriteLong=NULL; + g_pengfuncsTable_Post->pfnWriteAngle=NULL; + g_pengfuncsTable_Post->pfnWriteCoord=NULL; + g_pengfuncsTable_Post->pfnWriteString=NULL; + g_pengfuncsTable_Post->pfnWriteEntity=NULL; + g_pengfuncsTable_Post->pfnMessageEnd=NULL; + + RETURN_META(MRES_IGNORED); +}; + +void WriteByte_Post(int iValue) +{ + HookedMessage->WriteByte(iValue); + RETURN_META(MRES_IGNORED); +}; + +void WriteChar_Post(int iValue) +{ + HookedMessage->WriteChar(iValue); + RETURN_META(MRES_IGNORED); +}; + +void WriteShort_Post(int iValue) +{ + HookedMessage->WriteShort(iValue); + RETURN_META(MRES_IGNORED); +}; + +void WriteLong_Post(int iValue) +{ + HookedMessage->WriteLong(iValue); + RETURN_META(MRES_IGNORED); +}; + +void WriteAngle_Post(float flValue) +{ + HookedMessage->WriteAngle(flValue); + RETURN_META(MRES_IGNORED); +}; + +void WriteCoord_Post(float flValue) +{ + HookedMessage->WriteCoord(flValue); + RETURN_META(MRES_IGNORED); +}; + +void WriteString_Post(const char *sz) +{ + HookedMessage->WriteString(sz); + RETURN_META(MRES_IGNORED); +}; + +void WriteEntity_Post(int iValue) +{ + HookedMessage->WriteEntity(iValue); + RETURN_META(MRES_IGNORED); +}; + diff --git a/dlls/ns/MessageHandler.h b/dlls/ns/MessageHandler.h new file mode 100644 index 00000000..3af6aab8 --- /dev/null +++ b/dlls/ns/MessageHandler.h @@ -0,0 +1,178 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* Class with virtual members for easy message handling + * Don't forget to add new messages to "Initialize_MessageHandler()" + */ +#ifndef MESSAGEHANDLER_H +#define MESSAGEHANDLER_H + +#include "utilfunctions.h" + +class MessageHandler +{ +public: + unsigned int m_Count; + int m_Target; + float m_Origin[3]; + edict_t *m_Entity; + int m_Msg; + + + /** + * Return 1 to hook the rest of this message, 0 otherwise + */ + virtual int Begin(int Target, int Msg, const float *Origin, edict_t *Entity) + { + return 0; + }; + + virtual void End(void) + { + return; + }; + + virtual void WriteByte(int Data) + { + ++m_Count; + }; + + virtual void WriteChar(int Data) + { + ++m_Count; + }; + + virtual void WriteShort(int Data) + { + ++m_Count; + }; + + virtual void WriteLong(int Data) + { + ++m_Count; + }; + + virtual void WriteAngle(REAL Data) + { + ++m_Count; + }; + + virtual void WriteCoord(REAL Data) + { + ++m_Count; + }; + + virtual void WriteString(const char *Data) + { + ++m_Count; + }; + + virtual void WriteEntity(int Data) + { + ++m_Count; + }; + +}; + + +class MessageCountDown : public MessageHandler +{ +public: + int m_CountDownTime; + + virtual int Begin(int Target, int Msg, const float *Origin, edict_t *Entity) + { + m_Count=0; + return 1; + }; + + virtual void End(void) + { + if (m_Count!=1) // invalid message? + { + MF_Log("[NS] Invalid Countdown message received! Got %d args, expected 1.",m_Count); + return; + } + + GameMan.HandleCountdown(m_CountDownTime); + }; + + virtual void WriteByte(int Data) + { + ++m_Count; + m_CountDownTime=Data; + }; +}; + +class MessageGameStatus : public MessageHandler +{ +public: + int FirstByte; + + virtual int Begin(int Target, int Msg, const float *Origin, edict_t *Entity) + { + m_Count=0; + return 1; + }; + + virtual void End(void) + { + GameMan.HandleGameStatus(FirstByte); + }; + + virtual void WriteByte(int iValue) + { + if (m_Count==0) + { + FirstByte=iValue; + }; + ++m_Count; + }; +}; + + +void Initialize_MessageHandler(void); + +void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); +void MessageEnd_Post(void); +void WriteByte_Post(int iValue); +void WriteChar_Post(int iValue); +void WriteShort_Post(int iValue); +void WriteLong_Post(int iValue); +void WriteAngle_Post(float flValue); +void WriteCoord_Post(float flValue); +void WriteString_Post(const char *sz); +void WriteEntity_Post(int iValue); + + +#endif // MESSAGEHANDLER_H diff --git a/dlls/ns/NEW_Util.h b/dlls/ns/NEW_Util.h new file mode 100644 index 00000000..6a826f93 --- /dev/null +++ b/dlls/ns/NEW_Util.h @@ -0,0 +1,100 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* 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) +{ + // call the HL Engine ENTINDEX to make sure this is index 0 + + int index=ENTINDEX(Entity); + + if (index==0) + { + NEW_FirstEdict=Entity; + NEW_Initialized=true; + return; + } + + // This is not worldspawn? + // compensate + NEW_FirstEdict=Entity - index; + 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 + + +// straight from amxmodx's string.cpp; no need for this to be an api call +inline cell *MF_GetAmxAddr_NEW(AMX *amx, cell amx_addr) +{ + return (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); +}; + + +#endif // NEW_UTIL_H diff --git a/dlls/ns/NMisc.cpp b/dlls/ns/NMisc.cpp deleted file mode 100755 index d3560cd1..00000000 --- a/dlls/ns/NMisc.cpp +++ /dev/null @@ -1,496 +0,0 @@ -#include "ns.h" - -// These are natives directly from NS2AMX - -static cell AMX_NATIVE_CALL ns_has_weapon(AMX *amx,cell *params) -{ - CHECK_ENTITY(params[1]); - edict_t *pEntity = NULL; - pEntity = INDEXENT2(params[1]); - if (params[3] == -1) - { - if ((pEntity->v.weapons & (1< 0) - { - return 1; - } - } - else - { - if ((pEntity->v.weapons & (1< 0) - { - if (params[3] == 0) - { - pEntity->v.weapons &= ~(1<v.weapons |= (1< 0) - { - if (FStrEq("team_advarmory",buildtype) || FStrEq("team_advturretfactory",buildtype)) - { - iCount++; - } - else - { - if (pBuild->v.fuser1 >= 1000 || pBuild->v.iuser4 & MASK_ELECTRICITY) - { - iCount++; - } - } - } - else - { - iCount++; - } - if (iNumber > 0 && iCount == iNumber) - return ENTINDEX(pBuild); - } - return iCount++; -} - -static cell AMX_NATIVE_CALL ns_get_speedchange(AMX *amx, cell *params) -{ - // Params: get_speedchange(index) - int index=params[1]; - if (!(index>0 && index<=gpGlobals->maxClients)) - return 0; - CPlayer *player = GET_PLAYER_I(params[1]); - return player->speedchange; -} -static cell AMX_NATIVE_CALL ns_set_speedchange(AMX *amx, cell *params) -{ - // Params: set_speedchange(index,speedchange=0) - if (!(params[1]>0&¶ms[1]<=32)) - return 0; - CPlayer *player = GET_PLAYER_I(params[1]); - player->speedchange=params[2]; - return 1; -} -static cell AMX_NATIVE_CALL ns_get_maxspeed(AMX *amx, cell *params) -{ - // Params: get_maxspeed(index) (returns the max speed of the player BEFORE speed change is factored in.) - if (!(params[1]>0 && params[1]<=32)) - return 0; - CPlayer *player = GET_PLAYER_I(params[1]); - return player->maxspeed; -} -static cell AMX_NATIVE_CALL ns_set_player_model(AMX *amx, cell *params) -{ - // Params: set_player_model(id,szModel[]) - if (!(params[1] > 0 && params[1] <= gpGlobals->maxClients)) - { - MF_LogError(amx, AMX_ERR_NATIVE, "Can't set player model for a non-player entity"); - return 0; - } - int len; - char *temp = MF_GetAmxString(amx,params[2],0,&len); - CPlayer *player = GET_PLAYER_I(params[1]); - if (!FStrEq(temp,"")) - { - PRECACHE_MODEL(temp); - snprintf(player->model,127,"%s",temp); - player->custommodel=true; - - } - else - player->custommodel=false; - return 1; -} -static cell AMX_NATIVE_CALL ns_set_player_skin(AMX *amx, cell *params) -{ - // Params: set_player_skin(id,skin=-1) - if (!(params[1] > 0 && params[1] <= gpGlobals->maxClients)) - { - MF_LogError(amx, AMX_ERR_NATIVE, "Can't set player skin for a non-player entity"); - return 0; - } - CPlayer *player = GET_PLAYER_I(params[1]); - if (params[2] < 0) - { - // Reset skin. - player->skin=0; - player->customskin=false; - } - else - { - player->customskin=true; - player->skin=params[2]; - } - return 1; -} -static cell AMX_NATIVE_CALL ns_set_player_body(AMX *amx, cell *params) -{ - // Params: set_player_body(id,body=-1) - if (!(params[1] > 0 && params[1] <= gpGlobals->maxClients)) - { - MF_LogError(amx, AMX_ERR_NATIVE, "Can't set player body for a non-player entity"); - return 0; - } - CPlayer *player = GET_PLAYER_I(params[1]); - if (params[2] < 0) - { - // Reset body. - player->body=0; - player->custombody=false; - } - else - { - player->custombody=true; - player->body=params[2]; - } - return 1; -} - -static cell AMX_NATIVE_CALL ns_get_class(AMX *amx, cell *params) -{ - if (params[1] < 1 || params[1] > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(params[1]); - - return player->GetClass(); -} -static cell AMX_NATIVE_CALL ns_get_jpfuel(AMX *amx, cell *params) -{ - if (params[1] < 1 || params[1] > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(params[1]); - return FLOAT_TO_CELL(player->pev->fuser3 / 10.0); -} -static cell AMX_NATIVE_CALL ns_set_jpfuel(AMX *amx, cell *params) -{ - if (params[1] < 1 || params[1] > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(params[1]); - REAL fuel = CELL_TO_FLOAT(params[2]); - if (fuel > 100.0) - fuel = 100.0; - if (fuel < 0.0) - fuel = 0.0; - player->pev->fuser3 = fuel * 10.0; - return 1; -} -static cell AMX_NATIVE_CALL ns_is_combat(AMX *amx, cell *params) -{ - return iscombat; -} - -static cell AMX_NATIVE_CALL ns_get_mask(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxEntities) - return -1; - edict_t *pEntity = INDEXENT2(params[1]); - if (pEntity->v.iuser4 & params[2]) - return 1; - return 0; -} -static cell AMX_NATIVE_CALL ns_set_mask(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxEntities) - return -1; - edict_t *pEntity = INDEXENT2(params[1]); - if (params[3] > 0) - { - if (pEntity->v.iuser4 & params[2]) - return 0; - pEntity->v.iuser4 |= params[2]; - return 1; - } - if (pEntity->v.iuser4 & params[2]) - { - pEntity->v.iuser4 &= ~params[2]; - return 1; - } - return 0; -} - -static cell AMX_NATIVE_CALL ns_popup(AMX *amx, cell *params) -{ - if (!gmsgHudText2) - gmsgHudText2 = GET_USER_MSG_ID(PLID, "HudText2", NULL); - if (params[1]) - { - if (params[1] > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(params[1]); - MESSAGE_BEGIN(MSG_ONE,gmsgHudText2,NULL,player->edict); - } - else - MESSAGE_BEGIN(MSG_ALL,gmsgHudText2); - int len; - char *blah = MF_GetAmxString(amx,params[2],0,&len); - char msg[190]; - strncpy(msg,blah,188); - WRITE_STRING(msg); - WRITE_BYTE(params[3]); - MESSAGE_END(); - return 1; -} -static cell AMX_NATIVE_CALL ns_set_fov(AMX *amx, cell *params) -{ - if (params[1] < 1 || params[1] > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(params[1]); - REAL fov = CELL_TO_FLOAT(params[2]); - LOG_CONSOLE(PLID,"Got fov. fov=%f",fov); - int gmsgSetFov = GET_USER_MSG_ID(PLID, "SetFOV", NULL); - if (fov == 0.0) - { - player->foved=false; - player->fov=0.0; - MESSAGE_BEGIN(MSG_ONE,gmsgSetFov,NULL,player->edict); - WRITE_BYTE(0); - MESSAGE_END(); - return 1; - } - if (fov > 0) - { - player->foved=true; - player->fov=fov; - MESSAGE_BEGIN(MSG_ONE,gmsgSetFov,NULL,player->edict); - WRITE_BYTE((int)fov); - MESSAGE_END(); - return 1; - } - return 0; -} -static cell AMX_NATIVE_CALL ns_giveitem(AMX *amx, cell *params) -{ - int index=params[1]; - int len; - char *classname = MF_GetAmxString(amx,params[2],0,&len); - if (index<1 || index>gpGlobals->maxClients) - return 0; - edict_t *player=INDEXENT2(index); - if (player->v.deadflag > 0) - return 0; - edict_t *object=CREATE_NAMED_ENTITY(ALLOC_STRING(classname)); //create - if (!object) - { - MF_LogError(amx, AMX_ERR_NATIVE, "Error creating entity \"%s\"", classname); - return 0; - } - SET_ORIGIN(object,player->v.origin); // move to player - gpGamedllFuncs->dllapi_table->pfnSpawn(object); // emulate spawn - object->v.flags |= FL_ONGROUND; // make it think it's touched the ground - gpGamedllFuncs->dllapi_table->pfnThink(object); // - gpGamedllFuncs->dllapi_table->pfnTouch(object,player); // give it to the player - - return 1; -} -static cell AMX_NATIVE_CALL ns_user_kill(AMX *amx, cell *params) -{ - int index = params[1]; - if (index<1||index>gpGlobals->maxClients) - return 0; - - edict_t *e=INDEXENT2(index); - if (e->v.iuser3 == 2 /* Commander class*/) - return 0; - - if (MF_IsPlayerIngame(index) && MF_IsPlayerAlive(index)) - { - float bef = e->v.frags; - edict_t *pEntity = CREATE_NAMED_ENTITY(MAKE_STRING("trigger_hurt")); - if (pEntity) - { - KeyValueData kvd; - kvd.szClassName="trigger_hurt"; - kvd.szKeyName="classname"; - kvd.szValue="trigger_hurt"; - kvd.fHandled=0; - MDLL_KeyValue(pEntity,&kvd); - kvd.szClassName="trigger_hurt"; - kvd.szKeyName="dmg"; - kvd.szValue="20000.0"; - kvd.fHandled=0; - MDLL_KeyValue(pEntity,&kvd); - kvd.szClassName="trigger_hurt"; - kvd.szKeyName="damagetype"; - kvd.szValue="1"; - kvd.fHandled=0; - MDLL_KeyValue(pEntity,&kvd); - kvd.szClassName="trigger_hurt"; - kvd.szKeyName="origin"; - kvd.szValue="8192 8192 8192"; - kvd.fHandled=0; - MDLL_KeyValue(pEntity,&kvd); - MDLL_Spawn(pEntity); - pEntity->v.classname=MAKE_STRING("slay"); - MDLL_Touch(pEntity,e); - REMOVE_ENTITY(pEntity); - } - if (params[2]) e->v.frags = bef; - return 1; - } - - return 0; -} -#define ANGLEVECTORS (*g_engfuncs.pfnAngleVectors) -static cell AMX_NATIVE_CALL ns_user_slap(AMX *amx, cell *params) /* 2 param */ -{ - int index = params[1]; - if (index<1||index>gpGlobals->maxClients) - return 0; - int power = abs((int)params[2]); - edict_t *e=INDEXENT2(index); - if (e->v.iuser3 == 2 /* Commander class*/) - return 0; - - if (MF_IsPlayerIngame(index) && MF_IsPlayerAlive(index)) { - if (e->v.health <= power) { - float bef = e->v.frags; - /*MDLL_ClientKill(pPlayer->pEdict);*/ - edict_t *pEntity = CREATE_NAMED_ENTITY(MAKE_STRING("trigger_hurt")); - if (pEntity) - { - KeyValueData kvd; - kvd.szClassName="trigger_hurt"; - kvd.szKeyName="classname"; - kvd.szValue="trigger_hurt"; - kvd.fHandled=0; - MDLL_KeyValue(pEntity,&kvd); - kvd.szClassName="trigger_hurt"; - kvd.szKeyName="dmg"; - kvd.szValue="20000.0"; - kvd.fHandled=0; - MDLL_KeyValue(pEntity,&kvd); - kvd.szClassName="trigger_hurt"; - kvd.szKeyName="damagetype"; - kvd.szValue="1"; - kvd.fHandled=0; - MDLL_KeyValue(pEntity,&kvd); - kvd.szClassName="trigger_hurt"; - kvd.szKeyName="origin"; - kvd.szValue="8192 8192 8192"; - kvd.fHandled=0; - MDLL_KeyValue(pEntity,&kvd); - MDLL_Spawn(pEntity); - pEntity->v.classname=MAKE_STRING("slap"); - MDLL_Touch(pEntity,e); - REMOVE_ENTITY(pEntity); - } - - e->v.frags = bef; - } - else { - edict_t *pEdict = e; - int numparam = *params/sizeof(cell); - if (numparam<3 || params[3]) { - pEdict->v.velocity.x += RANDOM_LONG(-600,600); - pEdict->v.velocity.y += RANDOM_LONG(-180,180); - pEdict->v.velocity.z += RANDOM_LONG(100,200); - } - else { - vec3_t v_forward, v_right; - vec3_t vang = pEdict->v.angles; - float fang[3]; - fang[0] = vang.x; - fang[1] = vang.y; - fang[2] = vang.z; - ANGLEVECTORS( fang, v_forward, v_right, NULL ); - pEdict->v.velocity = pEdict->v.velocity + v_forward * 220 + Vector(0,0,200); - } - pEdict->v.punchangle.x = RANDOM_LONG(-10,10); - pEdict->v.punchangle.y = RANDOM_LONG(-10,10); - pEdict->v.health -= power; - int armor = (int)pEdict->v.armorvalue; - armor -= power; - if (armor < 0) armor = 0; - pEdict->v.armorvalue = armor; - pEdict->v.dmg_inflictor = pEdict; - static const char *bit_sound[3] = { - "weapons/cbar_hitbod1.wav", - "weapons/cbar_hitbod2.wav", - "weapons/cbar_hitbod3.wav" }; - EMIT_SOUND_DYN2(pEdict, CHAN_VOICE, bit_sound[RANDOM_LONG(0,2)], 1.0, ATTN_NORM, 0, PITCH_NORM); - } - return 1; - } - return 0; -} -AMX_NATIVE_INFO ns_misc_natives[] = { - /////////////////// - { "user_kill", ns_user_kill }, - { "user_slap", ns_user_slap }, - - { "ns_get_build", ns_get_build }, - - { "ns_set_player_model", ns_set_player_model }, - { "ns_set_player_skin", ns_set_player_skin }, - { "ns_set_player_body", ns_set_player_body }, - - { "ns_has_weapon", ns_has_weapon }, - - { "ns_get_spawn", ns_get_spawnpoints }, - - { "ns_get_speedchange", ns_get_speedchange }, - { "ns_set_speedchange", ns_set_speedchange }, - { "ns_get_maxspeed", ns_get_maxspeed }, - - { "ns_get_class", ns_get_class }, - - { "ns_get_jpfuel", ns_get_jpfuel }, - { "ns_set_jpfuel", ns_set_jpfuel }, - - { "ns_get_energy", ns_get_jpfuel }, // They do the same thing... - { "ns_set_energy", ns_set_jpfuel }, // - { "ns_is_combat", ns_is_combat }, - - { "ns_get_mask", ns_get_mask }, - { "ns_set_mask", ns_set_mask }, - - { "ns_popup", ns_popup }, - - { "ns_set_fov", ns_set_fov }, - - { "ns_give_item", ns_giveitem }, - - /////////////////// - - { NULL, NULL } -}; diff --git a/dlls/ns/NPData.cpp b/dlls/ns/NPData.cpp deleted file mode 100755 index 0577d8ec..00000000 --- a/dlls/ns/NPData.cpp +++ /dev/null @@ -1,389 +0,0 @@ -#include "ns.h" - -int get_private(edict_t *pEntity, int woffset,int loffset) -{ -#ifdef __linux__ - return *(int*)((char*)(pEntity->pvPrivateData)+loffset); -#else - return *(int*)((char*)(pEntity->pvPrivateData)+woffset); -#endif -} -REAL get_private_f(edict_t *pEntity, int woffset, int loffset) -{ -#ifdef __linux__ - return *(REAL*)((char*)(pEntity->pvPrivateData)+loffset); -#else - return *(REAL*)((char*)(pEntity->pvPrivateData)+woffset); -#endif -} -void set_private(edict_t *pEntity, int woffset, int loffset, int value) -{ -#ifdef __linux__ - *(int*)((char*)(pEntity->pvPrivateData)+loffset) = value; -#else - *(int*)((char*)(pEntity->pvPrivateData)+woffset) = value; -#endif -} -void set_private(edict_t *pEntity, int woffset, int loffset, REAL value) -{ -#ifdef __linux__ - *(REAL*)((char*)(pEntity->pvPrivateData)+loffset) = value; -#else - *(REAL*)((char*)(pEntity->pvPrivateData)+woffset) = value; -#endif -} - -static cell AMX_NATIVE_CALL ns_get_res(AMX *amx, cell *params) -{ - if (iscombat) - return 0; - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - - CPlayer *player = GET_PLAYER_I(id); - - if (!player->connected) - return 0; - if (player->edict->pvPrivateData == NULL) // Worth a shot to make sure it's initialized. - return 0; - REAL res = get_private_f(player->edict,OFFSET_WIN_RESOURCES,OFFSET_LIN_RESOURCES); - return FLOAT_TO_CELL(res); -} - -static cell AMX_NATIVE_CALL ns_set_res(AMX *amx, cell *params) -{ - if (iscombat) - return 0; - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - if (!player->connected || player->edict->pvPrivateData == NULL) - return 0; - REAL res = CELL_TO_FLOAT(params[2]); - set_private(player->edict,OFFSET_WIN_RESOURCES,OFFSET_LIN_RESOURCES,res); - return 1; -} -static cell AMX_NATIVE_CALL ns_get_exp(AMX *amx, cell *params) -{ - if (!iscombat) - return 0; - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - - CPlayer *player = GET_PLAYER_I(id); - - if (!player->connected) - return 0; - if (player->edict->pvPrivateData == NULL) // Worth a shot to make sure it's initialized. - return 0; - REAL res = get_private_f(player->edict,OFFSET_WIN_EXP,OFFSET_LIN_EXP); - return FLOAT_TO_CELL(res); -} - -static cell AMX_NATIVE_CALL ns_set_exp(AMX *amx, cell *params) -{ - if (!iscombat) - return 0; - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - if (!player->connected || player->edict->pvPrivateData == NULL) - return 0; - REAL res = CELL_TO_FLOAT(params[2]); - set_private(player->edict,OFFSET_WIN_EXP,OFFSET_LIN_EXP,res); - return 1; -} - -static cell AMX_NATIVE_CALL ns_get_points(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - if (!player->connected || player->edict->pvPrivateData == NULL) - return 0; - return get_private(player->edict,OFFSET_WIN_POINTS,OFFSET_LIN_POINTS); -} -static cell AMX_NATIVE_CALL ns_set_points(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - if (!player->connected || player->edict->pvPrivateData == NULL) - return 0; - set_private(player->edict,OFFSET_WIN_POINTS,OFFSET_LIN_POINTS,(int)params[2]); - return 1; -} -static cell AMX_NATIVE_CALL ns_set_weapon_dmg(AMX *amx, cell *params) -{ - int id = params[1]; - if (id <= gpGlobals->maxClients || id > gpGlobals->maxEntities) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (pEntity->pvPrivateData == NULL) - return 0; - REAL dmg = CELL_TO_FLOAT(params[2]); - set_private(pEntity,OFFSET_WIN_WEAPDMG,OFFSET_LIN_WEAPDMG,dmg); - return 1; -} -static cell AMX_NATIVE_CALL ns_get_weapon_dmg(AMX *amx, cell *params) -{ - int id = params[1]; - if (id <= gpGlobals->maxClients || id > gpGlobals->maxEntities) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (pEntity->pvPrivateData == NULL) - return 0; - return FLOAT_TO_CELL(get_private_f(pEntity,OFFSET_WIN_WEAPDMG,OFFSET_LIN_WEAPDMG)); -} - -static cell AMX_NATIVE_CALL ns_set_weapon_range(AMX *amx, cell *params) -{ - int id = params[1]; - if (id <= gpGlobals->maxClients || id > gpGlobals->maxEntities) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (pEntity->pvPrivateData == NULL) - return 0; - REAL dmg = CELL_TO_FLOAT(params[2]); - set_private(pEntity,OFFSET_WIN_WEAPRANGE,OFFSET_LIN_WEAPRANGE,dmg); - return 1; -} -static cell AMX_NATIVE_CALL ns_get_weapon_range(AMX *amx, cell *params) -{ - int id = params[1]; - if (id <= gpGlobals->maxClients || id > gpGlobals->maxEntities) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (pEntity->pvPrivateData == NULL) - return 0; - return FLOAT_TO_CELL(get_private_f(pEntity,OFFSET_WIN_WEAPRANGE,OFFSET_LIN_WEAPRANGE)); -} -static cell AMX_NATIVE_CALL ns_set_weapon_ammo(AMX *amx, cell *params) -{ - int id = params[1]; - if (id <= gpGlobals->maxClients || id > gpGlobals->maxEntities) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (pEntity->pvPrivateData == NULL) - return 0; - set_private(pEntity,OFFSET_WIN_WEAPCLIP,OFFSET_LIN_WEAPCLIP,(int)params[2]); - return 1; -} -static cell AMX_NATIVE_CALL ns_get_weapon_ammo(AMX *amx, cell *params) -{ - int id = params[1]; - if (id <= gpGlobals->maxClients || id > gpGlobals->maxEntities) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (pEntity->pvPrivateData == NULL) - return 0; - return get_private(pEntity,OFFSET_WIN_WEAPCLIP,OFFSET_LIN_WEAPCLIP); -} -static cell AMX_NATIVE_CALL ns_get_weap_reserve(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - if (!player->connected || player->edict->pvPrivateData == NULL) - return 0; - switch (params[2]) - { - case WEAPON_PISTOL: - return get_private(player->edict,OFFSET_WIN_AMMO_PISTOL,OFFSET_LIN_AMMO_PISTOL); - case WEAPON_LMG: - return get_private(player->edict,OFFSET_WIN_AMMO_LMG,OFFSET_LIN_AMMO_LMG); - case WEAPON_SHOTGUN: - return get_private(player->edict,OFFSET_WIN_AMMO_SHOTGUN,OFFSET_LIN_AMMO_SHOTGUN); - case WEAPON_HMG: - return get_private(player->edict,OFFSET_WIN_AMMO_HMG,OFFSET_LIN_AMMO_HMG); - case WEAPON_GRENADE_GUN: - return get_private(player->edict,OFFSET_WIN_AMMO_GL,OFFSET_LIN_AMMO_GL); - case WEAPON_GRENADE: - return get_private(player->edict,OFFSET_WIN_AMMO_HG,OFFSET_LIN_AMMO_HG); - default: - return 0; - } - return 0; -} -static cell AMX_NATIVE_CALL ns_set_weap_reserve(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - if (!player->connected || player->edict->pvPrivateData == NULL) - return 0; - switch (params[2]) - { - case WEAPON_PISTOL: - set_private(player->edict,OFFSET_WIN_AMMO_PISTOL,OFFSET_LIN_AMMO_PISTOL,(int)params[3]); - return 1; - case WEAPON_LMG: - set_private(player->edict,OFFSET_WIN_AMMO_LMG,OFFSET_LIN_AMMO_LMG,(int)params[3]); - return 1; - case WEAPON_SHOTGUN: - set_private(player->edict,OFFSET_WIN_AMMO_SHOTGUN,OFFSET_LIN_AMMO_SHOTGUN,(int)params[3]); - return 1; - case WEAPON_HMG: - set_private(player->edict,OFFSET_WIN_AMMO_HMG,OFFSET_LIN_AMMO_HMG,(int)params[3]); - return 1; - case WEAPON_GRENADE_GUN: - set_private(player->edict,OFFSET_WIN_AMMO_GL,OFFSET_LIN_AMMO_GL,(int)params[3]); - return 1; - case WEAPON_GRENADE: - set_private(player->edict,OFFSET_WIN_AMMO_HG,OFFSET_LIN_AMMO_HG,(int)params[3]); - return 1; - default: - return 0; - } - return 0; -} -static cell AMX_NATIVE_CALL ns_get_score(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - if (!player->connected || player->edict->pvPrivateData == NULL) - return 0; - return get_private(player->edict,OFFSET_WIN_SCORE,OFFSET_LIN_SCORE); -} -static cell AMX_NATIVE_CALL ns_set_score(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - if (!player->connected || player->edict->pvPrivateData == NULL) - return 0; - set_private(player->edict,OFFSET_WIN_SCORE,OFFSET_LIN_SCORE,(int)params[2]); - return 1; -} -static cell AMX_NATIVE_CALL ns_set_hive_trait(AMX *amx, cell *params) -{ - int id = params[1]; - if (id <= gpGlobals->maxClients || id > gpGlobals->maxEntities) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (pEntity->pvPrivateData == NULL) - return 0; - set_private(pEntity,OFFSET_WIN_HIVE_TRAIT,OFFSET_LIN_HIVE_TRAIT,(int)params[2]); - return 1; -} -static cell AMX_NATIVE_CALL ns_get_hive_trait(AMX *amx, cell *params) -{ - int id = params[1]; - if (id <= gpGlobals->maxClients || id > gpGlobals->maxEntities) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (pEntity->pvPrivateData == NULL) - return 0; - return get_private(pEntity,OFFSET_WIN_HIVE_TRAIT,OFFSET_LIN_HIVE_TRAIT); -} -static cell AMX_NATIVE_CALL ns_get_deaths(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - return get_private(player->edict,OFFSET_WIN_DEATHS,OFFSET_LIN_DEATHS); -} -static cell AMX_NATIVE_CALL ns_set_deaths(AMX *amx, cell *params) -{ - int id = params[1]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - CPlayer *player = GET_PLAYER_I(id); - set_private(player->edict,OFFSET_WIN_DEATHS,OFFSET_LIN_DEATHS,(int)params[2]); - return 1; -} - -static cell AMX_NATIVE_CALL ns_get_struct_owner(AMX *amx, cell *params) -{ - int id = params[1]; - if (id <= gpGlobals->maxClients || id >= gpGlobals->maxEntities) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (!pEntity) - return 0; - if (pEntity->pvPrivateData == NULL) - return 0; - return get_private(pEntity,OFFSET_WIN_STRUCTOWNER,OFFSET_LIN_STRUCTOWNER); -} -static cell AMX_NATIVE_CALL ns_set_struct_owner(AMX *amx, cell *params) -{ - int id = params[1]; - int ido = params[2]; - if (id <= gpGlobals->maxClients || id >= gpGlobals->maxEntities) - return 0; - if (ido > gpGlobals->maxClients || ido < -1) - return 0; - edict_t *pEntity = INDEXENT2(id); - if (!pEntity) - return 0; - if (pEntity->pvPrivateData == NULL) - return 0; - set_private(pEntity,OFFSET_WIN_STRUCTOWNER,OFFSET_LIN_STRUCTOWNER,ido); - return 1; -} - -static cell AMX_NATIVE_CALL ns_get_hive_ability(AMX *amx, cell *params) -{ - int id = params[1]; - int abilitynum = params[2]; - if (id < 1 || id > gpGlobals->maxClients) - return 0; - - CPlayer *player = GET_PLAYER_I(id); - int result = get_private(player->edict, OFFSET_WIN_HIVEABILITY, OFFSET_LIN_HIVEABILITY); - - return (abilitynum > 0) ? (result >= abilitynum - 1) : result; -} - -AMX_NATIVE_INFO ns_pdata_natives[] = { - /*****************/ - { "ns_get_res", ns_get_res }, - { "ns_set_res", ns_set_res }, - - { "ns_get_exp", ns_get_exp }, - { "ns_set_exp", ns_set_exp }, - - { "ns_get_points", ns_get_points }, - { "ns_set_points", ns_set_points }, - - { "ns_set_weap_dmg", ns_set_weapon_dmg }, - { "ns_get_weap_dmg", ns_get_weapon_dmg }, - - { "ns_set_weap_range", ns_set_weapon_range }, - { "ns_get_weap_range", ns_get_weapon_range }, - - { "ns_set_weap_clip", ns_set_weapon_ammo }, - { "ns_get_weap_clip", ns_get_weapon_ammo }, - - { "ns_set_weap_reserve", ns_set_weap_reserve }, - { "ns_get_weap_reserve", ns_get_weap_reserve }, - - { "ns_set_score", ns_set_score }, - { "ns_get_score", ns_get_score }, - - { "ns_get_deaths", ns_get_deaths }, - { "ns_set_deaths", ns_set_deaths }, - - { "ns_get_hive_trait", ns_get_hive_trait }, - { "ns_set_hive_trait", ns_set_hive_trait }, - - { "ns_get_struct_owner", ns_get_struct_owner }, - { "ns_set_struct_owner", ns_set_struct_owner }, - - { "ns_get_hive_ability", ns_get_hive_ability}, - - { NULL, NULL } -}; - diff --git a/dlls/ns/ParticleManager.cpp b/dlls/ns/ParticleManager.cpp new file mode 100644 index 00000000..626c4838 --- /dev/null +++ b/dlls/ns/ParticleManager.cpp @@ -0,0 +1,121 @@ +#include "sdk/amxxmodule.h" +#include "ns.h" + +#include "CVector.h" +#include "CString.h" + +#include "ParticleManager.h" + + +void ParticleManager::ReadFile(void) +{ + this->Prune(); + if (m_iFileLoaded!=0) + { + return; + } + m_iFileLoaded=1; + + char FileName[256]; + + snprintf(FileName,sizeof(FileName)-1,"%s/ns.ps",MF_GetModname()); + FILE *fp=fopen(FileName,"r"); + + if (!fp) + { + MF_Log("ParticleManager: Cannot open \"%s\" for reading!",FileName); + return; + } + + // Since I don't care about the actual parameters of each + // particle system, just their order and name + // I only have to scan for "start pSystemName NAME" + + char Buffer[1024]; + + char *Start; + char *End; + + int Count=0; + + memset(&Buffer[0],0x0,sizeof(Buffer)); + + while (!feof(fp)) + { + Buffer[0]='\0'; + + fgets(Buffer,1023,fp); + + Start=&Buffer[0]; + + // strip whitespace from the front + while (*Start==' ' || + *Start=='\t') + { + ++Start; + } + + // if the first character is ' ignore it + if (*Start=='\'') + { + continue; + } + + // if the first word is "start" then this is a line we want + + if (strncmp("start ",Start,6)!=0) + { + continue; + } + + // Move up past 2 space blocks + + while (*Start!='\0' && + *Start!=' ' && + *Start!='\t') + { + ++Start; + } + while (*Start==' ' || + *Start=='\t') + { + ++Start; + } + + while (*Start!='\0' && + *Start!=' ' && + *Start!='\t') + { + ++Start; + } + while (*Start==' ' || + *Start=='\t') + { + ++Start; + } + + // now strip whitespace from the end + + End=Start+strlen(Start)-1; + + while (*End=='\n' || + *End=='\r' || + *End==' ' || + *End=='\t') + { + *End--='\0'; + } + + // "Start" should now point to the name of this particle system + + //printf("Particle system %d = \"%s\"\n",Count,Start); + + + this->Add(Start,1); + + + ++Count; + } + + fclose(fp); +}; diff --git a/dlls/ns/ParticleManager.h b/dlls/ns/ParticleManager.h new file mode 100644 index 00000000..07cec51f --- /dev/null +++ b/dlls/ns/ParticleManager.h @@ -0,0 +1,152 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +#ifndef PARTICLEMANAGER_H +#define PARTICLEMANAGER_H + +typedef struct psystem_s +{ + String Name; + int id; + int IsStatic; // Set to 1 if the particle system is loaded from ns.ps + +} ParticleSystem; + +class ParticleManager +{ +private: + CVector Systems; + int m_iFileLoaded; + unsigned short m_iEventID; + +public: + ParticleManager() + { + m_iFileLoaded=0; + m_iEventID=0; + Systems.reserve(64); + }; + + // Remove all non-static particle systems + inline void Prune() + { + if (Systems.size()==0) + { + return; + } + CVector::iterator iter; + while (1) + { + if (Systems.size()==0) + { + break; + } + iter=Systems.end(); + iter--; + + if ((*iter)->IsStatic) + { + break; + } + + delete (*iter); + Systems.pop_back(); + }; + }; + + void ReadFile(void); + + inline int Add(const char *Start, int Static) + { + ParticleSystem *ps=new ParticleSystem; + + ps->id=Systems.size(); + ps->IsStatic=Static; + ps->Name.assign(Start); + + Systems.push_back(ps); + + return Systems.size()-1; + }; + inline void FireSystem(int id, float *Origin, float *Angles, int flags) + { + PLAYBACK_EVENT_FULL(flags, /*flags*/ + NULL, /*pInvoker*/ + m_iEventID, /*eventid*/ + 0.0, /*delay*/ + Origin, /*origin*/ + Angles, /*angles*/ + 0.0, /*fparam1*/ + 0.0, /*fparam2*/ + id, /*iparam1 - particle system id*/ + 0, /*iparam2*/ + 0, /*bparam1*/ + 0); /*bparam2*/ + }; + inline void PrecacheEvent(const char *file) + { + if (strcmp(file,"events/Particle.sc")==0) + { + if (META_RESULT_STATUS >= MRES_OVERRIDE) + { + m_iEventID=META_RESULT_OVERRIDE_RET(unsigned short); + } + else + { + m_iEventID=META_RESULT_ORIG_RET(unsigned short); + } + //printf("EVENT=%d\n",m_iEventID); + } + }; + inline int Find(const char *Needle) + { + CVector::iterator iter=Systems.begin(); + CVector::iterator end=Systems.end(); + + while (iter!=end) + { + if (strcmp(Needle,(*iter)->Name.c_str())==0) + { + return (*iter)->id; + } + ++iter; + } + + return -1; + }; + +}; + +extern ParticleManager ParticleMan; + +#endif // PARTICLEMANAGER_H diff --git a/dlls/ns/SpawnManager.h b/dlls/ns/SpawnManager.h new file mode 100644 index 00000000..af6d6b1e --- /dev/null +++ b/dlls/ns/SpawnManager.h @@ -0,0 +1,128 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +#ifndef SPAWNMANAGER_H +#define SPAWNMANAGER_H + +#include "CVector.h" + +typedef struct spawndata_s +{ + REAL Location[3]; + REAL Angle[3]; +} SpawnData; + +class SpawnManager +{ +private: + CVector TeamSpawns[5]; + +public: + SpawnManager() + { + this->Clear(); + }; + + inline void Clear(void) + { + TeamSpawns[0].clear(); + TeamSpawns[1].clear(); + TeamSpawns[2].clear(); + TeamSpawns[3].clear(); + TeamSpawns[4].clear(); + + // Reserve data for a "typical" map layout + // makes data entry faster on map load + TeamSpawns[0].reserve(32); + TeamSpawns[1].reserve(16); + TeamSpawns[2].reserve(48); + }; + + inline void Insert(const edict_t *Entity) + { + // Bounds check team + if (Entity->v.team<0 || Entity->v.team > 4) + { + return; + } + + SpawnData TemporaryData; + + Entity->v.origin.CopyToArray(TemporaryData.Location); + Entity->v.angles.CopyToArray(TemporaryData.Angle); + + TeamSpawns[Entity->v.team].push_back(TemporaryData); + }; + inline void InsertReadyRoom(const edict_t *Entity) + { + SpawnData TemporaryData; + + Entity->v.origin.CopyToArray(TemporaryData.Location); + Entity->v.angles.CopyToArray(TemporaryData.Angle); + + TeamSpawns[0].push_back(TemporaryData); + }; + + // ns_get_spawn(team,number=0,Float:ret[3]); + inline cell Lookup(AMX *amx, cell *params) + { + if (params[1] < 0 || params[1] > 4) + { + return 0; + } + if (params[2]==0) + { + return static_cast(TeamSpawns[params[1]].size()); + } + + if (params[2]>=(int)TeamSpawns[params[1]].size()) + { + return 0; + } + + cell *Return=MF_GetAmxAddr(amx,params[3]); + + SpawnData SpawnRet=TeamSpawns[params[1]][params[2]]; + + Return[0]=amx_ftoc2(SpawnRet.Location[0]); + Return[1]=amx_ftoc2(SpawnRet.Location[1]); + Return[2]=amx_ftoc2(SpawnRet.Location[2]); + + return 1; + + }; +}; + +extern SpawnManager SpawnMan; + +#endif // SPAWNMANAGER_H diff --git a/dlls/ns/TitleManager.cpp b/dlls/ns/TitleManager.cpp new file mode 100644 index 00000000..f08ff64a --- /dev/null +++ b/dlls/ns/TitleManager.cpp @@ -0,0 +1,142 @@ +#include "sdk/amxxmodule.h" +#include "ns.h" +#include "TitleManager.h" + + + +void TitleManager::LoadTitles(void) +{ + if (m_Loaded!=0) // already loaded? + { + return; + } + + m_Loaded=1; + + char FileName[128]; + + snprintf(FileName,127,"%s/titles.txt",MF_GetModname()); + + FILE *fp=fopen(FileName,"r"); + + if (!fp) + { + MF_Log("Unable to load \"%s\": TitleManager will not work!",FileName); + return; + }; + + //MF_Log("TitleManager Loading titles from \"%s\"",FileName); + char KeyName[512]; // last known good keyname + char Data[2048]; // data for the key + // does not support multi line data, but for + // location namesthat is acceptable. + char TempBuffer[2048]; // currently read data + char *TempPointer; + char *TempPointerEnd; + + unsigned int Line=0; +scan_for_key: + KeyName[0]='\0'; + + while (!feof(fp)) + { + Line++; + fgets(TempBuffer,2047,fp); + TempPointer=&TempBuffer[0]; + + // get rid of white space at the front + while (*TempPointer=='\0' || // terminator + *TempPointer==' ' || // space + *TempPointer=='\t') // tab + { + ++TempPointer; + } + if (*TempPointer=='\0' || // terminator + *TempPointer=='/') // comment + { + continue; + } + + // get rid of \r\n at the end + TempPointerEnd=TempPointer+strlen(TempPointer)-1; + while (*TempPointerEnd=='\r' || + *TempPointerEnd=='\n' || + *TempPointerEnd=='\t' || + *TempPointerEnd==' ') + { + *TempPointerEnd--='\0'; + } + + if (*TempPointer=='{') // start of data + { + if (KeyName[0]!='\0') // do we have a keyname + { + goto scan_for_data; + } + else + { + MF_Log("TitleManager: titles.txt line %u: began a data section with no key name in use!",Line); + goto scan_for_key; + } + } + + // have a valid key name here + strncpy(KeyName,TempBuffer,sizeof(KeyName)-1); + + // keep looping (until we hit a '{') + }; + + // if we're out here then !feof() failed + goto end_of_file; +scan_for_data: + Data[0]='\0'; + + while (!feof(fp)) + { + Line++; + fgets(TempBuffer,2047,fp); + TempPointer=&TempBuffer[0]; + + // get rid of white space at the front + while (*TempPointer=='\0' || // terminator + *TempPointer==' ' || // space + *TempPointer=='\t') // tab + { + ++TempPointer; + } + if (*TempPointer=='\0' || // terminator + *TempPointer=='/') // comment + { + continue; + } + + // get rid of trailing whitespace + TempPointerEnd=TempPointer+strlen(TempPointer)-1; + while (*TempPointerEnd=='\r' || + *TempPointerEnd=='\n' || + *TempPointerEnd=='\t' || + *TempPointerEnd==' ') + { + *TempPointerEnd--='\0'; + } + + if (*TempPointer=='}') // end of data + { + // insert KeyName & Data into the hash + String key(KeyName); + + key.toLower(); + this->m_Hash.insert(key, new String(Data)); + + goto scan_for_key; + } + + // have valid data here + strncpy(Data,TempBuffer,sizeof(Data)-1); + }; +end_of_file: + + fclose(fp); + + //MF_Log("TitleManager loaded %u entries from titles.txt (%u lines parsed)",m_List.size(),Line); +}; diff --git a/dlls/ns/TitleManager.h b/dlls/ns/TitleManager.h new file mode 100644 index 00000000..47c58ddb --- /dev/null +++ b/dlls/ns/TitleManager.h @@ -0,0 +1,79 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +#ifndef TITLEMANAGER_H +#define TITLEMANAGER_H + +#include +#include +#include + +#include "CString.h" +#include "Hash.h" + + +class TitleManager +{ +private: + int m_Loaded; + + // Use a string pointer for the data type because the location manager + // stores a direct pointer to the c_str() of the title + Hash m_Hash; + +public: + + TitleManager() + { + m_Loaded=0; + }; + + inline const char *Lookup(String &input) + { + String** ret = m_Hash.find(input); + + if (ret == NULL || *ret == NULL) + { + // was not found + return NULL; + } + + + return (*ret)->c_str(); + }; + void LoadTitles(void); +}; + +extern TitleManager TitleMan; + +#endif // TITLEMANAGER_H diff --git a/dlls/ns/amxxapi.cpp b/dlls/ns/amxxapi.cpp new file mode 100644 index 00000000..881ff29f --- /dev/null +++ b/dlls/ns/amxxapi.cpp @@ -0,0 +1,107 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* Calls sent by AMX Mod X are handled here */ + +#include "sdk/amxxmodule.h" + +#include "ns.h" +#include "utilfunctions.h" + +#include "CVector.h" +#include "CString.h" + +#include "GameManager.h" +#include "TitleManager.h" +#include "MessageHandler.h" +#include "ParticleManager.h" + +#include "AllocString.h" + +extern int gmsgHudText2; +extern BOOL iscombat; + +TitleManager TitleMan; +ParticleManager ParticleMan; + +void MFuncs_Initialize(void); + +// Native register calls here +void AddNatives_MemberFunc(); +void AddNatives_Particles(); +void AddNatives_Player(); +void AddNatives_PlayerMemory(); +void AddNatives_Weapons(); +void AddNatives_Structure(); +void AddNatives_General(); + +// All plugins have loaded (called during spawning worldspawn) +void OnPluginsLoaded() +{ + + // This message is used for the ns_popup native + GameMan.GetMessageIDs(); + + // Check the map name and see if it's combat or not. + GameMan.EvaluateCombat(); + + GameMan.RegisterForwards(); + + GameMan.CheckAllHooks(); + + AllocStringList.Clear(); + + TitleMan.LoadTitles(); + + GameMan.CheckMap(); + + ParticleMan.ReadFile(); +} + + + + +// Module is attaching to AMXX +void OnAmxxAttach() +{ + AddNatives_MemberFunc(); + AddNatives_Particles(); + AddNatives_Player(); + AddNatives_PlayerMemory(); + AddNatives_Weapons(); + AddNatives_Structure(); + AddNatives_General(); + + MFuncs_Initialize(); +} + diff --git a/dlls/ns/amxxapi.h b/dlls/ns/amxxapi.h deleted file mode 100755 index 87e9df73..00000000 --- a/dlls/ns/amxxapi.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _INCLUDE_AMXXAPI_H -#define _INCLUDE_AMXXAPI_H - -extern int ChangeclassForward; -extern int BuiltForward; - -#endif //_INCLUDE_AMXXAPI_H diff --git a/dlls/ns/dllapi.cpp b/dlls/ns/dllapi.cpp new file mode 100644 index 00000000..c344f376 --- /dev/null +++ b/dlls/ns/dllapi.cpp @@ -0,0 +1,234 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* Calls going from the engine to the game dll are handled here */ + +#include "sdk/amxxmodule.h" + + +#include "ns.h" +#include "utilfunctions.h" + +#include "SpawnManager.h" + +#include "GameManager.h" +#include "CPlayer.h" +#include "MessageHandler.h" +#include "LocationManager.h" +#include "ParticleManager.h" + +LocationManager LocationMan; +GameManager GameMan; +SpawnManager SpawnMan; + +extern edict_t* avhgameplay; + +CPlayer g_player[33]; +extern void *GameRules; + +bool NEW_Initialized=false; +edict_t *NEW_FirstEdict=NULL; + +/** + * This is only called during the CountDown + * This call will unhook itself with Metamod + * when it is finished. + */ +void StartFrame() +{ + GameMan.StartFrame(); + RETURN_META(MRES_IGNORED); +} + +/** + * Check spawning for: + * - Worldspawn + * - Initialize NEW_Utilities + * - Clear CPlayer / CSpawn data + * - info_team_start (team spawn point) + * - Save in list + * - info_player_start (ready room spawn point) + * - Save in list + */ +int DispatchSpawn(edict_t *pEntity) +{ + if (!NEW_Initialized) + { + NEW_Initialize(pEntity); + } + if (ENTINDEX_NEW(pEntity)==0) // worldspawn + { + int i=0; + while (i<=32) + { + GET_PLAYER_I(i++)->Reset(); + } + + LocationMan.Clear(); + + SpawnMan.Clear(); + + } + else if (FStrEq(STRING(pEntity->v.classname),"info_player_start")) + { + // Mark down the ready room spawn point. + SpawnMan.InsertReadyRoom(pEntity); + } + else if (FStrEq(STRING(pEntity->v.classname),"info_team_start")) + { + // Mark down the team based spawn point. + SpawnMan.Insert(pEntity); + } + + else if (FStrEq(STRING(pEntity->v.classname),"env_particles_custom")) + { + ParticleMan.Add(STRING(pEntity->v.targetname),0); + } + + RETURN_META_VALUE(MRES_IGNORED, 0); +} + +void DispatchKeyValue(edict_t *pEntity,KeyValueData *pkvd) +{ + if (strcmp(pkvd->szKeyName,"locationname")==0) + { + if (pkvd->szClassName && strcmp(pkvd->szClassName,"info_location")==0) + { + // this is a BSP model, so calling SetModel + // will update the mins/maxs + SET_MODEL(pEntity,STRING(pEntity->v.model)); + + // Add it to our list + LocationMan.Add(pkvd->szValue,pEntity); + RETURN_META(MRES_IGNORED); + } + } + RETURN_META(MRES_IGNORED); +} + +void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) +{ + // Reset CPlayer classes (again?) + for(int i = 1; i <= gpGlobals->maxClients;i++) + { + + CPlayer *player=GET_PLAYER_I(i); + + player->FullReset(); + + player->SetEdict(pEdictList + i); + + } + + GameRules=NULL; + + RETURN_META(MRES_IGNORED); +} + +void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax) +{ + Initialize_MessageHandler(); + + g_pFunctionTable_Post->pfnServerActivate=NULL; + + RETURN_META(MRES_IGNORED); +} + +/** + * PlayerPreThink, PlayerPreThink_Post and PlayerPostThink_Post + * all disable their Metamod hook calls when they are no longer needed. + * (Actually it is disabled in the native calls) + */ +void PlayerPreThink(edict_t *pEntity) +{ + GET_PLAYER_E(pEntity)->PreThink(); + RETURN_META(MRES_IGNORED); +} +void PlayerPreThink_Post(edict_t *pEntity) +{ + GET_PLAYER_E(pEntity)->PreThink_Post(); + + RETURN_META(MRES_IGNORED); +} +void PlayerPostThink_Post(edict_t *pEntity) +{ + GET_PLAYER_E(pEntity)->PostThink_Post(); + + RETURN_META(MRES_IGNORED); +} + + + +// Map is changing/server is shutting down. +// We do all cleanup routines here, since, as noted in metamod's dllapi +// ServerDeactivate is the very last function called before the server loads up a new map. +void ServerDeactivate(void) +{ + for (int i=1;i<=gpGlobals->maxClients;i++) + { + GET_PLAYER_I(i)->Disconnect(); + } + GameRules = NULL; + avhgameplay = NULL; + RETURN_META(MRES_IGNORED); +} + +// Reset player data here.. +qboolean ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ]) +{ + // Client's connecting. Freshen up his save data, and mark him as being connected. + GET_PLAYER_E(pEntity)->Connect(); + + RETURN_META_VALUE(MRES_HANDLED,0); +} +void ClientDisconnect(edict_t *pEntity) +{ + // Client is disconnecting, clear all his saved information. + GET_PLAYER_E(pEntity)->Disconnect(1); + + RETURN_META(MRES_HANDLED); +} + +/** + * NS resets pev->fov every single frame, but this is called right before the data is sent to the client. + * Reset FOV if we need to. + * - + * NOTE: This function is not called if no clients have FoV changed + */ +void UpdateClientData( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) +{ + GET_PLAYER_E(const_cast(static_cast(ent)))->UpdateFOV(); + + RETURN_META(MRES_HANDLED); + +} diff --git a/dlls/ns/engineapi.cpp b/dlls/ns/engineapi.cpp new file mode 100644 index 00000000..69896462 --- /dev/null +++ b/dlls/ns/engineapi.cpp @@ -0,0 +1,317 @@ +/* AMX Mod X + * Natural Selection 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. + */ + +/* Calls going from the game dll to the engine are handled here */ + +#include "sdk/amxxmodule.h" + +#include "ns.h" + +#include "utilfunctions.h" +#include "CVector.h" +#include "CString.h" + +#include "GameManager.h" +#include "ParticleManager.h" +#include "CPlayer.h" + + +// Parse log messages here for any desired information (structure_built, etc.) +// The following logs are needed: +// "sawce<1>" triggered "structure_built" (type "defensechamber")` +void AlertMessage_Post(ALERT_TYPE atype, char *szFmt, ...) +{ + if (atype != at_logged) + { + RETURN_META(MRES_IGNORED); + } + + char *MessageStart; // original pointer to start of the message + char *TypePointer; // pointer to the structure type + char *CIDPointer; // pointer to the name text + + int CID; // connection ID of the player + + va_list LogArgs; + + va_start(LogArgs,szFmt); + MessageStart=va_arg(LogArgs,char *); + va_end(LogArgs); + + if (MessageStart==NULL) // Somehow got a null pointer, get out of here now + { + RETURN_META(MRES_IGNORED); + } + + + if ((TypePointer=strstr(MessageStart,"\"structure_built\""))==NULL) // was not found + { + RETURN_META(MRES_IGNORED); + } + + if (*(TypePointer - 2) != 'd') // If this is not from a 'triggered "structure_built"', then ignore the message + { + RETURN_META(MRES_IGNORED); + } + + // If we got here, then for all we can tell this message is good + + // Move up a few spaces + TypePointer+=25; // strlen("\"structure_built\" (type \"")=25 + + // Now get the player's CID + CIDPointer=MessageStart+1; // skip over the very first quotation mark + + while (*CIDPointer++ != '"') /*do nothing*/; + + --CIDPointer; + + // Move back past three < + + while (*CIDPointer-- != '<') /* do nothing*/; + while (*CIDPointer-- != '<') /* do nothing*/; + while (*CIDPointer-- != '<') /* do nothing*/; + + ++CIDPointer; + + // now skip past the < + ++CIDPointer; + + // We now point to the CID string, atoi will stop at the > so just atoi it for the CID + CID=atoi(CIDPointer); + + CPlayer *Player; + + if ((Player=UTIL_PlayerByCID(CID))==NULL) + { + RETURN_META(MRES_IGNORED); + } + + // list of what impulses represent what type of structure building + // use + // 0 for unknown (shouldn't be used ever) + // 1 for marine + // 2 for alien + + // I'm marking the upgrades as marine structures just incase + // they should never be used though! + static int StructureTypes[128] = + { + + 0, // 0 = unknown + 0, // 1 = next weapon + 0, // 2 = reload + 0, // 3 = drop weapon + 0, // 4 = unknown + 0, // 5 = unknown + 0, // 6 = unknown + 0, // 7 = radio comm + 0, // 8 = radio comm + 0, // 9 = radio comm + + 0, // 10 = radio comm + 0, // 11 = radio comm + 0, // 12 = radio comm + 0, // 13 = radio comm + 0, // 14 = radio comm + 0, // 15 = radio comm + 0, // 16 = unknown + 0, // 17 = unknown + 0, // 18 = unknown + 0, // 19 = unknown + + 1, // 20 = armor 1 + 1, // 21 = armor 2 + 1, // 22 = armor 3 + 1, // 23 = weapons 1 + 1, // 24 = weapons 2 + 1, // 25 = weapons 3 + 1, // 26 = siege upgrade + 1, // 27 = drop catalyst + 1, // 28 = research jp + 1, // 29 = research ha + + 1, // 30 = distress beacon + 1, // 31 = resupply (combat) + 0, // 32 = unknown + 1, // 33 = motion tracking + 1, // 34 = phase gates upgrade + 0, // 35 = unknown + 1, // 36 = electricity upgrade + 1, // 37 = handgrenades upgrade + 1, // 38 = drop jetpack + 1, // 39 = drop heavy armor + + 1, // 40 = infantry portal + 1, // 41 = marine RT + 0, // 42 = unused + 1, // 43 = turret factory + 0, // 44 = unused + 1, // 45 = arms lab + 1, // 46 = proto lab + 1, // 47 = upgrade + 1, // 48 = armory + 1, // 49 = advanced armory + + 0, // 50 = unknown + 1, // 51 = observatory + 0, // 52 = unknown + 1, // 53 = scanner sweep + 0, // 54 = unknown + 1, // 55 = build phase gate + 1, // 56 = build turret + 1, // 57 = build siege turret + 1, // 58 = build command chair + 1, // 59 = drop health pack + + 1, // 60 = drop ammo pack + 1, // 61 = drop mine pack + 1, // 62 = drop welder + 0, // 63 = unknown + 1, // 64 = drop shotgun + 1, // 65 = drop heavymachinegun + 1, // 66 = drop grenadelauncher + 0, // 67 = unknown + 0, // 68 = unknown + 0, // 69 = unknown + + 0, // 70 = unknown + 0, // 71 = unknown + 0, // 72 = unknown + 0, // 73 = unknown + 0, // 74 = unknown + 0, // 75 = unknown + 0, // 76 = unknown + 0, // 77 = unknown + 0, // 78 = unknown + 0, // 79 = unknown + + 0, // 80 = radio comm + 0, // 81 = radio comm + 1, // 82 = commander message + 0, // 83 = commander message + 0, // 84 = commander message + 0, // 85 = unknown + 0, // 86 = unknown + 0, // 87 = unknown + 0, // 88 = unknown + 0, // 89 = unknown + + 2, // 90 = alienresourcetower + 2, // 91 = offensechamber + 2, // 92 = defensechamber + 2, // 93 = sensorychamber + 2, // 94 = movementchamber + 2, // 95 = team_hive + 0, // 96 = unknown + 0, // 97 = unknown + 0, // 98 = unknown + 0, // 99 = unknown + + 0, // 100 = unknown + 2, // 101 = carapace + 2, // 102 = regeneration + 2, // 103 = redemption + 0, // 104 = unknown + 1, // 105 = select all marines + 0, // 106 = unknown + 2, // 107 = celerity + 2, // 108 = adrenaline + 2, // 109 = silence + + 2, // 110 = cloaking + 2, // 111 = focus + 2, // 112 = scent of fear + 2, // 113 = skulk + 2, // 114 = gorge + 2, // 115 = lerk + 2, // 116 = fade + 2, // 117 = onos + 2, // 118 = unlock next ability (combat) + 0, // 119 = unknown + + 0, // 120 = unknown + 0, // 121 = unknown + 0, // 122 = unknown + 0, // 123 = unknown + 0, // 124 = unknown + 0, // 125 = unknown + 2, // 126 = unlock next ability (combat) + 0 // 127 = unknown + }; + + int impulse=Player->GetPev()->impulse; + if (impulse < 0 || impulse > 127) + { + RETURN_META(MRES_IGNORED); + } + + if (impulse==95/*hive*/) + { + GameMan.ExecuteClientBuilt(Player->index(), UTIL_FindBuildingHive(), StructureTypes[impulse], impulse); + } + else + { + GameMan.ExecuteClientBuilt(Player->index(), ENTINDEX_NEW(GameMan.GetTemporaryEdict()), StructureTypes[impulse], impulse); + } + + RETURN_META(MRES_IGNORED); +} + +// We hook newly created entities here. +// This is where we check for client_built created entities. +edict_t* CreateNamedEntity_Post(int className) +{ + if (GameMan.IsCombat()) // this shouldn't be called during co, just incase + { + RETURN_META_VALUE(MRES_IGNORED,0); + } + + // Incase another plugin supercedes/overrides, use their returned value here. + // (Untested). + if (gpMetaGlobals->status >= MRES_OVERRIDE) + { + GameMan.SetTemporaryEdict(META_RESULT_OVERRIDE_RET(edict_t *)); + } + else + { + GameMan.SetTemporaryEdict(META_RESULT_ORIG_RET(edict_t *)); + } + RETURN_META_VALUE(MRES_IGNORED,0); +} + +unsigned short PrecacheEvent_Post(int type, const char *psz) +{ + ParticleMan.PrecacheEvent(psz); + RETURN_META_VALUE(MRES_IGNORED,0); +} diff --git a/dlls/ns/hookedfunctions.cpp b/dlls/ns/hookedfunctions.cpp deleted file mode 100755 index 15977058..00000000 --- a/dlls/ns/hookedfunctions.cpp +++ /dev/null @@ -1,487 +0,0 @@ -#include "ns.h" - - -#include //useful almost everywhere -#include -#include - -CSpawn ns_spawnpoints; -CPlayer g_player[33]; -edict_t *player_edicts[33]; - -BOOL CheckForPublic(const char *publicname); - -int gmsgHudText2=0; -int ChangeclassForward = -1; -int BuiltForward = -1; -int SpawnForward = -1; -int TeamForward = -1; -// Index of last entity hooked in CreateNamedEntity -int iCreateEntityIndex; -BOOL iscombat; -int gmsgScoreInfo=0; - -// Module is attaching to AMXX -void OnAmxxAttach() -{ - MF_AddNatives(ns_misc_natives); - MF_AddNatives(ns_pdata_natives); -} - -// All plugins have loaded (probably around Spawning worldspawn.. -void OnPluginsLoaded() -{ - - gmsgHudText2 = GET_USER_MSG_ID(&Plugin_info,"HudText2",NULL); - // Check the map name and see if it's combat or not. - iscombat=FALSE; - char mapname[255]; - strcpy(mapname,STRING(gpGlobals->mapname)); - if ((mapname[0]=='c' || mapname[0]=='C') && (mapname[1]=='o' || mapname[1]=='O') && mapname[2]=='_') - iscombat=TRUE; - - ChangeclassForward = MF_RegisterForward("client_changeclass", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE); - // No sense in this if it's combat.. - if (!iscombat) { - if (CheckForPublic("client_built")) { - BuiltForward = MF_RegisterForward("client_built", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE); - g_pengfuncsTable_Post->pfnAlertMessage=AlertMessage_Post; - g_pengfuncsTable->pfnCreateNamedEntity=CreateNamedEntity; - } else { - g_pengfuncsTable_Post->pfnAlertMessage=NULL; - g_pengfuncsTable->pfnCreateNamedEntity=NULL; - } - } else { - // no need for these hooks in co - g_pengfuncsTable_Post->pfnAlertMessage=NULL; - g_pengfuncsTable->pfnCreateNamedEntity=NULL; - } - SpawnForward = MF_RegisterForward("client_spawn",ET_IGNORE,FP_CELL/*id*/,FP_DONE); - TeamForward = MF_RegisterForward("client_changeteam",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*new team*/,FP_CELL/*old team*/,FP_DONE); -} - - - -int DispatchSpawn(edict_t *pEntity) -{ - // Everything starting up: - // - Reset CPlayer classes - // - Reset CSpawn classes - if (FStrEq(STRING(pEntity->v.classname),"worldspawn")) - { - int i; - for (i=0;i<=32;i++) - { - CPlayer *player = GET_PLAYER_I(i); - player->Reset(); - } - ns_spawnpoints.clear(); - } - else if (FStrEq(STRING(pEntity->v.classname),"info_player_start")) - { - // Mark down the ready room spawn point. - ns_spawnpoints.put(0,pEntity->v.origin); - } - else if (FStrEq(STRING(pEntity->v.classname),"info_team_start")) - { - // Mark down the team based spawn point. - ns_spawnpoints.put(pEntity->v.team,pEntity->v.origin); - } - RETURN_META_VALUE(MRES_IGNORED, 0); -} - - -void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) -{ - // Mark down proper edicts (fixes INDEXENT() bug). - // Reset CPlayer classes (again?) - for(int i = 1; i <= gpGlobals->maxClients;i++) - { - player_edicts[i]=pEdictList + i; - CPlayer *player = GET_PLAYER_I(i); - player->edict=pEdictList + i; - //player->index=i; - player->pev=&player->edict->v; - player->oldimpulse=0; - player->Reset(); - player->connected=false; - } - RETURN_META(MRES_IGNORED); -} -void PlayerPreThink(edict_t *pEntity) -{ - CPlayer *player = GET_PLAYER_E(pEntity); - player->PreThink(); - RETURN_META(MRES_IGNORED); -} -void PlayerPreThink_Post(edict_t *pEntity) -{ - CPlayer *player = GET_PLAYER_E(pEntity); - player->PreThink_Post(); - RETURN_META(MRES_IGNORED); -} -void PlayerPostThink_Post(edict_t *pEntity) -{ - CPlayer *player = GET_PLAYER_E(pEntity); - player->PostThink_Post(); - RETURN_META(MRES_IGNORED); -} - - -// Parse log messages here for any desired information (structure_built, etc.) -// The following logs are needed: -// name triggered "structure_built" (type "type") -- client_built -// name changed role to "class" -- client_changeclass -void AlertMessage_Post(ALERT_TYPE atype, char *szFmt, ...) -{ - if (atype != at_logged) - RETURN_META(MRES_IGNORED); - va_list LogArg; - char *sz, *message; - const char *b; - char szParm[5][128]; - int argc,len; - va_start(LogArg, szFmt); - sz = va_arg(LogArg, char *); - va_end(LogArg); - message = sz; - b=message; - argc=0; - // Parse the damn message - while (*b && *b!='\0' && argc<5) - { - - len=0; - if (*b == '"') - { - b++; // Skip over the " - while (*b && *b != '"' && len < 127) - { - szParm[argc][len]=*b; - b++; - len++; - } - //*szParm='\0'; - szParm[argc][len]='\0'; - if (*b && *b == '"' && *b+1 != '\0' && *b+2 != '\0') - { - b+=2; - argc++; - } - else - { - argc++; - break; - } - } - else if (*b == '(') - { - b++; // Skip over the ( - while (*b && *b != ')' && len < 127) - { - szParm[argc][len]=*b; - b++; - len++; - } - szParm[argc][len]='\0'; - if (*b && *b == ')' && *b+1 != '\0' && *b+2 != '\0') - { - b+=2; - argc++; - } - else - { - argc++; - break; - } - } - else - { - while (*b && *b != '"' && *b != '(' && len < 127) - { - szParm[argc][len]=*b; - b++; - len++; - } - szParm[argc][len]='\0'; - if (*b != '"' && *b != '(' && *b != '\0' && *b+1 != '\0' && *b+2 != '\0') - { - b+=2; - argc++; - } - else - { - argc++; - if (*b == '\0') - break; - } - - } - - - } -/* - if (argc == 3) // changed role to = 3 long - { - if (FStrEq((const char *)szParm[1],"changed role to ")) - { - int index=LogToIndex(szParm[0]); - if (!index) - RETURN_META(MRES_IGNORED); - CPlayer *player = GET_PLAYER_I(index); - int iImpulse=0; - int iClass=1; - if (INDEXENT2(index)->v.team != 0) - { - if (FStrEq((const char *)szParm[2],"gestate")) - { - iImpulse = player->oldpev.impulse; - } - if (FStrEq((const char *)szParm[2],"none")) - iClass=0; - if (iClass > 0) - { - ns2amx_changeclass.execute(index,player->oldpev.iuser3,player->pev->iuser3,iImpulse); - } - } - } - } - else */ - if (argc == 4) // structure_built / structure_destroyed are 4 long - { - //"NAME" triggered "structure_built" (type "TYPE") - if (FStrEq((const char *)szParm[2],"structure_built")) - { - int index=LogToIndex(szParm[0]); - if (!index) - RETURN_META(MRES_IGNORED); - CPlayer *player = GET_PLAYER_I(index); - - int iForward=0; - int iType=player->pev->impulse; - if (FStrEq((const char *)szParm[3],"type \"team_hive\"")) - { - iForward=2; - iCreateEntityIndex=Find_Building_Hive(); - } - else if (FStrEq((const char *)szParm[3],"type \"offensechamber\"")) - { - iForward=2; - } - else if (FStrEq((const char *)szParm[3],"type \"movementchamber\"")) - { - iForward=2; - } - else if (FStrEq((const char *)szParm[3],"type \"sensorychamber\"")) - { - iForward=2; - } - else if (FStrEq((const char *)szParm[3],"type \"defensechamber\"")) - { - iForward=2; - } - else if (FStrEq((const char *)szParm[3],"type \"alienresourcetower\"")) - { - iForward=2; - } - else - { - iForward = 1; - } -// ns2amx_built.execute(index,iCreateEntityIndex,iForward,iType); - if (BuiltForward != -1) { - MF_ExecuteForward(BuiltForward, index, FStrEq((const char *)szParm[3],"type \"weapon_mine\"") ? 0 : iCreateEntityIndex, iForward, iType); - } - iCreateEntityIndex=0; - } - } - RETURN_META(MRES_IGNORED); -} - -// We hook newly created entities here. -// This is where we check for client_built created entities. -edict_t* CreateNamedEntity(int className) -{ - if (iscombat) - RETURN_META_VALUE(MRES_IGNORED,0); - edict_t *pEntity; - // Incase another plugin supercedes/overrides, use their returned value here. - // (Untested). - if (gpMetaGlobals->status >= MRES_OVERRIDE) - { - pEntity=META_RESULT_OVERRIDE_RET(edict_t *); - iCreateEntityIndex=ENTINDEX(pEntity); - RETURN_META_VALUE(MRES_IGNORED, false); - } - else - { - pEntity=CREATE_NAMED_ENTITY(className); - if (!FNullEnt(pEntity)) - { - iCreateEntityIndex=ENTINDEX(pEntity); - RETURN_META_VALUE(MRES_SUPERCEDE,pEntity); - } - RETURN_META_VALUE(MRES_SUPERCEDE,pEntity); - } - RETURN_META_VALUE(MRES_IGNORED,false); -} - -// Map is changing/server is shutting down. -// We do all cleanup routines here, since, as noted in metamod's dllapi -// ServerDeactivate is the very last function called before the server loads up a new map. -void ServerDeactivate(void) -{ - for (int i=1;i<=gpGlobals->maxClients;i++) - { - CPlayer *player = GET_PLAYER_I(i); - if (player->connected) - player->Disconnect(); - } - ns_spawnpoints.clear(); - RETURN_META(MRES_IGNORED); -} - -// Reset player data here.. -qboolean ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ]) -{ - // Client's connecting. Freshen up his save data, and mark him as being connected. - CPlayer *player = GET_PLAYER_E(pEntity); - player->Connect(); - RETURN_META_VALUE(MRES_HANDLED,0); -} -void ClientDisconnect(edict_t *pEntity) -{ - // Client is disconnecting, clear all his saved information. - CPlayer *player = GET_PLAYER_E(pEntity); - player->Disconnect(); - RETURN_META(MRES_HANDLED); -} - -// NS resets pev->fov every single frame, but this is called right before the data is sent to the client. -// Reset FOV if we need to. -void UpdateClientData( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) -{ - edict_t *pEntity = (edict_t*)ent; - CPlayer *player = GET_PLAYER_E(pEntity); - if (player->foved) - pEntity->v.fov = player->fov; - - RETURN_META(MRES_HANDLED); - -} -int LogToIndex(char logline[128]) -{ - char *cname; - // Format of log line: - // name - // We need to find their ID from their name... - int x,y=0; - char cindex[64]; - // first we find the location of the start of the index - // Name can contain <>'s, so we go from the end up. - for (x=strlen(logline);x>=0;x--) - { - if (logline[x]=='<') - { - y++; - if (y==3) - { - y=x; - break; - } - } - } - // We found the end of the name, now copy the rest down. - y--; - x=0; - while (x<=y) - { - cindex[x]=logline[x]; - x++; - } - cindex[x]='\0'; - // Now we have their name, now cycle through all players to find which index it is - for (x=1;x<=gpGlobals->maxClients;x++) - { - cname=strdup(cindex); - if (!FNullEnt(INDEXENT2(x))) - { - if (FStrEq(cname,STRING(INDEXENT2(x)->v.netname))) - { - return x; - } - } - } - return 0; -} -int Find_Building_Hive(void) -{ - edict_t *pEntity=NULL; - while ((pEntity = UTIL_FindEntityByString(pEntity,"classname","team_hive"))) - { - if (pEntity->v.health > 0 && pEntity->v.solid > 0 && pEntity->v.fuser1 < 1000) - { - return ENTINDEX(pEntity); - } - } - return 0; -} - - - - -int AMX_MAKE_STRING(AMX *oPlugin, cell tParam, int &iLength) -{ - char *szNewValue = MF_GetAmxString(oPlugin, tParam, 0, &iLength); - return ALLOC_STRING(szNewValue); -} - -// Makes a char pointer out of an AMX cell. -char *AMX_GET_STRING(AMX *oPlugin, cell tParam, int &iLength) -{ - char *szNewValue = MF_GetAmxString(oPlugin, tParam, 0, &iLength); - return (char*)STRING(ALLOC_STRING(szNewValue)); -} -edict_t *UTIL_PlayerByIndexE( int playerIndex ) -{ - - if ( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ) - { - edict_t *pPlayerEdict = INDEXENT2( playerIndex ); - if ( pPlayerEdict && !pPlayerEdict->free ) - { - return pPlayerEdict; - } - } - - return NULL; -} -edict_t *UTIL_FindEntityByString(edict_t *pentStart, const char *szKeyword, const char *szValue) -{ - edict_t *pentEntity; - pentEntity=FIND_ENTITY_BY_STRING(pentStart, szKeyword, szValue); - if(!FNullEnt(pentEntity)) - return pentEntity; - return NULL; -} - -BOOL CheckForPublic(const char *publicname) -{ - AMX* amx; - char blah[64]; - strncpy(blah,publicname,63); - int iFunctionIndex; - int i=0; - // Loop through all running scripts - while((amx=MF_GetScriptAmx(i++))!=NULL) - { - // Scan for public - if (MF_AmxFindPublic(amx, blah, &iFunctionIndex) == AMX_ERR_NONE) - { - // Public was found. - return TRUE; - } - } - - return FALSE; // no public found in any loaded script -} diff --git a/dlls/ns/msvc8/ns.sln b/dlls/ns/msvc8/ns.sln index 6bb28b00..5e28a85b 100644 --- a/dlls/ns/msvc8/ns.sln +++ b/dlls/ns/msvc8/ns.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 +# Visual C++ Express 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ns", "ns.vcproj", "{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}" EndProject Global diff --git a/dlls/ns/msvc8/ns.vcproj b/dlls/ns/msvc8/ns.vcproj index 2a6728c9..a28c667e 100644 --- a/dlls/ns/msvc8/ns.vcproj +++ b/dlls/ns/msvc8/ns.vcproj @@ -49,7 +49,7 @@ Name="VCCLCompilerTool" Optimization="2" InlineFunctionExpansion="1" - AdditionalIncludeDirectories="..\;..\sdk" + 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" @@ -142,9 +142,8 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - diff --git a/dlls/ns/natives/general.cpp b/dlls/ns/natives/general.cpp new file mode 100644 index 00000000..20a2e873 --- /dev/null +++ b/dlls/ns/natives/general.cpp @@ -0,0 +1,553 @@ +/* AMX Mod X + * Natural Selection 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 + +#include "../sdk/amxxmodule.h" + +#include "cbase.h" // TakeDamage + +#include "../ns.h" + +#include "../utilfunctions.h" +#include "../NEW_Util.h" + +#include "../GameManager.h" +#include "../SpawnManager.h" +#include "../LocationManager.h" +#include "../TitleManager.h" + +#include "../CPlayer.h" + + +edict_t* avhgameplay=NULL; + +// drop-in replacement for user_kill +static cell AMX_NATIVE_CALL ns_user_kill(AMX *amx, cell *params) +{ + + CreatePlayerPointer(amx,params[1]); + + // 2 is commander, never slay commander + if (player->GetPev()->iuser3 == 2) + { + return 0; + } + + if (MF_IsPlayerIngame(params[1]) && MF_IsPlayerAlive(params[1])) + { + REAL bef = player->GetPev()->frags; + + edict_t *pEntity = CREATE_NAMED_ENTITY(MAKE_STRING("trigger_hurt")); + + if (pEntity) + { + KeyValueData kvd; + + kvd.szClassName="trigger_hurt"; + kvd.szKeyName="classname"; + kvd.szValue="trigger_hurt"; + kvd.fHandled=0; + MDLL_KeyValue(pEntity,&kvd); + + kvd.szClassName="trigger_hurt"; + kvd.szKeyName="dmg"; + kvd.szValue="50000.0"; + kvd.fHandled=0; + MDLL_KeyValue(pEntity,&kvd); + + kvd.szClassName="trigger_hurt"; + kvd.szKeyName="damagetype"; + kvd.szValue="1"; + kvd.fHandled=0; + MDLL_KeyValue(pEntity,&kvd); + + kvd.szClassName="trigger_hurt"; + kvd.szKeyName="origin"; + kvd.szValue="8192 8192 8192"; + kvd.fHandled=0; + MDLL_KeyValue(pEntity,&kvd); + + MDLL_Spawn(pEntity); + + pEntity->v.classname=MAKE_STRING("slay"); + + MDLL_Touch(pEntity,player->GetEdict()); + + REMOVE_ENTITY(pEntity); + } + + // If the optional parameter is 1, restore the frag count + if (params[2]) + { + player->GetPev()->frags = bef; + } + return 1; + } + + return 0; +} +// drop-in replacement for user_slap +#define ANGLEVECTORS (*g_engfuncs.pfnAngleVectors) +static cell AMX_NATIVE_CALL ns_user_slap(AMX *amx, cell *params) /* 2 param */ +{ + + CreatePlayerPointer(amx,params[1]); + + int power = abs((int)params[2]); + + // Check if commander, if player is comm then stop + if (player->GetPev()->iuser3 == 2) + { + return 0; + } + + if (MF_IsPlayerIngame(player->index()) && MF_IsPlayerAlive(player->index())) + { + if (player->GetPev()->health <= power) + { + float bef = player->GetPev()->frags; + /*MDLL_ClientKill(pPlayer->pEdict);*/ + edict_t *pEntity = CREATE_NAMED_ENTITY(MAKE_STRING("trigger_hurt")); + if (pEntity) + { + KeyValueData kvd; + + kvd.szClassName="trigger_hurt"; + kvd.szKeyName="classname"; + kvd.szValue="trigger_hurt"; + kvd.fHandled=0; + MDLL_KeyValue(pEntity,&kvd); + + kvd.szClassName="trigger_hurt"; + kvd.szKeyName="dmg"; + kvd.szValue="20000.0"; + kvd.fHandled=0; + MDLL_KeyValue(pEntity,&kvd); + + kvd.szClassName="trigger_hurt"; + kvd.szKeyName="damagetype"; + kvd.szValue="1"; + kvd.fHandled=0; + MDLL_KeyValue(pEntity,&kvd); + + kvd.szClassName="trigger_hurt"; + kvd.szKeyName="origin"; + kvd.szValue="8192 8192 8192"; + kvd.fHandled=0; + MDLL_KeyValue(pEntity,&kvd); + + MDLL_Spawn(pEntity); + + pEntity->v.classname=MAKE_STRING("slap"); + + MDLL_Touch(pEntity,player->GetEdict()); + + REMOVE_ENTITY(pEntity); + } + + player->GetPev()->frags = bef; + } + else + { + int numparam = *params/sizeof(cell); + if (numparam<3 || params[3]) + { + player->GetPev()->velocity.x += RANDOM_LONG(-600,600); + player->GetPev()->velocity.y += RANDOM_LONG(-180,180); + player->GetPev()->velocity.z += RANDOM_LONG(100,200); + } + else + { + vec3_t v_forward, v_right; + vec3_t vang = player->GetPev()->angles; + float fang[3]; + fang[0] = vang.x; + fang[1] = vang.y; + fang[2] = vang.z; + ANGLEVECTORS( fang, v_forward, v_right, NULL ); + player->GetPev()->velocity = player->GetPev()->velocity + v_forward * 220 + Vector(0,0,200); + } + player->GetPev()->punchangle.x = RANDOM_LONG(-10,10); + player->GetPev()->punchangle.y = RANDOM_LONG(-10,10); + + player->GetPev()->health -= power; + + int armor = (int)player->GetPev()->armorvalue; + armor -= power; + + if (armor < 0) + { + armor = 0; + } + + player->GetPev()->armorvalue = armor; + + player->GetPev()->dmg_inflictor = player->GetEdict(); + + static const char *bit_sound[3] = { + "weapons/cbar_hitbod1.wav", + "weapons/cbar_hitbod2.wav", + "weapons/cbar_hitbod3.wav" + }; + + EMIT_SOUND_DYN2(player->GetEdict(), CHAN_VOICE, bit_sound[RANDOM_LONG(0,2)], 1.0, ATTN_NORM, 0, PITCH_NORM); + } + return 1; + } + return 0; +} +// native ns_get_locationname(Float:x, Float:y, name[], len, lookup=0); +static cell AMX_NATIVE_CALL ns_get_locationname(AMX *amx, cell *params) +{ + vec3_t location; + + + location.x=amx_ctof2(params[1]); + location.y=amx_ctof2(params[2]); + + if ((params[0] / sizeof(cell)) >= 5) + { + return MF_SetAmxString(amx,params[3],LocationMan.Lookup(location,params[5]),params[4]); + } + else + { + return MF_SetAmxString(amx,params[3],LocationMan.Lookup(location,0),params[4]); + } +} +// ns_lookup_title(const Key[], Output[], Size) +static cell AMX_NATIVE_CALL ns_lookup_title(AMX *amx, cell *params) +{ + // FIX: some keys have upper case characters; to fix i store all keys as lower case + String Input(MF_GetAmxString(amx,params[1],0,NULL)); + + Input.toLower(); + + const char *Output=TitleMan.Lookup(Input); + + if (Output==NULL) // not found + { + return -1; + } + + return MF_SetAmxString(amx,params[2],Output,params[3]); +}; +// ns_round_in_progress() +static cell AMX_NATIVE_CALL ns_round_in_progress(AMX *amx, cell *params) +{ + return GameMan.RoundInProgress(); +} +// ns_get_spawn(team,number=0,Float:ret[3]) +static cell AMX_NATIVE_CALL ns_get_spawn(AMX *amx, cell *params) +{ + return SpawnMan.Lookup(amx,params); +} +// ns_get_mask(id,MASK_*) +static cell AMX_NATIVE_CALL ns_get_mask(AMX *amx, cell *params) +{ + CreateEdict(amx,params[1],-1); + + if (Entity->v.iuser4 & static_cast(params[2])) + { + return 1; + } + + return 0; +} +// ns_set_mask(id,MASK_*,1 or 0) +static cell AMX_NATIVE_CALL ns_set_mask(AMX *amx, cell *params) +{ + CreateEdict(amx,params[1],-1); + + if (static_cast(params[3]) > 0) + { + if (Entity->v.iuser4 & static_cast(params[2])) + { + return 0; + } + + Entity->v.iuser4 |= static_cast(params[2]); + + return 1; + } + + if (Entity->v.iuser4 & static_cast(params[2])) + { + Entity->v.iuser4 &= ~static_cast(params[2]); + + return 1; + } + + return 0; +} +// ns_popup(id (0 for all),"text",OnlyShowWithCLHelpOn=0) +static cell AMX_NATIVE_CALL ns_popup(AMX *amx, cell *params) +{ + GameMan.UpdateHudText2(); + + if (params[1]) + { + CreatePlayerPointer(amx, params[1]); + + if (!player->IsConnected()) + { + return 0; + } + + MESSAGE_BEGIN(MSG_ONE,GameMan.GetHudText2(),NULL,player->GetEdict()); + } + else + { + MESSAGE_BEGIN(MSG_ALL,GameMan.GetHudText2()); + } + + char msg[190]; + strncpy(&msg[0],MF_GetAmxString(amx,params[2],0,NULL),188); + + WRITE_STRING(msg); + WRITE_BYTE(params[3]); + + MESSAGE_END(); + + return 1; +} +// ns_is_combat() +static cell AMX_NATIVE_CALL ns_is_combat(AMX *amx, cell *params) +{ + return GameMan.IsCombat(); +} +/** + * Pretty much a direct port of CheezyPeteza's unstick routine + * from the old unstuck.amxx plugin. This is included here + * to remove the engine requirement. + * - + * Return values: + * 1 success + * 0 no spot to move to + * -1 invalid state (stunned/webbed) + * -2 invalid class (commander/gorge) + * -3 player is dead or a spectator + * -4 player is invalid (unknown) + * -5 player is invalid (disconnected) + */ + +inline int GetPlayerHullSize(CPlayer *Player, int PlayerClass) +{ + switch (PlayerClass) + { + case CLASS_SKULK: + case CLASS_GORGE: + case CLASS_LERK: + return static_cast(head_hull); + + case CLASS_FADE: + case CLASS_JETPACK: + case CLASS_HEAVY: + case CLASS_MARINE: + if (Player->GetPev()->button & IN_DUCK || Player->GetPev()->flags & FL_DUCKING) + { + return static_cast(head_hull); + } + + return static_cast(human_hull); + + case CLASS_ONOS: + if (Player->GetPev()->button & IN_DUCK || Player->GetPev()->flags & FL_DUCKING) + { + return static_cast(human_hull); + } + + return static_cast(large_hull); + + default: + return -1; + + } + return -1; +} +static cell AMX_NATIVE_CALL ns_unstick_player(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return -5; + } + + if (player->GetPev()->iuser4 & (MASK_ENSNARED | MASK_PLAYER_STUNNED)) + { + return -1; + } + + int PlayerClass=player->GetClass(); + if (PlayerClass == CLASS_GESTATE || PlayerClass == CLASS_COMMANDER) + { + return -2; + } + + if (PlayerClass == CLASS_DEAD || PlayerClass == CLASS_NOTEAM || PlayerClass == CLASS_UNKNOWN) + { + return -3; + } + + int HullSize=GetPlayerHullSize(player, PlayerClass); + + + if (HullSize==-1) + { + return -4; + } + + Vector OriginalOrigin=player->GetPev()->origin; + + Vector NewOrigin; + int Distance=params[2]; + int Attempts; + TraceResult Result; + + while (Distance < 1000) + { + Attempts=params[3]; + + while (Attempts--) + { + NewOrigin.x = RANDOM_FLOAT(OriginalOrigin.x - Distance,OriginalOrigin.x + Distance); + NewOrigin.y = RANDOM_FLOAT(OriginalOrigin.y - Distance,OriginalOrigin.y + Distance); + NewOrigin.z = RANDOM_FLOAT(OriginalOrigin.z - Distance,OriginalOrigin.z + Distance); + + // (const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr); + TRACE_HULL(NewOrigin, NewOrigin, 0, HullSize, player->GetEdict(), &Result); + + if (Result.fInOpen && !Result.fAllSolid && !Result.fStartSolid) + { + SET_ORIGIN(player->GetEdict(),NewOrigin); + return 1; + } + } + Distance += params[2]; + } + + + return 0; // Couldn't be found +} +// Type: 131072 = DoT +// ns_takedamage +static cell AMX_NATIVE_CALL ns_takedamage(AMX *amx, cell *params) +{ + // NASTY + // Reinterprets pvPrivateData as CBaseEntity, then calls TakeDamage with the entvar of Inflictor, and Attacker, with the float value and damage type + // The NS offset of TakeDamage hasn't changed from the HLSDK fortunately, so no offset digging is necessary + return (reinterpret_cast(INDEXENT_NEW(params[1])->pvPrivateData))->TakeDamage(&(INDEXENT_NEW(params[2])->v),&(INDEXENT_NEW(params[3])->v),amx_ctof2(params[4]),static_cast(params[5])); +} + +static cell AMX_NATIVE_CALL ns_get_gameplay(AMX* amx, cell* params) +{ + if (avhgameplay == NULL) + { + avhgameplay = FIND_ENTITY_BY_CLASSNAME(NULL, "avhgameplay"); + } + if (avhgameplay == NULL || + avhgameplay->pvPrivateData == NULL) // Still null? Get out of here + { + return NSGame_CantTell; + } + + int ATeam /* i pity da foo */ = *reinterpret_cast(reinterpret_cast(avhgameplay->pvPrivateData) + MAKE_OFFSET(GAMEPLAY_TEAMA)); + int BTeam = *reinterpret_cast(reinterpret_cast(avhgameplay->pvPrivateData) + MAKE_OFFSET(GAMEPLAY_TEAMB)); + + if (ATeam == 2 && // alien + BTeam == 2) // alien + { + return NSGame_AlienVAlien; + } + if (ATeam == 1 && // marine + BTeam == 1) // marine + { + return NSGame_MarineVMarine; + } + if (ATeam == 1 && // marine + BTeam == 2) // alien + { + return NSGame_MarineVAlien; + } + return NSGame_Unknown; + +} + +#ifdef DEVELOPER_BUILD +static cell AMX_NATIVE_CALL refmem(AMX *amx, cell *params) +{ + return *(reinterpret_cast(params[1])); +}; +static cell AMX_NATIVE_CALL setmem(AMX *amx, cell *params) +{ + int *ptr=reinterpret_cast(params[1]); + + *ptr=params[2]; + + return 1; +}; +#endif + +AMX_NATIVE_INFO general_natives[] = { + + { "user_kill", ns_user_kill }, // replacement natives + { "user_slap", ns_user_slap }, // since ClientKill is changed in NS + + { "ns_get_locationname", ns_get_locationname }, + { "ns_lookup_title", ns_lookup_title }, + { "ns_round_in_progress", ns_round_in_progress }, + { "ns_get_spawn", ns_get_spawn }, + { "ns_get_mask", ns_get_mask }, + { "ns_set_mask", ns_set_mask }, + { "ns_is_combat", ns_is_combat }, + { "ns_unstick_player", ns_unstick_player }, + + { "ns_popup", ns_popup }, + + { "ns_takedamage", ns_takedamage}, + + { "ns_get_gameplay", ns_get_gameplay }, + +#ifdef DEVELOPER_BUILD + { "refmem", refmem }, + { "setmem", setmem }, +#endif + + { NULL, NULL } + +}; +void AddNatives_General() +{ + MF_AddNatives(general_natives); +} diff --git a/dlls/ns/natives/memberfuncs.cpp b/dlls/ns/natives/memberfuncs.cpp new file mode 100644 index 00000000..caf0266b --- /dev/null +++ b/dlls/ns/natives/memberfuncs.cpp @@ -0,0 +1,275 @@ +#include + +#include "../sdk/amxxmodule.h" + +#include "../ns.h" +#include "../ns_const.h" + +#include "../utilfunctions.h" + +#include "../FastDelegate.h" +#include "../GameManager.h" + +extern int IsValidBuilding[AVH_USER3_MAX + 1]; + +using namespace fastdelegate::detail; + + +void *GameRules=NULL; + + +mBOOL dlclose_handle_invalid; // Linking errors with metamod + +// void AvHBaseBuildable::StartRecycle() +static void (GenericClass::*MFP_Recycle)(); + +// void AvHWeldable::AddBuildTime(float) +static void (GenericClass::*MFP_WeldFinished)(float); + +// AvHGameRules *GetGameRules(void) +static void *(*FP_GetGameRules)(); + + +char *FuncBase; + +/** + * sizeof(void (detail::GenericClass::*fptr)()) + * is 8 in GCC. Add an empty void * pointer at + * the end to compensate. + * Layout in GCC: + * union { + * void *address; // When this is an address it will always be positive + * int vtable_index; // When it is a vtable index it will always be odd = (vindex*2)+1 + * }; + * int delta; + * - + * Delta is the adjustment to the this pointer + * For my implementations I will only need it to 0 + */ +#ifdef __GNUC__ +template +inline void set_mfp(OutType &out, void *in) +{ + union + { + void *in[2]; + OutType out; + } mfpu; + + mfpu.in[0]=in; + mfpu.in[1]=NULL; + out=mfpu.out; +}; +#else +template +inline void set_mfp(OutType &out, void *in) +{ + out=horrible_cast(in); +}; +#endif + +void MFuncs_Initialize(void) +{ + char FileName[256]; + DLHANDLE DLLBase; +#ifdef __linux__ + snprintf(FileName,sizeof(FileName)-1,"%s/dlls/ns_i386.so",MF_GetModname()); +#else + snprintf(FileName,sizeof(FileName)-1,"%s\\dlls\\ns.dll",MF_GetModname()); +#endif + + DLLBase=DLOPEN(FileName); + FuncBase=(char *)DLSYM(DLLBase, MAKE_OFFSET(BASE)); + DLCLOSE(DLLBase); + +#define MFP(Offs) (((void *)(((char *)FuncBase)+MAKE_OFFSET(Offs)))) + + set_mfp(MFP_Recycle,MFP(MEMBER_RECYCLE)); + + set_mfp(MFP_WeldFinished,MFP(MEMBER_TRIGGER_WELDABLE)); + + // This is not a member function pointer, but use MFP since it + // uses the same address conversion as MFPs do + FP_GetGameRules=horrible_cast(MFP(GETGAMERULES)); +}; + +static cell AMX_NATIVE_CALL ns_recycle(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->free || Entity->pvPrivateData==NULL) + { + return 0; + } + + if (Entity->v.iuser3 <= AVH_USER3_NONE || Entity->v.iuser3 >= AVH_USER3_MAX) + { + return 0; + } + if (IsValidBuilding[Entity->v.iuser3]!=1) // Not a marine structure? + { + return 0; + } + + // Make sure it's a marine building, undefined stuff happens on alien structures + (reinterpret_cast(Entity->pvPrivateData)->*(MFP_Recycle))(); + + + return 1; +}; +static cell AMX_NATIVE_CALL ns_finish_weldable(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->free || Entity->pvPrivateData==NULL) + { + return 0; + } + // verify the classname since this will crash if it's the wrong class! + if (strcmp(STRING(Entity->v.classname),"avhweldable")!=0) + { + return 0; + } + + // First need to set the weldable to 100% complete + set_private_f(Entity,MAKE_OFFSET(WELD_DONE),get_private_f(Entity,MAKE_OFFSET(WELD_TIME))); + + // Now make NS think the weldable has been welded again + // This has to call AvHWeldable::AddBuildTime(float) + // because AvHWeldable::TriggerFinished() does not work properly + (reinterpret_cast(Entity->pvPrivateData)->*(MFP_WeldFinished))(100.0); + + + return 1; +}; + +static cell AMX_NATIVE_CALL ns_get_teamres(AMX *amx, cell *params) +{ + if (GameMan.IsCombat()) + { + return 0; + } + if (GameRules==NULL) // GameRules not initialized yet + { + GameRules=(*(FP_GetGameRules))(); + } + if (GameRules==NULL) // Still null? Get out of here + { + return 0; + } + switch(params[1]) + { + case 1: + { + return amx_ftoc2(*(REAL *)((char *)GameRules+GAMERULES_TEAMA_RESOURCES)); + } + case 2: + { + return amx_ftoc2(*(REAL *)((char *)GameRules+GAMERULES_TEAMB_RESOURCES)); + } + default: + { + MF_LogError(amx, AMX_ERR_NATIVE, "ns_get_teamres: Expected 1 for team a or 2 for team b, got %d", params[1]); + return 0; + } + } + return 0; +} +static cell AMX_NATIVE_CALL ns_set_teamres(AMX *amx, cell *params) +{ + if (GameMan.IsCombat()) + { + return 0; + } + if (GameRules==NULL) // GameRules not initialized yet + { + GameRules=(*(FP_GetGameRules))(); + } + if (GameRules==NULL) // Still null? Get out of here + { + return 0; + } + switch(params[1]) + { + case 1: + { + *(REAL *)((char *)GameRules+GAMERULES_TEAMA_RESOURCES)=amx_ctof2(params[2]); + return 1; + } + case 2: + { + *(REAL *)((char *)GameRules+GAMERULES_TEAMB_RESOURCES)=amx_ctof2(params[2]); + return 1; + } + default: + { + MF_LogError(amx, AMX_ERR_NATIVE, "ns_set_teamres: Expected 1 for team a or 2 for team b, got %d", params[1]); + return 0; + } + } + return 0; +} +static cell AMX_NATIVE_CALL ns_add_teamres(AMX *amx, cell *params) +{ + if (GameMan.IsCombat()) + { + return 0; + } + if (GameRules==NULL) // GameRules not initialized yet + { + GameRules=(*(FP_GetGameRules))(); + } + if (GameRules==NULL) // Still null? Get out of here + { + return 0; + } + switch(params[1]) + { + case 1: + { + return amx_ftoc2(*(REAL *)((char *)GameRules+GAMERULES_TEAMA_RESOURCES)+=amx_ctof2(params[2])); + } + case 2: + { + return amx_ftoc2(*(REAL *)((char *)GameRules+GAMERULES_TEAMB_RESOURCES)+=amx_ctof2(params[2])); + } + default: + { + MF_LogError(amx, AMX_ERR_NATIVE, "ns_add_teamres: Expected 1 for team a or 2 for team b, got %d", params[1]); + return 0; + } + } + return 0; +} + +#ifdef DEVELOPER_BUILD +static cell AMX_NATIVE_CALL findgameinfo(AMX *amx, cell *params) +{ + void *Ret=(*(FP_GetGameRules))(); + union + { + void *v; + int i; + }vi; + vi.v=Ret; + + printf("GameRules=%d\n",vi.i); + return 1; +}; +#endif +AMX_NATIVE_INFO memberfunc_natives[] = { +#ifdef DEVELOPER_BUILD + { "getgameinfo", findgameinfo }, +#endif + { "ns_recycle", ns_recycle }, + { "ns_finish_weldable", ns_finish_weldable }, + { "ns_get_teamres", ns_get_teamres }, + { "ns_set_teamres", ns_set_teamres }, + { "ns_add_teamres", ns_add_teamres }, + { NULL, NULL } +}; + +void AddNatives_MemberFunc() +{ + MF_AddNatives(memberfunc_natives); +}; diff --git a/dlls/ns/natives/particles.cpp b/dlls/ns/natives/particles.cpp new file mode 100644 index 00000000..99c1c9d2 --- /dev/null +++ b/dlls/ns/natives/particles.cpp @@ -0,0 +1,276 @@ +/* AMX Mod X + * Natural Selection 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 "../sdk/amxxmodule.h" + +#include "../ns.h" +#include "../utilfunctions.h" +#include "../NEW_Util.h" + +#include "../CVector.h" +#include "../CString.h" +#include "../ParticleManager.h" + +#define KVI(__KEY) PSKeyValueI(__KEY,amx,params) +#define KVF(__KEY) PSKeyValueF(__KEY,amx,params) +#define KVS(__KEY) PSKeyValueS(__KEY,amx,params) +#define NEXT params[__pcount++] + +typedef enum partsystype_e +{ + PSYS_TYPE_INT, + PSYS_TYPE_FLOAT, + PSYS_TYPE_STRING +}partsystype; +typedef struct partsyskey_s +{ + const char *Name; + partsystype type; +}partsyskey; + +cell PSKeyValueI(char *name, AMX *amx, cell *params) +{ + if (params[1]==0) + { + MF_LogError(amx,AMX_ERR_NATIVE,"Invalid particle system handle provided!"); + return 0; + } + KeyValueData kvd; + + char StrData[1024]; + + snprintf(StrData,sizeof(StrData)-1,"%d",params[2]); + + kvd.szClassName=const_cast(STRING(reinterpret_cast(params[1])->v.classname)); + kvd.szKeyName=name; + kvd.szValue=&StrData[0]; + kvd.fHandled=0; + //printf("\"%s\" \"%s\"\n",kvd.szKeyName,kvd.szValue); + + MDLL_KeyValue(reinterpret_cast(params[1]),&kvd); + + return 1; +} +cell PSKeyValueF(char *name, AMX *amx, cell *params) +{ + if (params[1]==0) + { + MF_LogError(amx,AMX_ERR_NATIVE,"Invalid particle system handle provided!"); + return 0; + } + KeyValueData kvd; + + char StrData[1024]; + + snprintf(StrData,sizeof(StrData)-1,"%f",amx_ctof2(params[2])); + + kvd.szClassName=const_cast(STRING(reinterpret_cast(params[1])->v.classname)); + kvd.szKeyName=name; + kvd.szValue=&StrData[0]; + kvd.fHandled=0; + + //printf("\"%s\" \"%s\"\n",kvd.szKeyName,kvd.szValue); + + MDLL_KeyValue(reinterpret_cast(params[1]),&kvd); + + return 1; + +} +cell PSKeyValueS(char *name, AMX *amx, cell *params) +{ + if (params[1]==0) + { + MF_LogError(amx,AMX_ERR_NATIVE,"Invalid particle system handle provided!"); + return 0; + } + KeyValueData kvd; + + kvd.szClassName=const_cast(STRING(reinterpret_cast(params[1])->v.classname)); + kvd.szKeyName=name; + kvd.szValue=MF_GetAmxString(amx,params[2],0,NULL); + kvd.fHandled=0; + //printf("\"%s\" \"%s\"\n",kvd.szKeyName,kvd.szValue); + + MDLL_KeyValue(reinterpret_cast(params[1]),&kvd); + + return 1; + +} +static cell AMX_NATIVE_CALL ns_set_ps_name(AMX *amx, cell *params) +{ + return KVS("targetname"); +} +static cell AMX_NATIVE_CALL ns_set_ps_sprite(AMX *amx, cell *params) +{ + return KVS("pSprite"); +} +static cell AMX_NATIVE_CALL ns_set_ps_genrate(AMX *amx, cell *params) +{ + return KVI("pGenRate"); +} +static cell AMX_NATIVE_CALL ns_set_ps_genshape(AMX *amx, cell *params) +{ + return KVI("pGenShape"); +} +static cell AMX_NATIVE_CALL ns_set_ps_genshape_params(AMX *amx, cell *params) +{ + return KVS("pGenShapeParams"); +} +static cell AMX_NATIVE_CALL ns_set_ps_spriteframes(AMX *amx, cell *params) +{ + return KVI("pSpriteNumFrames"); +} +static cell AMX_NATIVE_CALL ns_set_ps_numparticles(AMX *amx, cell *params) +{ + return KVI("pNumParticles"); +} +static cell AMX_NATIVE_CALL ns_set_ps_size(AMX *amx, cell *params) +{ + return KVF("pSize"); +} +static cell AMX_NATIVE_CALL ns_set_ps_vel_params(AMX *amx, cell *params) +{ + return KVS("pVelParams"); +} +static cell AMX_NATIVE_CALL ns_set_ps_vel_shape(AMX *amx, cell *params) +{ + return KVI("pVelShape"); +} +static cell AMX_NATIVE_CALL ns_set_ps_sys_life(AMX *amx, cell *params) +{ + return KVF("pSystemLifetime"); +} +static cell AMX_NATIVE_CALL ns_set_ps_particle_life(AMX *amx, cell *params) +{ + return KVF("pLifetime"); +} +static cell AMX_NATIVE_CALL ns_set_ps_rendermode(AMX *amx, cell *params) +{ + return KVI("pRenderMode"); +} +static cell AMX_NATIVE_CALL ns_set_ps_to_gen(AMX *amx, cell *params) +{ + return KVS("pPSToGen"); +} +static cell AMX_NATIVE_CALL ns_set_ps_anim_speed(AMX *amx, cell *params) +{ + return KVI("pAnimationSpeed"); +} +static cell AMX_NATIVE_CALL ns_set_ps_spawn_flags(AMX *amx, cell *params) +{ + return KVI("spawnflags"); +} +static cell AMX_NATIVE_CALL ns_set_ps_base_color(AMX *amx, cell *params) +{ + return KVS("pBaseColor"); +} +static cell AMX_NATIVE_CALL ns_set_ps_scale(AMX *amx, cell *params) +{ + return KVF("pScale"); +} +static cell AMX_NATIVE_CALL ns_set_ps_max_alpha(AMX *amx, cell *params) +{ + return KVF("pMaxAlpha"); +} +// ns_create_partsys(const name[], pGenShape, const pGenShapeParams[], pGenRate, const pSprite[], +// pSpriteFrames, pNumParticles, Float:pSize, const pVelParams[], pVelShape, +// Float:pSystemLifetime, Float:pParticleLifetime, pRenderMode, const pPSToGen[], pAnimationSpeed, pSpawnFlags) +static cell AMX_NATIVE_CALL ns_create_partsys(AMX *amx, cell *params) +{ + return (cell)CREATE_NAMED_ENTITY(MAKE_STRING("env_particles_custom")); +}; +static cell AMX_NATIVE_CALL ns_spawn_ps(AMX *amx, cell *params) +{ + if (params[1]==0) + { + MF_LogError(amx, AMX_ERR_NATIVE, "Invalid particle system handle"); + return 0; + } + + edict_t *Ent=reinterpret_cast(params[1]); + MDLL_Spawn(Ent); + + if (!Ent->free) + { + REMOVE_ENTITY(Ent); + } + return ParticleMan.Add(STRING(Ent->v.targetname),0); +} +// ns_fire_ps(Particle:id,Float:origin[3],Float:angles[3],flags=0) +static cell AMX_NATIVE_CALL ns_fire_partsys(AMX *amx, cell *params) +{ + float *origin=(float*)MF_GetAmxAddr(amx,params[2]); + float *angles=(float*)MF_GetAmxAddr(amx,params[3]); + + ParticleMan.FireSystem(static_cast(params[1]),origin,angles,static_cast(params[4])); + + return 0; +}; + +static cell AMX_NATIVE_CALL ns_get_partsys_id(AMX *amx, cell *params) +{ + return ParticleMan.Find(MF_GetAmxString(amx,params[1],0,NULL));; +}; + +AMX_NATIVE_INFO particle_natives[] = { + { "ns_create_ps", ns_create_partsys }, + { "ns_set_ps_name", ns_set_ps_name }, + { "ns_set_ps_sprite", ns_set_ps_sprite }, + { "ns_set_ps_genrate", ns_set_ps_genrate }, + { "ns_set_ps_genshape", ns_set_ps_genshape }, + { "ns_set_ps_genshape_params", ns_set_ps_genshape_params }, + { "ns_set_ps_spriteframes", ns_set_ps_spriteframes }, + { "ns_set_ps_numparticles", ns_set_ps_numparticles }, + { "ns_set_ps_size", ns_set_ps_size }, + { "ns_set_ps_vel_params", ns_set_ps_vel_params }, + { "ns_set_ps_vel_shape", ns_set_ps_vel_shape }, + { "ns_set_ps_sys_life", ns_set_ps_sys_life }, + { "ns_set_ps_particle_life", ns_set_ps_particle_life }, + { "ns_set_ps_rendermode", ns_set_ps_rendermode }, + { "ns_set_ps_to_gen", ns_set_ps_to_gen }, + { "ns_set_ps_anim_speed", ns_set_ps_anim_speed }, + { "ns_set_ps_spawn_flags", ns_set_ps_spawn_flags }, + { "ns_set_ps_base_color", ns_set_ps_base_color }, + { "ns_set_ps_scale", ns_set_ps_scale }, + { "ns_set_ps_max_alpha", ns_set_ps_max_alpha }, + { "ns_spawn_ps", ns_spawn_ps }, + + { "ns_fire_ps", ns_fire_partsys }, + { "ns_get_ps_id", ns_get_partsys_id }, + + { NULL, NULL } +}; +void AddNatives_Particles() +{ + MF_AddNatives(particle_natives); +} diff --git a/dlls/ns/natives/player.cpp b/dlls/ns/natives/player.cpp new file mode 100644 index 00000000..4a3ce587 --- /dev/null +++ b/dlls/ns/natives/player.cpp @@ -0,0 +1,222 @@ +/* AMX Mod X + * Natural Selection 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 "../sdk/amxxmodule.h" + +#include "../ns.h" + +#include "../utilfunctions.h" +#include "../NEW_Util.h" + +#include "../GameManager.h" +#include "../CPlayer.h" + +#include "../AllocString.h" + +StringManager AllocStringList; + +// ns_set_player_model(id,const Model[]="") +static cell AMX_NATIVE_CALL ns_set_player_model(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + player->SetModel(MF_GetAmxString(amx,params[2],0,NULL)); + + GameMan.HookPostThink_Post(); + + return 1; +} + +// ns_set_player_skin(id,skin=-1) +static cell AMX_NATIVE_CALL ns_set_player_skin(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + player->SetSkin(params[2]); + + GameMan.HookPostThink_Post(); + + return 1; +} +// ns_set_player_body(id,body=-1) +static cell AMX_NATIVE_CALL ns_set_player_body(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + player->SetBody(params[2]); + + GameMan.HookPostThink_Post(); + + return 1; +} +// ns_get_class(id) +static cell AMX_NATIVE_CALL ns_get_class(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + return player->GetClass(); +} +// ns_get_jpfuel(id) +static cell AMX_NATIVE_CALL ns_get_jpfuel(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + REAL ret=(player->GetPev()->fuser3) / 10.0; + + return amx_ftoc2(ret); +} +// ns_set_jpfuel(id,Float:fuelpercent) +static cell AMX_NATIVE_CALL ns_set_jpfuel(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + REAL fuel = amx_ctof2(params[2]); + if (fuel > 100.0) + { + fuel = 100.0; + } + if (fuel < 0.0) + { + fuel = 0.0; + } + + player->GetPev()->fuser3 = fuel * 10.0; + return 1; +} +static cell AMX_NATIVE_CALL ns_add_jpfuel(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + REAL fuel = clamp(amx_ctof2(params[2]),0.0,100.0); + + return amx_ftoc2(player->GetPev()->fuser3 = clamp(static_cast(player->GetPev()->fuser3 + (fuel * 10.0)),static_cast(0.0))); +}; +// ns_get_speedchange(index) +static cell AMX_NATIVE_CALL ns_get_speedchange(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + return player->GetSpeedChange(); +} + +// ns_set_speedchange(index,speedchange=0) +static cell AMX_NATIVE_CALL ns_set_speedchange(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + player->SetSpeedChange(params[2]); + + // Update PreThink_Post if we need to + GameMan.HookPreThink_Post(); + return 1; +} + +// ns_get_maxspeed(index) (returns the max speed of the player BEFORE speed change is factored in.) +static cell AMX_NATIVE_CALL ns_get_maxspeed(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + return player->GetMaxSpeed(); +} +// ns_set_fov(id,Float:fov); +static cell AMX_NATIVE_CALL ns_set_fov(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + return player->SetFOV(amx_ctof3(¶ms[2])); +} +// ns_giveiteM(id,"item"); +static cell AMX_NATIVE_CALL ns_giveitem(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + char *classname = MF_GetAmxString(amx,params[2],0,NULL); + + if (!player->IsConnected()) + { + return 0; + } + if (player->GetPev()->deadflag > 0) + { + return 0; + } + + edict_t *object=CREATE_NAMED_ENTITY(ALLOC_STRING2(classname)); + + if (!object) + { + MF_LogError(amx, AMX_ERR_NATIVE, "Error creating entity \"%s\"", classname); + return 0; + } + + SET_ORIGIN(object,player->GetPev()->origin); // move to player + gpGamedllFuncs->dllapi_table->pfnSpawn(object); // emulate spawn + object->v.flags |= FL_ONGROUND; // make it think it's touched the ground + gpGamedllFuncs->dllapi_table->pfnThink(object); // + gpGamedllFuncs->dllapi_table->pfnTouch(object,player->GetEdict()); // give it to the player + + return 1; +} + + +AMX_NATIVE_INFO player_natives[] = { + + { "ns_set_player_model", ns_set_player_model }, + { "ns_set_player_skin", ns_set_player_skin }, + { "ns_set_player_body", ns_set_player_body }, + + { "ns_get_class", ns_get_class }, + + { "ns_get_jpfuel", ns_get_jpfuel }, + { "ns_set_jpfuel", ns_set_jpfuel }, + { "ns_add_jpfuel", ns_add_jpfuel }, + + { "ns_get_energy", ns_get_jpfuel }, // They do the same thing... + { "ns_set_energy", ns_set_jpfuel }, // + { "ns_add_energy", ns_add_jpfuel }, + + { "ns_get_speedchange", ns_get_speedchange }, + { "ns_set_speedchange", ns_set_speedchange }, + { "ns_get_maxspeed", ns_get_maxspeed }, + + { "ns_set_fov", ns_set_fov }, + + { "ns_give_item", ns_giveitem }, + + + { NULL, NULL } +}; +void AddNatives_Player() +{ + MF_AddNatives(player_natives); +} diff --git a/dlls/ns/natives/player_memory.cpp b/dlls/ns/natives/player_memory.cpp new file mode 100644 index 00000000..dfd456dd --- /dev/null +++ b/dlls/ns/natives/player_memory.cpp @@ -0,0 +1,355 @@ +/* AMX Mod X + * Natural Selection 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 "../sdk/amxxmodule.h" + +#include "../ns.h" + +#include "../utilfunctions.h" +#include "../NEW_Util.h" + +#include "../GameManager.h" +#include "../CPlayer.h" + +// Float:ns_get_res(Player) +static cell AMX_NATIVE_CALL ns_get_res(AMX *amx, cell *params) +{ + if (GameMan.IsCombat()) + { + return 0; + } + + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + + if (!player->HasPrivateData()) + { + return 0; + } + + return amx_ftoc2(get_private_f(player->GetEdict(),MAKE_OFFSET(RESOURCES))); +} + +// ns_set_res(Player,Float:res) +static cell AMX_NATIVE_CALL ns_set_res(AMX *amx, cell *params) +{ + if (GameMan.IsCombat()) + { + return 0; + } + + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + + if (!player->HasPrivateData()) + { + return 0; + } + + set_private_f(player->GetEdict(),MAKE_OFFSET(RESOURCES),amx_ctof2(params[2])); + + return 1; +} +// Float:ns_add_res(Player,Float:res) +static cell AMX_NATIVE_CALL ns_add_res(AMX *amx, cell *params) +{ + if (GameMan.IsCombat()) + { + return 0; + } + + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + + if (!player->HasPrivateData()) + { + return 0; + } + + return amx_ftoc2(inc_private_f(player->GetEdict(),MAKE_OFFSET(RESOURCES),amx_ctof2(params[2]),0.0,100.0)); +} +// Float:ns_get_exp(Player) +static cell AMX_NATIVE_CALL ns_get_exp(AMX *amx, cell *params) +{ + if (!GameMan.IsCombat()) + { + return 0; + } + + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + if (!player->HasPrivateData()) + { + return 0; + } + + return amx_ftoc2(get_private_f(player->GetEdict(),MAKE_OFFSET(EXP))); +} + +// ns_set_exp(Player,Float:exp) +static cell AMX_NATIVE_CALL ns_set_exp(AMX *amx, cell *params) +{ + if (!GameMan.IsCombat()) + { + return 0; + } + + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + if (!player->HasPrivateData()) + { + return 0; + } + + set_private_f(player->GetEdict(),MAKE_OFFSET(EXP),amx_ctof2(params[2])); + + return 1; +} +// Float:ns_add_exp(Player,Float:exp) +static cell AMX_NATIVE_CALL ns_add_exp(AMX *amx, cell *params) +{ + if (!GameMan.IsCombat()) + { + return 0; + } + + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + if (!player->HasPrivateData()) + { + return 0; + } + + return amx_ftoc2(inc_private_f(player->GetEdict(),MAKE_OFFSET(EXP),amx_ctof2(params[2]),0.0)); +} + +// ns_get_points(Player) +static cell AMX_NATIVE_CALL ns_get_points(AMX *amx, cell *params) +{ + if (!GameMan.IsCombat()) + { + return 0; + } + + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + + if (!player->HasPrivateData()) + { + return 0; + } + + return get_private(player->GetEdict(),MAKE_OFFSET(POINTS)); +} + +// ns_set_points(Player,points) +static cell AMX_NATIVE_CALL ns_set_points(AMX *amx, cell *params) +{ + if (!GameMan.IsCombat()) + { + return 0; + } + + CreatePlayerPointer(amx, params[1]); + + if (!player->IsConnected()) + { + return 0; + } + if (!player->HasPrivateData()) + { + return 0; + } + + set_private(player->GetEdict(),MAKE_OFFSET(POINTS),static_cast(params[2])); + return 1; +} +// ns_add_points(Player,points) +static cell AMX_NATIVE_CALL ns_add_points(AMX *amx, cell *params) +{ + if (!GameMan.IsCombat()) + { + return 0; + } + + CreatePlayerPointer(amx, params[1]); + + if (!player->IsConnected()) + { + return 0; + } + if (!player->HasPrivateData()) + { + return 0; + } + + return inc_private(player->GetEdict(),MAKE_OFFSET(POINTS),static_cast(params[2]),0,9); +} +static cell AMX_NATIVE_CALL ns_get_score(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected() || !player->HasPrivateData()) + { + return 0; + } + return get_private(player->GetEdict(),MAKE_OFFSET(SCORE)); +} +static cell AMX_NATIVE_CALL ns_set_score(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected() || !player->HasPrivateData()) + { + return 0; + } + + set_private(player->GetEdict(),MAKE_OFFSET(SCORE),static_cast(params[2])); + return 1; +} +static cell AMX_NATIVE_CALL ns_add_score(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected() || !player->HasPrivateData()) + { + return 0; + } + + return inc_private(player->GetEdict(),MAKE_OFFSET(SCORE),static_cast(params[2])); +} +static cell AMX_NATIVE_CALL ns_get_deaths(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected() || !player->HasPrivateData()) + { + return 0; + } + return get_private(player->GetEdict(),MAKE_OFFSET(DEATHS)); +} +static cell AMX_NATIVE_CALL ns_set_deaths(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected() || !player->HasPrivateData()) + { + return 0; + } + + set_private(player->GetEdict(),MAKE_OFFSET(DEATHS),static_cast(params[2])); + return 1; +} +static cell AMX_NATIVE_CALL ns_add_deaths(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected() || !player->HasPrivateData()) + { + return 0; + } + + return inc_private(player->GetEdict(),MAKE_OFFSET(DEATHS),static_cast(params[2])); +} + +static cell AMX_NATIVE_CALL ns_get_hive_ability(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + int result = get_private(player->GetEdict(), MAKE_OFFSET(HIVEABILITY)); + + return (params[2] > 0) ? (result >= params[2] - 1) : result; +} + + + +AMX_NATIVE_INFO player_memory_natives[] = { + + { "ns_get_res", ns_get_res }, + { "ns_set_res", ns_set_res }, + { "ns_add_res", ns_add_res }, + + { "ns_get_exp", ns_get_exp }, + { "ns_set_exp", ns_set_exp }, + { "ns_add_exp", ns_add_exp }, + + { "ns_get_points", ns_get_points }, + { "ns_set_points", ns_set_points }, + { "ns_add_points", ns_add_points }, + + { "ns_set_score", ns_set_score }, + { "ns_get_score", ns_get_score }, + { "ns_add_score", ns_add_score }, + + { "ns_get_deaths", ns_get_deaths }, + { "ns_set_deaths", ns_set_deaths }, + { "ns_add_deaths", ns_add_deaths }, + + { "ns_get_hive_ability", ns_get_hive_ability}, + + + + { NULL, NULL } +}; +void AddNatives_PlayerMemory() +{ + MF_AddNatives(player_memory_natives); +} diff --git a/dlls/ns/natives/structure.cpp b/dlls/ns/natives/structure.cpp new file mode 100644 index 00000000..d4473e78 --- /dev/null +++ b/dlls/ns/natives/structure.cpp @@ -0,0 +1,405 @@ +/* AMX Mod X + * Natural Selection 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 "../sdk/amxxmodule.h" + +#include "../ns.h" + +#include "../utilfunctions.h" +#include "../NEW_Util.h" + +int IsValidBuilding[AVH_USER3_MAX + 1] = { + 0, // AVH_USER3_NONE = 0, + 0, // AVH_USER3_MARINE_PLAYER, + 0, // AVH_USER3_COMMANDER_PLAYER, + 0, // AVH_USER3_ALIEN_PLAYER1, + 0, // AVH_USER3_ALIEN_PLAYER2, + 0, // AVH_USER3_ALIEN_PLAYER3, + 0, // AVH_USER3_ALIEN_PLAYER4, + 0, // AVH_USER3_ALIEN_PLAYER5, + 0, // AVH_USER3_ALIEN_EMBRYO, + 0, // AVH_USER3_SPAWN_TEAMONE, + 0, // AVH_USER3_SPAWN_TEAMTWO, + 0, // AVH_USER3_PARTICLE_ON, // only valid for AvHParticleEntity: entindex as int in fuser1, template index stored in fuser2 + 0, // AVH_USER3_PARTICLE_OFF, // only valid for AvHParticleEntity: particle system handle in fuser1 + 0, // AVH_USER3_WELD, // float progress (0 - 100) stored in fuser1 + 0, // AVH_USER3_ALPHA, // fuser1 indicates how much alpha this entity toggles to in commander mode, fuser2 for players + 0, // AVH_USER3_MARINEITEM, // Something a friendly marine can pick up + 0, // AVH_USER3_WAYPOINT, + 2, // AVH_USER3_HIVE, + 0, // AVH_USER3_NOBUILD, + 0, // AVH_USER3_USEABLE, + 0, // AVH_USER3_AUDIO_ON, + 0, // AVH_USER3_AUDIO_OFF, + 0, // AVH_USER3_FUNC_RESOURCE, + 1, // AVH_USER3_COMMANDER_STATION, + 1, // AVH_USER3_TURRET_FACTORY, + 1, // AVH_USER3_ARMORY, + 1, // AVH_USER3_ADVANCED_ARMORY, + 1, // AVH_USER3_ARMSLAB, + 1, // AVH_USER3_PROTOTYPE_LAB, + 1, // AVH_USER3_OBSERVATORY, + 0, // AVH_USER3_CHEMLAB, + 0, // AVH_USER3_MEDLAB, + 0, // AVH_USER3_NUKEPLANT, + 1, // AVH_USER3_TURRET, + 1, // AVH_USER3_SIEGETURRET, + 1, // AVH_USER3_RESTOWER, + 0, // AVH_USER3_PLACEHOLDER, + 1, // AVH_USER3_INFANTRYPORTAL, + 0, // AVH_USER3_NUKE, + 0, // AVH_USER3_BREAKABLE, + 0, // AVH_USER3_UMBRA, + 1, // AVH_USER3_PHASEGATE, + 2, // AVH_USER3_DEFENSE_CHAMBER, + 2, // AVH_USER3_MOVEMENT_CHAMBER, + 2, // AVH_USER3_OFFENSE_CHAMBER, + 2, // AVH_USER3_SENSORY_CHAMBER, + 2, // AVH_USER3_ALIENRESTOWER, + 0, // AVH_USER3_HEAVY, + 0, // AVH_USER3_JETPACK, + 1, // AVH_USER3_ADVANCED_TURRET_FACTORY, + 0, // AVH_USER3_SPAWN_READYROOM, + 0, // AVH_USER3_CLIENT_COMMAND, + 0, // AVH_USER3_FUNC_ILLUSIONARY, + 0, // AVH_USER3_MENU_BUILD, + 0, // AVH_USER3_MENU_BUILD_ADVANCED, + 0, // AVH_USER3_MENU_ASSIST, + 0, // AVH_USER3_MENU_EQUIP, + 0, // AVH_USER3_MINE, + 0 // AVH_USER3_MAX + +}; + + +// ns_build_structure(idStructure); +static cell AMX_NATIVE_CALL ns_build_structure(AMX *amx, cell *params) +{ + // Trick NS into thinking that this structure is being spawned from the map + // set the "startbuilt" setting to 1, then remove it. + // "startbuilt" is set as "spawnflag" "1" in the ns.fgd + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->free) + { + return 0; + }; + + if (Entity->v.iuser3 <= AVH_USER3_NONE || Entity->v.iuser3 >= AVH_USER3_MAX) + { + return 0; + } + + + int StructureType=IsValidBuilding[Entity->v.iuser3]; + if (StructureType==0) + { + return 0; + } + + if (Entity->v.iuser3==AVH_USER3_HIVE) + { + return 0; + } + + // Already set? + if (Entity->v.spawnflags & 1) + { + MDLL_Spawn(Entity); + + goto undo_ghost; + } + + Entity->v.spawnflags |= 1; + + MDLL_Spawn(Entity); + + Entity->v.spawnflags &= ~1; + +undo_ghost: + if (StructureType==1) // marine, remove "ghost" appearance + { + if (get_private(Entity,MAKE_OFFSET(GHOST_STRUCTURE))!=0) + { + set_private(Entity,MAKE_OFFSET(GHOST_STRUCTURE),0); + + Entity->v.rendermode=kRenderNormal; + Entity->v.renderamt=100.0; + } + } + + return 1; +}; + +#define MASK_ELECTRICITY 8192 +static cell AMX_NATIVE_CALL ns_get_build(AMX *amx, cell *params) +{ + int iLength; + char *buildtype = MF_GetAmxString(amx,params[1],0,&iLength); + int iBuiltOnly = params[2]; + int iNumber = params[3]; + edict_t* pBuild = NULL; + int iCount=0; + + while ((pBuild = UTIL_FindEntityByString(pBuild,"classname",buildtype)) != NULL) + { + if (iBuiltOnly > 0) + { + if (FStrEq("team_advarmory",buildtype) || FStrEq("team_advturretfactory",buildtype)) + { + iCount++; + } + else + { + if (pBuild->v.fuser1 >= 1000 || pBuild->v.iuser4 & MASK_ELECTRICITY) + { + iCount++; + } + } + } + else + { + iCount++; + } + if (iNumber > 0 && iCount == iNumber) + return ENTINDEX_NEW(pBuild); + } + return iCount++; +} +static cell AMX_NATIVE_CALL ns_set_hive_trait(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + set_private(Entity,MAKE_OFFSET(HIVE_TRAIT),static_cast(params[2])); + return 1; +} +static cell AMX_NATIVE_CALL ns_get_hive_trait(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + return get_private(Entity,MAKE_OFFSET(HIVE_TRAIT)); +} + +static cell AMX_NATIVE_CALL ns_get_struct_owner(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + return get_private(Entity,MAKE_OFFSET(STRUCTOWNER)); +} +// ns_set_struct_owner(idStructure,idPlayer) - -1 means no owner +static cell AMX_NATIVE_CALL ns_set_struct_owner(AMX *amx, cell *params) +{ + + CreateNonPlayerEdict(amx,params[1]); + + if (params[2] > gpGlobals->maxClients || params[2] < -1) + { + return 0; + } + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + set_private(Entity,MAKE_OFFSET(STRUCTOWNER),params[2]); + return 1; +} +// Float:ns_get_obs_energy(id); +static cell AMX_NATIVE_CALL ns_get_obs_energy(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + return amx_ftoc2(get_private(Entity,MAKE_OFFSET(OBS_ENERGY))); +}; +// Float:ns_set_obs_energy(id,Float:energy); +static cell AMX_NATIVE_CALL ns_set_obs_energy(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + set_private_f(Entity,MAKE_OFFSET(OBS_ENERGY),amx_ctof2(params[2])); + return 1; +}; + +// Float:ns_add_obs_energy(id,Float:energy); +static cell AMX_NATIVE_CALL ns_add_obs_energy(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + return amx_ftoc2(inc_private_f(Entity,MAKE_OFFSET(OBS_ENERGY),amx_ctof2(params[2]),0.0,100.0)); +}; + +// Float:ns_get_weld_time(idWeldable); +static cell AMX_NATIVE_CALL ns_get_weld_time(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + return amx_ftoc2(get_private_f(Entity,MAKE_OFFSET(WELD_TIME))); +}; +// ns_set_weld_time(idWeldable,Float:value); +static cell AMX_NATIVE_CALL ns_set_weld_time(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + set_private_f(Entity,MAKE_OFFSET(WELD_TIME),amx_ctof2(params[2])); + + return 1; +}; +// Float:ns_add_weld_time(idWeldable,Float:value); +static cell AMX_NATIVE_CALL ns_add_weld_time(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + return amx_ftoc2(inc_private_f(Entity,MAKE_OFFSET(WELD_TIME),amx_ctof2(params[2]),0.0)); +}; +// Float:ns_get_weld_done(idWeldable); +static cell AMX_NATIVE_CALL ns_get_weld_done(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + return amx_ftoc2(get_private_f(Entity,MAKE_OFFSET(WELD_DONE))); +}; +// ns_set_weld_done(idWeldable,Float:value); +static cell AMX_NATIVE_CALL ns_set_weld_done(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + set_private_f(Entity,MAKE_OFFSET(WELD_DONE),amx_ctof2(params[2])); + + return 1; +}; +// Float:ns_add_weld_done(idWeldable,Float:value); +static cell AMX_NATIVE_CALL ns_add_weld_done(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL) + { + return 0; + } + + return amx_ftoc2(inc_private_f(Entity,MAKE_OFFSET(WELD_DONE),amx_ctof2(params[2]),0.0)); +}; + + +AMX_NATIVE_INFO structure_natives[] = { + { "ns_build_structure", ns_build_structure }, + + { "ns_get_build", ns_get_build }, + + { "ns_get_hive_trait", ns_get_hive_trait }, + { "ns_set_hive_trait", ns_set_hive_trait }, + + { "ns_get_struct_owner", ns_get_struct_owner }, + { "ns_set_struct_owner", ns_set_struct_owner }, + + { "ns_get_obs_energy", ns_get_obs_energy }, + { "ns_set_obs_energy", ns_set_obs_energy }, + { "ns_add_obs_energy", ns_add_obs_energy }, + + { "ns_get_weld_time", ns_get_weld_time }, + { "ns_set_weld_time", ns_set_weld_time }, + { "ns_add_weld_time", ns_add_weld_time }, + + { "ns_get_weld_done", ns_get_weld_done }, + { "ns_set_weld_done", ns_set_weld_done }, + { "ns_add_weld_done", ns_add_weld_done }, + + /* prototypes for natives i have planned */ + //{ "ns_get_phase_target", ns_get_phase_target }, + //{ "ns_set_phase_target", ns_set_phase_target }, + + //{ "ns_set_phase_nextuse", ns_set_phase_nextuse }, + //{ "ns_get_phase_nextuse", ns_get_phase_nextuse }, + //{ "ns_add_phase_nextuse", ns_add_phase_nextuse }, + + { NULL, NULL } +}; +void AddNatives_Structure() +{ + MF_AddNatives(structure_natives); +} diff --git a/dlls/ns/natives/weapons.cpp b/dlls/ns/natives/weapons.cpp new file mode 100644 index 00000000..3b2de17c --- /dev/null +++ b/dlls/ns/natives/weapons.cpp @@ -0,0 +1,479 @@ +/* AMX Mod X + * Natural Selection 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 "../sdk/amxxmodule.h" + +#include "../ns.h" + +#include "../utilfunctions.h" +#include "../NEW_Util.h" + +#include "../GameManager.h" +#include "../CPlayer.h" + +// ns_has_weapon(idPlayer,NsWeapon,set=0) +static cell AMX_NATIVE_CALL ns_has_weapon(AMX *amx,cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + + if (params[3] == -1) + { + if ((player->GetPev()->weapons & (1< 0) + { + return 1; + } + } + else + { + if ((player->GetPev()->weapons & (1< 0) + { + if (params[3] == 0) + { + player->GetPev()->weapons &= ~(1<GetPev()->weapons |= (1<pvPrivateData == NULL || Entity->free) + { + return 0; + } + + set_private_f(Entity,MAKE_OFFSET(WEAPDMG),amx_ctof2(params[2])); + + return 1; +} + +// Float:ns_get_weap_dmg(WeaponID) +static cell AMX_NATIVE_CALL ns_get_weapon_dmg(AMX *amx, cell *params) +{ + + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL || Entity->free) + { + return 0; + } + + REAL ret=get_private_f(Entity,MAKE_OFFSET(WEAPDMG)); + return amx_ftoc2(ret); +} + +// ns_set_weap_range(WeaponID,Float:range) +static cell AMX_NATIVE_CALL ns_set_weapon_range(AMX *amx, cell *params) +{ + + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL || Entity->free) + { + return 0; + } + + set_private_f(Entity,MAKE_OFFSET(WEAPRANGE),amx_ctof2(params[2])); + + return 1; +} +// Float:ns_get_weap_range(WeaponID) +static cell AMX_NATIVE_CALL ns_get_weapon_range(AMX *amx, cell *params) +{ + + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL || Entity->free) + { + return 0; + } + + REAL ret=get_private_f(Entity,MAKE_OFFSET(WEAPRANGE)); + return amx_ftoc2(ret); +} +// ns_get_weap_ammo(WeaponID) +static cell AMX_NATIVE_CALL ns_get_weapon_clip(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL || Entity->free) + { + return 0; + } + + return get_private(Entity,MAKE_OFFSET(WEAPCLIP)); +} +// ns_set_weap_ammo(WeaponID,ammo) +static cell AMX_NATIVE_CALL ns_set_weapon_clip(AMX *amx, cell *params) +{ + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL || Entity->free) + { + return 0; + } + + set_private(Entity,MAKE_OFFSET(WEAPCLIP),params[2]); + return 1; +} +static cell AMX_NATIVE_CALL ns_add_weapon_clip(AMX *amx, cell *params) +{ + + CreateNonPlayerEdict(amx,params[1]); + + if (Entity->pvPrivateData == NULL || Entity->free) + { + return 0; + } + + return inc_private(Entity,MAKE_OFFSET(WEAPCLIP),static_cast(params[2]),0); +} +// ns_get_weap_reserve(PlayerID,WeaponType) +static cell AMX_NATIVE_CALL ns_get_weap_reserve(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + + if (!player->HasPrivateData()) + { + return 0; + } + + switch (params[2]) + { + case WEAPON_PISTOL: + return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_PISTOL)); + case WEAPON_LMG: + return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_LMG)); + case WEAPON_SHOTGUN: + return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_SHOTGUN)); + case WEAPON_HMG: + return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_HMG)); + case WEAPON_GRENADE_GUN: + return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_GL)); + case WEAPON_GRENADE: + return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_HG)); + default: + return 0; + } + return 0; +} +static cell AMX_NATIVE_CALL ns_set_weap_reserve(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected() || !player->HasPrivateData()) + { + return 0; + } + + switch (params[2]) + { + case WEAPON_PISTOL: + set_private(player->GetEdict(),MAKE_OFFSET(AMMO_PISTOL),params[3]); + return 1; + case WEAPON_LMG: + set_private(player->GetEdict(),MAKE_OFFSET(AMMO_LMG),(int)params[3]); + return 1; + case WEAPON_SHOTGUN: + set_private(player->GetEdict(),MAKE_OFFSET(AMMO_SHOTGUN),(int)params[3]); + return 1; + case WEAPON_HMG: + set_private(player->GetEdict(),MAKE_OFFSET(AMMO_HMG),(int)params[3]); + return 1; + case WEAPON_GRENADE_GUN: + set_private(player->GetEdict(),MAKE_OFFSET(AMMO_GL),(int)params[3]); + return 1; + case WEAPON_GRENADE: + set_private(player->GetEdict(),MAKE_OFFSET(AMMO_HG),(int)params[3]); + return 1; + default: + return 0; + } + return 0; +} +static cell AMX_NATIVE_CALL ns_add_weap_reserve(AMX *amx, cell *params) +{ + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected() || !player->HasPrivateData()) + { + return 0; + } + + switch (params[2]) + { + case WEAPON_PISTOL: + return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_PISTOL),params[3],0); + case WEAPON_LMG: + return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_LMG),(int)params[3],0); + case WEAPON_SHOTGUN: + return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_SHOTGUN),(int)params[3],0); + case WEAPON_HMG: + return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_HMG),(int)params[3],0); + case WEAPON_GRENADE_GUN: + return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_GL),(int)params[3],0); + case WEAPON_GRENADE: + return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_HG),(int)params[3],0); + default: + return 0; + } + return 0; +} +// ns_get_weapon(idPlayer,weaponid,&weapontype=0) +static cell AMX_NATIVE_CALL ns_get_weapon(AMX *amx, cell *params) +{ + // Peachy did it like this: + // if weapontype is 0, return the primary weapon index of the player + // if weapontype is < 0, return the last inventory weapon index of the player + // otherwise, scan the player's inventory and look for a weapon of the given type + // such as WEAPON_KNIFE, etc, etc + // I added the last parameter, which will byref the weapontype of the weapon found + // returns 0 on failure + // last param default value added to not conflict with his version + + CreatePlayerPointer(amx,params[1]); + + if (!player->IsConnected()) + { + return 0; + } + + if (!player->HasPrivateData()) + { + return 0; + } + + if (params[2]<0) // find lastinv weapon + { + edict_t *Weapon=private_to_edict(get_private_p(player->GetEdict(),MAKE_OFFSET(LAST_WEAPON))); + + if (Weapon==NULL) // no weapon + { + return 0; + } + + if ((params[0] / sizeof(cell))>2) // If this plugin was compiled with peachy's .inc then don't byref + { + *MF_GetAmxAddr_NEW(amx,params[3])=get_private(Weapon,MAKE_OFFSET(WEAPID)); + } + + return ENTINDEX_NEW(Weapon); + + } + if (params[2]==0) // find current weapon + { + edict_t *Weapon=private_to_edict(get_private_p(player->GetEdict(),MAKE_OFFSET(CURRENT_WEAPON))); + + if (Weapon==NULL) // no weapon + { + return 0; + } + + if ((params[0] / sizeof(cell))>2) // If this plugin was compiled with peachy's .inc then don't byref + { + *MF_GetAmxAddr_NEW(amx,params[3])=get_private(Weapon,MAKE_OFFSET(WEAPID)); + } + + return ENTINDEX_NEW(Weapon); + } + + // Finding weapon by ID + + char **pPlayerItems = reinterpret_cast(static_cast(player->GetEdict()->pvPrivateData) + MAKE_OFFSET(PLAYER_ITEMS)); + char *pItem; + int weapon=params[2]; + + for (int i = 0; i < 6; i++) + { + pItem = pPlayerItems[i]; + while (pItem) + { + if (*(int *)(pItem + MAKE_OFFSET(WEAPID)) == weapon) + { + return ENTINDEX_NEW(private_to_edict(pItem)); + } + else + { + pItem = *(char **)(pItem + MAKE_OFFSET(WEAP_NEXT)); + } + } + } + return 0; +} +#ifdef DEVELOPER_BUILD +// ns_find_weapon_offset(idPlayer,"primweapon","lastinvweapon") +static cell AMX_NATIVE_CALL ns_find_weapon_offset(AMX *amx, cell *params) +{ + char *SPrimWeapon=MF_GetAmxString(amx,params[2],0,NULL); + char *SLastInv=MF_GetAmxString(amx,params[3],1,NULL); + edict_t *ePlayer=INDEXENT_NEW(params[1]); + + // Locate entities by name + edict_t *PrimWeapon=NULL; + edict_t *LastInv=NULL; + + edict_t *Temp=NULL; + + while ((Temp=UTIL_FindEntityByString(Temp,"classname",SPrimWeapon))!=NULL) + { + if (Temp->v.owner==ePlayer) + { + PrimWeapon=Temp; + break; + } + } + Temp=NULL; + while ((Temp=UTIL_FindEntityByString(Temp,"classname",SLastInv))!=NULL) + { + if (Temp->v.owner==ePlayer) + { + LastInv=Temp; + break; + } + } + + if (LastInv == NULL || PrimWeapon == NULL) + { + if (LastInv==NULL) + { + MF_Log("LastInv==NULL"); + } + if (PrimWeapon==NULL) + { + MF_Log("PrimWeapon=NULL"); + } + return 0; + } + + // now iterate through the client's private data until we find the pointer to PrimWeapon/LastInv's offset + unsigned int *Ptr=(unsigned int*)ePlayer->pvPrivateData; + + int FoundLastInv=0; + int FoundPrim=0; + size_t count=0; + unsigned int iPrim; + unsigned int iLast; + + // so nasty D: this is basically horrible_cast + union bleh + { + void *ptr; + unsigned int ival; + }blah; + + blah.ptr=PrimWeapon->pvPrivateData; + iPrim=blah.ival; + + blah.ptr=LastInv->pvPrivateData; + iLast=blah.ival; + + while (count<4000) + { + if (*Ptr==iLast) + { + MF_Log("Found LastInv: %d",count); + FoundLastInv=1; + } + if (*Ptr==iPrim) + { + MF_Log("Found Primary: %d",count); + FoundPrim=1; + } + + if (FoundLastInv && FoundPrim) + { + //break; + } + count+=4; + Ptr++; + } + return 1; +} +#endif + + +AMX_NATIVE_INFO weapon_natives[] = { + + { "ns_has_weapon", ns_has_weapon }, + + { "ns_set_weap_dmg", ns_set_weapon_dmg }, + { "ns_get_weap_dmg", ns_get_weapon_dmg }, + + { "ns_set_weap_range", ns_set_weapon_range }, + { "ns_get_weap_range", ns_get_weapon_range }, + + { "ns_set_weap_clip", ns_set_weapon_clip }, + { "ns_get_weap_clip", ns_get_weapon_clip }, + { "ns_add_weap_clip", ns_add_weapon_clip }, + + { "ns_set_weap_reserve", ns_set_weap_reserve }, + { "ns_get_weap_reserve", ns_get_weap_reserve }, + { "ns_add_weap_reserve", ns_add_weap_reserve }, + + { "ns_get_weapon", ns_get_weapon}, + +#ifdef DEVELOPER_BUILD + { "ns_find_weapon_offset", ns_find_weapon_offset}, +#endif + + { NULL, NULL } +}; +void AddNatives_Weapons() +{ + MF_AddNatives(weapon_natives); +} diff --git a/dlls/ns/ns.h b/dlls/ns/ns.h index 693c6d71..934f6288 100755 --- a/dlls/ns/ns.h +++ b/dlls/ns/ns.h @@ -1,14 +1,46 @@ +/* AMX Mod X + * Natural Selection 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. + */ + #ifndef NS_H #define NS_H - -#include -#include -#include "amxxmodule.h" #include "ns_const.h" -#include "CPlayer.h" -#include "CSpawn.h" -#include "utilfunctions.h" + +#if defined CRAZY_OPTS +#define EXTERN_VIS __attribute__((externally_visible)) +#else +#define EXTERN_VIS +#endif extern DLL_FUNCTIONS *g_pFunctionTable; extern DLL_FUNCTIONS *g_pFunctionTable_Post; @@ -18,28 +50,44 @@ extern NEW_DLL_FUNCTIONS *g_pNewFunctionsTable; extern NEW_DLL_FUNCTIONS *g_pNewFunctionsTable_Post; -extern CSpawn ns_spawnpoints; -extern BOOL iscombat; -extern CPlayer g_player[33]; +extern class CPlayer g_player[33]; extern edict_t *player_edicts[33]; // Stupid INDEXENT() bug. -extern int gmsgHudText2; -extern AMX_NATIVE_INFO ns_misc_natives[]; -extern AMX_NATIVE_INFO ns_pdata_natives[]; - -extern int SpawnForward; -extern int TeamForward; - -extern int ChangeclassForward; -extern int BuiltForward; +void PlayerPreThink(edict_t *pEntity); +void PlayerPreThink_Post(edict_t *pEntity); +void PlayerPostThink_Post(edict_t *pEntity); +void UpdateClientData( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); +void StartFrame(void); +edict_t* CreateNamedEntity_Post(int className); +void AlertMessage_Post(ALERT_TYPE atype, char *szFmt, ...); -//////////////////////////////// +typedef struct tagAMX_HEADER { + int32_t size PACKED; /* size of the "file" */ + uint16_t magic PACKED; /* signature */ + char file_version; /* file format version */ + char amx_version; /* required version of the AMX */ + int16_t flags PACKED; + int16_t defsize PACKED; /* size of a definition record */ + int32_t cod PACKED; /* initial value of COD - code block */ + int32_t dat PACKED; /* initial value of DAT - data block */ + int32_t hea PACKED; /* initial value of HEA - start of the heap */ + int32_t stp PACKED; /* initial value of STP - stack top */ + int32_t cip PACKED; /* initial value of CIP - the instruction pointer */ + int32_t publics PACKED; /* offset to the "public functions" table */ + int32_t natives PACKED; /* offset to the "native functions" table */ + int32_t libraries PACKED; /* offset to the table of libraries */ + int32_t pubvars PACKED; /* the "public variables" table */ + int32_t tags PACKED; /* the "public tagnames" table */ + int32_t nametable PACKED; /* name table */ +} PACKED AMX_HEADER; +// Don't enable this, it just adds some offset finding natives +#define DEVELOPER_BUILD #endif // NS_H diff --git a/dlls/ns/ns_const.h b/dlls/ns/ns_const.h index 1e7ed07d..90337c94 100755 --- a/dlls/ns/ns_const.h +++ b/dlls/ns/ns_const.h @@ -1,3 +1,36 @@ +/* AMX Mod X + * Natural Selection 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. + */ + #ifndef NS_CONST_H #define NS_CONST_H @@ -6,56 +39,156 @@ // Offsets (used in NPData.cpp) -#define OFFSET_WIN_RESOURCES 1816 //454 * 4 // est: 454 // CONFIRMED -#define OFFSET_LIN_RESOURCES 1836 //459 * 4 // no change +#define NEED_TO_FIND 0 -#define OFFSET_WIN_WEAPDMG 408 //100 * 4 // est: 102 // CONFIRMED -#define OFFSET_LIN_WEAPDMG 424 //106 * 4 // Changed + 8 Bytes -#define OFFSET_WIN_WEAPRANGE 404 //99 * 4 // est: 101 // CONFIRMED -#define OFFSET_LIN_WEAPRANGE 420 //105 * 4 // Changed + 8 Bytes +#define OFFSET_WIN_RESOURCES 1816 +#define OFFSET_LIN_RESOURCES 1836 -#define OFFSET_WIN_WEAPCLIP 364 //91 * 4 // est: 91 // CONFIRMED -#define OFFSET_LIN_WEAPCLIP 380 //95 * 4 // no change +#define OFFSET_WIN_WEAPDMG 408 +#define OFFSET_LIN_WEAPDMG 424 -#define OFFSET_WIN_HIVE_TRAIT 488 //121 * 4 // est: 122 // CONFIRMED -#define OFFSET_LIN_HIVE_TRAIT 504 //126 * 4 // Changed + 4 bytes +#define OFFSET_WIN_WEAPRANGE 404 +#define OFFSET_LIN_WEAPRANGE 420 -#define OFFSET_WIN_SCORE 6588 //1639 * 4 // est: 1647 // CONFIRMED -#define OFFSET_LIN_SCORE 6608 //1644 * 4 // Changed + 32 bytes +#define OFFSET_WIN_WEAPCLIP 364 +#define OFFSET_LIN_WEAPCLIP 380 -#define OFFSET_WIN_EXP 6512 //1620 * 4 // est: 1628 // CONFIRMED -#define OFFSET_LIN_EXP 6532 //1633 * 4 // Changed + 32 bytes +#define OFFSET_WIN_WEAPID 324 +#define OFFSET_LIN_WEAPID 340 -#define OFFSET_WIN_POINTS 6520 //1622 * 4 // est: 1630 // CONFIRMED -#define OFFSET_LIN_POINTS 6540 //1635 * 4 // Changed + 32 bytes +// Next weapon in the item linked list +#define OFFSET_WIN_WEAP_NEXT 320 +#define OFFSET_LIN_WEAP_NEXT 336 -#define OFFSET_WIN_AMMO_LMG 1116 //279 * 4 // est: 279 // CONFIRMED -#define OFFSET_LIN_AMMO_LMG 1136 //284 * 4 // no change +#define OFFSET_WIN_HIVE_TRAIT 488 +#define OFFSET_LIN_HIVE_TRAIT 504 -#define OFFSET_WIN_AMMO_PISTOL 1120 //280 * 4 // est: 280 // CONFIRMED -#define OFFSET_LIN_AMMO_PISTOL 1140 //285 * 4 // no change +#define OFFSET_WIN_SCORE 6588 +#define OFFSET_LIN_SCORE 6608 -#define OFFSET_WIN_AMMO_SHOTGUN 1124 //281 * 4 // est: 281 // CONFIRMED -#define OFFSET_LIN_AMMO_SHOTGUN 1144 //286 * 4 // no change +#define OFFSET_WIN_EXP 6512 +#define OFFSET_LIN_EXP 6532 -#define OFFSET_WIN_AMMO_HMG 1128 //282 * 4 // est: 282 // CONFIRMED -#define OFFSET_LIN_AMMO_HMG 1148 //287 * 4 // no change +#define OFFSET_WIN_POINTS 6520 +#define OFFSET_LIN_POINTS 6540 -#define OFFSET_WIN_AMMO_GL 1132 //283 * 4 // est: 283 // CONFIRMED -#define OFFSET_LIN_AMMO_GL 1152 //288 * 4 // no change +#define OFFSET_WIN_AMMO_LMG 1116 +#define OFFSET_LIN_AMMO_LMG 1136 -#define OFFSET_WIN_AMMO_HG 1136 //284 * 4 // est: 284 // CONFIRMED -#define OFFSET_LIN_AMMO_HG 1156 //289 * 4 // no change +#define OFFSET_WIN_AMMO_PISTOL 1120 +#define OFFSET_LIN_AMMO_PISTOL 1140 -#define OFFSET_WIN_DEATHS 1380 //345 * 4 // est: 345 // CONFIRMED -#define OFFSET_LIN_DEATHS 1400 //350 * 4 // no change +#define OFFSET_WIN_AMMO_SHOTGUN 1124 +#define OFFSET_LIN_AMMO_SHOTGUN 1144 -#define OFFSET_WIN_STRUCTOWNER 324 //81 * 4 // est: 81 // CONFIRMED -#define OFFSET_LIN_STRUCTOWNER 340 //85 * 4 // no change +#define OFFSET_WIN_AMMO_HMG 1128 +#define OFFSET_LIN_AMMO_HMG 1148 -#define OFFSET_WIN_HIVEABILITY 6248 //1555 * 4 // est: 1562 // CONFIRMED -#define OFFSET_LIN_HIVEABILITY 6268 //1567 * 4 // Changed + 28 bytes +#define OFFSET_WIN_AMMO_GL 1132 +#define OFFSET_LIN_AMMO_GL 1152 + +#define OFFSET_WIN_AMMO_HG 1136 +#define OFFSET_LIN_AMMO_HG 1156 + +#define OFFSET_WIN_DEATHS 1380 +#define OFFSET_LIN_DEATHS 1400 + +#define OFFSET_WIN_STRUCTOWNER 324 +#define OFFSET_LIN_STRUCTOWNER 340 + +#define OFFSET_WIN_HIVEABILITY 6248 +#define OFFSET_LIN_HIVEABILITY 6268 + +#define OFFSET_WIN_PLAYER_ITEMS 1068 +#define OFFSET_LIN_PLAYER_ITEMS 1088 + +#define OFFSET_WIN_NEXT_WEAPON 1280 +#define OFFSET_LIN_NEXT_WEAPON 1300 + +#define OFFSET_WIN_CURRENT_WEAPON 1092 +#define OFFSET_LIN_CURRENT_WEAPON 1112 // +4 is the client known weapon if it's ever needed + +#define OFFSET_WIN_LAST_WEAPON 1100 +#define OFFSET_LIN_LAST_WEAPON 1120 + + + +#define OFFSET_WIN_ENTVAR 4 +#define OFFSET_LIN_ENTVAR 4 // first entry in the virtual class (vtable is 0) + +#define OFFSET_WIN_OBS_ENERGY 476 +#define OFFSET_LIN_OBS_ENERGY 492 + +#define OFFSET_WIN_WELD_DONE 128 +#define OFFSET_LIN_WELD_DONE 144 + +#define OFFSET_WIN_WELD_TIME 132 +#define OFFSET_LIN_WELD_TIME 148 + +#define OFFSET_WIN_GHOST_STRUCTURE 472 +#define OFFSET_LIN_GHOST_STRUCTURE 488 + +// The teamnumber for the specified team +#define OFFSET_WIN_GAMEPLAY_TEAMA 0x54 +#define OFFSET_LIN_GAMEPLAY_TEAMA 0x64 + +#define OFFSET_WIN_GAMEPLAY_TEAMB 0x58 +#define OFFSET_LIN_GAMEPLAY_TEAMB 0x68 + + +// TODO: Symbols / signatures instead +// Not actually offsets, but easier to use MAKE_OFFSET stuff for this :o +// First functions listed in the disassembler +#define OFFSET_WIN_BASE "?SUB_CallUseToggle@CBaseEntity@@QAEXXZ" +#define OFFSET_LIN_BASE "_init" + +#define OFFSET_LIN_MEMBERFUNCSTART 0x000EDBE8 // The location of _init in the binary +#define OFFSET_WIN_MEMBERFUNCSTART 0x00001000 // The location of CBaseEntity::SUB_CallUseToggle + +// NOTE: These addresses are raw offsets, not including the +// base addresses! These are the exact offsets that +// the disassembler provides. +// MAKE_MEMBER_OFFSET will compensate for the base address + + +// Recycle: void AvHBaseBuildable::StartRecycle(void) +#define OFFSET_WIN_MEMBER_RECYCLE MAKE_MEMBER_OFFSET(0x00053950) +#define OFFSET_LIN_MEMBER_RECYCLE MAKE_MEMBER_OFFSET(0x00180800) + + +// Weldable: void AvHWeldable::AddWeldTime(float Time) +#define OFFSET_WIN_MEMBER_TRIGGER_WELDABLE MAKE_MEMBER_OFFSET(0x000A0E20) +#define OFFSET_LIN_MEMBER_TRIGGER_WELDABLE MAKE_MEMBER_OFFSET(0x00232840) + + + +// Game Rules: AvHGameRules *GetGameRules(void) +#define OFFSET_WIN_GETGAMERULES MAKE_MEMBER_OFFSET(0x00068000) +#define OFFSET_LIN_GETGAMERULES MAKE_MEMBER_OFFSET(0x0019F930) + +// Offset into the gamerules pointer to the TeamA / TeamB class +#define GAMERULES_TEAMA_OFFSET 0xCC +#define GAMERULES_TEAMB_OFFSET 0x2A8 + +#define AVHTEAM_RESOURCES_OFFSET 0x94 + +#define GAMERULES_TEAMA_RESOURCES GAMERULES_TEAMA_OFFSET + AVHTEAM_RESOURCES_OFFSET +#define GAMERULES_TEAMB_RESOURCES GAMERULES_TEAMB_OFFSET + AVHTEAM_RESOURCES_OFFSET + + +enum +{ + NSGame_CantTell, /**< It is too soon to tell (can't find avhgameplay + entity or it doesn't have private data) */ + + NSGame_MarineVAlien, /**< Marine vs Aliens (standard) gameplay */ + NSGame_MarineVMarine, /**< Marine vs Marine */ + NSGame_AlienVAlien, /**< Alien vs Alien */ + + NSGame_Unknown, /**< Can find the gameplay entity, but can't + determine gameplay type. */ +}; enum { @@ -63,51 +196,51 @@ enum MASK_SIGHTED = 1, MASK_DETECTED = 2, MASK_BUILDABLE = 4, - MASK_BASEBUILD0 = 8, // Base build slot #0 - MASK_WEAPONS1 = 8, // Marine weapons 1 - MASK_CARAPACE = 8, // Alien carapace - MASK_WEAPONS2 = 16, // Marines weapons 2 - MASK_REGENERATION = 16, // Alien regeneration - MASK_BASEBUILD1 = 16, // Base build slot #1 - MASK_WEAPONS3 = 32, // Marine weapons 3 - MASK_REDEMPTION = 32, // Alien redemption - MASK_BASEBUILD2 = 32, // Base build slot #2 - MASK_ARMOR1 = 64, // Marine armor 1 - MASK_CELERITY = 64, // Alien celerity - MASK_BASEBUILD3 = 64, // Base build slot #3 - MASK_ARMOR2 = 128, // Marine armor 2 - MASK_ADRENALINE = 128, // Alien adrenaline - MASK_BASEBUILD4 = 128, // Base build slot #4 - MASK_ARMOR3 = 256, // Marine armor 3 - MASK_SILENCE = 256, // Alien silence - MASK_BASEBUILD5 = 256, // Base build slot #5 - MASK_JETPACK = 512, // Marine jetpacks - MASK_CLOAKING = 512, // Alien cloaking - MASK_BASEBUILD6 = 512, // Base build slot #6 - MASK_FOCUS = 1024, // Alien focus - MASK_MOTION = 1024, // Marine motion tracking - MASK_BASEBUILD7 = 1024, // Base build slot #7 + MASK_BASEBUILD0 = 8, // Base build slot #0 + MASK_WEAPONS1 = 8, // Marine weapons 1 + MASK_CARAPACE = 8, // Alien carapace + MASK_WEAPONS2 = 16, // Marines weapons 2 + MASK_REGENERATION = 16, // Alien regeneration + MASK_BASEBUILD1 = 16, // Base build slot #1 + MASK_WEAPONS3 = 32, // Marine weapons 3 + MASK_REDEMPTION = 32, // Alien redemption + MASK_BASEBUILD2 = 32, // Base build slot #2 + MASK_ARMOR1 = 64, // Marine armor 1 + MASK_CELERITY = 64, // Alien celerity + MASK_BASEBUILD3 = 64, // Base build slot #3 + MASK_ARMOR2 = 128, // Marine armor 2 + MASK_ADRENALINE = 128, // Alien adrenaline + MASK_BASEBUILD4 = 128, // Base build slot #4 + MASK_ARMOR3 = 256, // Marine armor 3 + MASK_SILENCE = 256, // Alien silence + MASK_BASEBUILD5 = 256, // Base build slot #5 + MASK_JETPACK = 512, // Marine jetpacks + MASK_CLOAKING = 512, // Alien cloaking + MASK_BASEBUILD6 = 512, // Base build slot #6 + MASK_FOCUS = 1024, // Alien focus + MASK_MOTION = 1024, // Marine motion tracking + MASK_BASEBUILD7 = 1024, // Base build slot #7 MASK_SCENTOFFEAR = 2048, // Alien scent of fear - MASK_DEFENSE2 = 4096, // Defense level 2 - MASK_DEFENSE3 = 8192, // Defense level 3 + MASK_DEFENSE2 = 4096, // Defense level 2 + MASK_DEFENSE3 = 8192, // Defense level 3 MASK_ELECTRICITY = 8192, // Electricy - MASK_MOVEMENT2 = 16384, // Movement level 2, - MASK_MOVEMENT3 = 32768, // Movement level 3 + MASK_MOVEMENT2 = 16384, // Movement level 2, + MASK_MOVEMENT3 = 32768, // Movement level 3 MASK_HEAVYARMOR = 32768, // Marine heavy armor - MASK_SENSORY2 = 65536, // Sensory level 2 - MASK_SENSORY3 = 131072, // Sensory level 3 + MASK_SENSORY2 = 65536, // Sensory level 2 + MASK_SENSORY3 = 131072, // Sensory level 3 MASK_ALIEN_MOVEMENT = 262144, // Onos is charging MASK_WALLSTICKING = 524288, // Flag for wall-sticking MASK_PRIMALSCREAM = 1048576, // Alien is in range of active primal scream - MASK_UMBRA = 2097152, // In umbra + MASK_UMBRA = 2097152, // In umbra MASK_DIGESTING = 4194304, // When set on a visible player, player is digesting. When set on invisible player, player is being digested MASK_RECYCLING = 8388608, // Building is recycling MASK_TOPDOWN = 16777216, // Commander view MASK_PLAYER_STUNNED = 33554432, // Player has been stunned by stomp MASK_ENSNARED = 67108864, // Webbed - MASK_ALIEN_EMBRYO = 134217728, //268435456, // Gestating - MASK_SELECTABLE = 268435456, //536870912, // ??? - MASK_PARASITED = 536870912, //1073741824, // Parasite flag + MASK_ALIEN_EMBRYO = 134217728, //268435456, // Gestating + MASK_SELECTABLE = 268435456, //536870912, // ??? + MASK_PARASITED = 536870912, //1073741824, // Parasite flag MASK_SENSORY_NEARBY = 1073741824 //2147483648 // Sensory chamber in range }; diff --git a/dlls/ns/sdk/amxxmodule.cpp b/dlls/ns/sdk/amxxmodule.cpp index 3a6a2a00..ab2cbdb6 100755 --- a/dlls/ns/sdk/amxxmodule.cpp +++ b/dlls/ns/sdk/amxxmodule.cpp @@ -2284,7 +2284,7 @@ C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_ } #ifdef FN_META_QUERY - FN_META_QUERY(); + return FN_META_QUERY(); #endif // FN_META_QUERY return 1; @@ -2327,7 +2327,7 @@ C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) } #ifdef FN_META_DETACH - FN_META_DETACH(); + return FN_META_DETACH(); #endif // FN_META_DETACH return TRUE; } @@ -2374,7 +2374,7 @@ C_DLLEXPORT void __stdcall GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, gpGlobals = pGlobals; // NOTE! Have to call logging function _after_ copying into g_engfuncs, so // that g_engfuncs.pfnAlertMessage() can be resolved properly, heh. :) - // UTIL_LogPrintf("[%s] dev: called: GiveFnptrsToDll\n", Plugin_info.logtag); + UTIL_LogPrintf("[%s] dev: called: GiveFnptrsToDll\n", Plugin_info.logtag); // --> ** Function core #ifdef _MSC_VER diff --git a/dlls/ns/sdk/amxxmodule.h b/dlls/ns/sdk/amxxmodule.h index a99c1fca..964ad53b 100755 --- a/dlls/ns/sdk/amxxmodule.h +++ b/dlls/ns/sdk/amxxmodule.h @@ -1077,7 +1077,7 @@ void FN_AlertMessage(ALERT_TYPE atype, char *szFmt, ...); #endif // FN_AlertMessage #ifdef FN_EngineFprintf -void FN_EngineFprintf(void *pfile, char *szFmt, ...); +void FN_EngineFprintf(FILE *pfile, char *szFmt, ...); #endif // FN_EngineFprintf #ifdef FN_PvAllocEntPrivateData @@ -1141,11 +1141,11 @@ void FN_GetBonePosition(const edict_t *pEdict, int iBone, float *rgflOrigin, flo #endif // FN_GetBonePosition #ifdef FN_FunctionFromName -uint32 FN_FunctionFromName(const char *pName); +unsigned long FN_FunctionFromName(const char *pName); #endif // FN_FunctionFromName #ifdef FN_NameForFunction -const char *FN_NameForFunction(uint32); +const char *FN_NameForFunction(unsigned long function); #endif // FN_NameForFunction #ifdef FN_ClientPrintf @@ -1189,7 +1189,7 @@ CRC32_t FN_CRC32_Final(CRC32_t pulCRC); #endif // FN_CRC32_Final #ifdef FN_RandomLong -int32 FN_RandomLong(int32 lLow, int32 lHigh); +long FN_RandomLong(long lLow, long lHigh); #endif // FN_RandomLong #ifdef FN_RandomFloat @@ -1658,11 +1658,11 @@ void FN_AlertMessage_Post(ALERT_TYPE atype, char *szFmt, ...); #endif // FN_AlertMessage_Post #ifdef FN_EngineFprintf_Post -void FN_EngineFprintf_Post(void *pfile, char *szFmt, ...); +void FN_EngineFprintf_Post(FILE *pfile, char *szFmt, ...); #endif // FN_EngineFprintf_Post #ifdef FN_PvAllocEntPrivateData_Post -void *FN_PvAllocEntPrivateData_Post(edict_t *pEdict, int32 cb); +void *FN_PvAllocEntPrivateData_Post(edict_t *pEdict, long cb); #endif // FN_PvAllocEntPrivateData_Post #ifdef FN_PvEntPrivateData_Post @@ -1722,11 +1722,11 @@ void FN_GetBonePosition_Post(const edict_t *pEdict, int iBone, float *rgflOrigin #endif // FN_GetBonePosition_Post #ifdef FN_FunctionFromName_Post -uint32 FN_FunctionFromName_Post(const char *pName); +unsigned long FN_FunctionFromName_Post(const char *pName); #endif // FN_FunctionFromName_Post #ifdef FN_NameForFunction_Post -const char *FN_NameForFunction_Post(uint32); +const char *FN_NameForFunction_Post(unsigned long function); #endif // FN_NameForFunction_Post #ifdef FN_ClientPrintf_Post @@ -1770,7 +1770,7 @@ CRC32_t FN_CRC32_Final_Post(CRC32_t pulCRC); #endif // FN_CRC32_Final_Post #ifdef FN_RandomLong_Post -int32 FN_RandomLong_Post(int32 lLow, int32 lHigh); +long FN_RandomLong_Post(long lLow, long lHigh); #endif // FN_RandomLong_Post #ifdef FN_RandomFloat_Post diff --git a/dlls/ns/sdk/moduleconfig.h b/dlls/ns/sdk/moduleconfig.h index 1ade5e68..0d9b24aa 100755 --- a/dlls/ns/sdk/moduleconfig.h +++ b/dlls/ns/sdk/moduleconfig.h @@ -3,18 +3,16 @@ #ifndef __MODULECONFIG_H__ #define __MODULECONFIG_H__ -#include "svn_version.h" - // Module info #define MODULE_NAME "NS" -#define MODULE_VERSION SVN_VERSION -#define MODULE_AUTHOR "Steve Dudenhoeffer" +#define MODULE_VERSION "1.8" +#define MODULE_AUTHOR "AMX Mod X Dev Team" #define MODULE_URL "http://www.amxmodx.org/" #define MODULE_LOGTAG "NS" #define MODULE_LIBRARY "ns" #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 +// #define MODULE_RELOAD_ON_MAPCHANGE #ifdef __DATE__ #define MODULE_DATE __DATE__ @@ -90,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() */ @@ -107,7 +105,7 @@ // #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_ParmsNewLevel ParmsNewLevel /* pfnParmsNewLevel() */ @@ -122,7 +120,7 @@ // #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_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 */ @@ -157,10 +155,10 @@ // #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 +// #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 @@ -211,7 +209,7 @@ // #define FN_AngleVectors AngleVectors // #define FN_CreateEntity CreateEntity // #define FN_RemoveEntity RemoveEntity -#define FN_CreateNamedEntity CreateNamedEntity +// #define FN_CreateNamedEntity CreateNamedEntity // #define FN_MakeStatic MakeStatic // #define FN_EntIsOnFloor EntIsOnFloor // #define FN_DropToFloor DropToFloor @@ -395,7 +393,7 @@ // #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_AlertMessage_Post AlertMessage_Post // #define FN_EngineFprintf_Post EngineFprintf_Post // #define FN_PvAllocEntPrivateData_Post PvAllocEntPrivateData_Post // #define FN_PvEntPrivateData_Post PvEntPrivateData_Post @@ -456,7 +454,7 @@ // #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_PrecacheEvent_Post PrecacheEvent_Post // #define FN_PlaybackEvent_Post PlaybackEvent_Post // #define FN_SetFatPVS_Post SetFatPVS_Post // #define FN_SetFatPAS_Post SetFatPAS_Post diff --git a/dlls/ns/sh_list.h b/dlls/ns/sh_list.h new file mode 100644 index 00000000..93daad36 --- /dev/null +++ b/dlls/ns/sh_list.h @@ -0,0 +1,297 @@ +/* ======== SourceMM ======== +* Copyright (C) 2004-2005 Metamod:Source Development Team +* No warranties of any kind +* +* License: zlib/libpng +* +* Author(s): David "BAILOPAN" Anderson +* ============================ +*/ + +#ifndef _INCLUDE_SMM_LIST_H +#define _INCLUDE_SMM_LIST_H + +// MSVC8 fix for offsetof macro redefition warnings +#ifdef _MSC_VER + #if _MSC_VER >= 1400 + #undef offsetof + #endif +#endif + +#include +#include + +//namespace SourceHook +//{ + //This class is from CSDM for AMX Mod X + /* + A circular, doubly-linked list with one sentinel node + + Empty: + m_Head = sentinel + m_Head->next = m_Head; + m_Head->prev = m_Head; + One element: + m_Head = sentinel + m_Head->next = node1 + m_Head->prev = node1 + node1->next = m_Head + node1->prev = m_Head + Two elements: + m_Head = sentinel + m_Head->next = node1 + m_Head->prev = node2 + node1->next = node2 + node1->prev = m_Head + node2->next = m_Head + node2->prev = node1 + */ + template + class List + { + public: + class iterator; + friend class iterator; + class ListNode + { + public: + ListNode(const T & o) : obj(o) { }; + ListNode() { }; + T obj; + ListNode *next; + ListNode *prev; + }; + private: + // Initializes the sentinel node. + // BAIL used malloc instead of new in order to bypass the need for a constructor. + ListNode *_Initialize() + { + ListNode *n = (ListNode *)malloc(sizeof(ListNode)); + n->next = n; + n->prev = n; + return n; + } + public: + List() : m_Head(_Initialize()), m_Size(0) + { + } + List(const List &src) : m_Head(_Initialize()), m_Size(0) + { + iterator iter; + for (iter=src.begin(); iter!=src.end(); iter++) + push_back( (*iter) ); + } + ~List() + { + clear(); + + // Don't forget to free the sentinel + if (m_Head) + { + free(m_Head); + m_Head = NULL; + } + } + void push_back(const T &obj) + { + ListNode *node = new ListNode(obj); + + node->prev = m_Head->prev; + node->next = m_Head; + m_Head->prev->next = node; + m_Head->prev = node; + + m_Size++; + } + size_t size() + { + return m_Size; + } + + void clear() + { + ListNode *node = m_Head->next; + ListNode *temp; + m_Head->next = m_Head; + m_Head->prev = m_Head; + + // Iterate through the nodes until we find g_Head (the sentinel) again + while (node != m_Head) + { + temp = node->next; + delete node; + node = temp; + } + m_Size = 0; + } + bool empty() + { + return (m_Size == 0); + } + T & back() + { + return m_Head->prev->obj; + } + private: + ListNode *m_Head; + size_t m_Size; + public: + class iterator + { + friend class List; + public: + iterator() + { + m_This = NULL; + } + iterator(const List &src) + { + m_This = src.m_Head; + } + iterator(ListNode *n) : m_This(n) + { + } + iterator(const iterator &where) + { + m_This = where.m_This; + } + //pre decrement + iterator & operator--() + { + if (m_This) + m_This = m_This->prev; + return *this; + } + //post decrement + iterator operator--(int) + { + iterator old(*this); + if (m_This) + m_This = m_This->prev; + return old; + } + + //pre increment + iterator & operator++() + { + if (m_This) + m_This = m_This->next; + return *this; + } + //post increment + iterator operator++(int) + { + iterator old(*this); + if (m_This) + m_This = m_This->next; + return old; + } + + const T & operator * () const + { + return m_This->obj; + } + T & operator * () + { + return m_This->obj; + } + + T * operator -> () + { + return &(m_This->obj); + } + const T * operator -> () const + { + return &(m_This->obj); + } + + bool operator != (const iterator &where) const + { + return (m_This != where.m_This); + } + bool operator ==(const iterator &where) const + { + return (m_This == where.m_This); + } + private: + ListNode *m_This; + }; + public: + iterator begin() const + { + return iterator(m_Head->next); + } + iterator end() const + { + return iterator(m_Head); + } + iterator erase(iterator &where) + { + ListNode *pNode = where.m_This; + iterator iter(where); + iter++; + + + // Works for all cases: empty list, erasing first element, erasing tail, erasing in the middle... + pNode->prev->next = pNode->next; + pNode->next->prev = pNode->prev; + + delete pNode; + m_Size--; + + return iter; + } + + iterator insert(iterator where, const T &obj) + { + // Insert obj right before where + + ListNode *node = new ListNode(obj); + ListNode *pWhereNode = where.m_This; + + pWhereNode->prev->next = node; + node->prev = pWhereNode->prev; + pWhereNode->prev = node; + node->next = pWhereNode; + + m_Size++; + + return iterator(node); + } + + public: + void remove(const T & obj) + { + iterator b; + for (b=begin(); b!=end(); b++) + { + if ( (*b) == obj ) + { + erase( b ); + break; + } + } + } + template + iterator find(const U & equ) + { + iterator iter; + for (iter=begin(); iter!=end(); iter++) + { + if ( (*iter) == equ ) + return iter; + } + return end(); + } + List & operator =(const List &src) + { + clear(); + iterator iter; + for (iter=src.begin(); iter!=src.end(); iter++) + push_back( (*iter) ); + return *this; + } + }; +//}; //NAMESPACE + +#endif //_INCLUDE_CSDM_LIST_H diff --git a/dlls/ns/utilfunctions.h b/dlls/ns/utilfunctions.h index 51dcde56..55c25fc8 100755 --- a/dlls/ns/utilfunctions.h +++ b/dlls/ns/utilfunctions.h @@ -1,57 +1,99 @@ -//====================================================================== -// Forward declarations for functions that deal directly with the engine -//====================================================================== +/* AMX Mod X + * Natural Selection 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. + */ + #ifndef UTILFUNCTIONS_H #define UTILFUNCTIONS_H -#include "CPlayer.h" -extern CPlayer g_player[33]; - -#define GET_PLAYER_E(x) (&g_player[ENTINDEX(x)]); -#define GET_PLAYER_I(x) (&g_player[x]); - -/* -#define FLOAT_TO_CELL(x) *(cell*)&x -#define CELL_TO_FLOAT(x) *(float*)&x -*/ -#define FLOAT_TO_CELL amx_ftoc -#define CELL_TO_FLOAT amx_ctof +#include "NEW_Util.h" // include my experimental INDEXENT / ENTINDEX replacements -#define ABSOLUTE_VALUE_EASY(x) (((x) < 0) ? (-(x)) : (x)) //very useful for gpGlobals->time comparisons -#define GetEdictModel(edict) ( (g_engfuncs.pfnInfoKeyValue((*g_engfuncs.pfnGetInfoKeyBuffer)(edict), "model")) ) -//#define INFO_KEY_VALUE(entity,keyname) (*g_engfuncs.pfnGetInfoKeyBuffer)(entity),keyname) -#define GetKeyValue(edict,key) ( (g_engfuncs.pfnInfoKeyValue((*g_engfuncs.pfnGetInfoKeyBuffer)(edict), key)) ) -#define INFO_KEY_BUFFER (*g_engfuncs.pfnGetInfoKeyBuffer) -#define INFO_KEY_VALUE (*g_engfuncs.pfnInfoKeyValue) +#define GET_PLAYER_E(x) (&g_player[ENTINDEX_NEW(x)]) +#define GET_PLAYER_I(x) (&g_player[x]) -//just declare extra helper functions you need here -edict_t *UTIL_FindEntityByString(edict_t *pentStart, const char *szKeyword, const char *szValue); -edict_t *UTIL_PlayerByIndexE( int playerIndex ); -int LogToIndex(char logline[128]); -int Find_Building_Hive(void); +/** + * Like GET_PLAYER_I, but this handles the invalid player index + * as well as setting the CPlayer pointer. + * NOTE: This declares CPlayer *player for you + */ +#define CreatePlayerPointer(AMX__, INDEX__) \ + if (INDEX__ < 1 || INDEX__ > gpGlobals->maxClients) \ + { \ + return 0; \ + } \ + CPlayer *player = &g_player[INDEX__] + +/** + * Declares an edict (Entity) and verify it's not a player + */ +#define CreateNonPlayerEdict(AMX__, INDEX__) \ + if (INDEX__ <= gpGlobals->maxClients || INDEX__ > gpGlobals->maxEntities) \ + { \ + return 0; \ + } \ + edict_t *Entity=INDEXENT_NEW(INDEX__) + +/** + * Declares an edict (Entity) does not care if it is a player + */ +#define CreateEdict(AMX__, INDEX__, INVALIDRET__) \ + if (INDEX__ < 1 || INDEX__ > gpGlobals->maxEntities) \ + { \ + return INVALIDRET__; \ + } \ + edict_t *Entity=INDEXENT_NEW(INDEX__) + + +/** + * There is no need to use the AMXx provided calls as + * they do an api call to recast, seems like overkill + */ +//#define amx_ftoc2(x) *((cell *)&x) +//#define amx_ctof2(x) *((REAL *)&x) +#define amx_ftoc3(x) *((cell *)x) +#define amx_ctof3(x) *((REAL *)x) +inline cell amx_ftoc2(REAL x) +{ + return *((cell *)&x); +}; +inline REAL amx_ctof2(cell x) +{ + return *((REAL *)&x); +}; -void GiveItem(edict_t *pEntity,char *szname); -void HudMessage(int index, const hudtextparms_t &textparms, const char *pMessage); -void ClearHudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage); -void UTIL_EmptyMenu(edict_t *pEntity, int keys, int time); -void UTIL_FakeClientCmd(edict_t *pEntity, char *cmd); -inline edict_t* INDEXENT2( int iEdictNum ) -{ - if (iEdictNum >= 1 && iEdictNum <= gpGlobals->maxClients) - { - CPlayer *player = GET_PLAYER_I(iEdictNum); - return player->edict; - } - else - { - return (*g_engfuncs.pfnPEntityOfEntIndex)(iEdictNum); - } -} inline BOOL isValidEntity(int x) { if (x < 0) @@ -64,9 +106,151 @@ inline BOOL isValidEntity(int x) return FALSE; return TRUE; } -#define CHECK_ENTITY(x) if (x != 0 && (FNullEnt(INDEXENT2(x)) || x < 0 || x > gpGlobals->maxEntities)) return 0; +#define CHECK_ENTITY(x) if (x != 0 && (FNullEnt(INDEXENT_NEW(x)) || x < 0 || x > gpGlobals->maxEntities)) return 0; #define CHECK_PARAMS(x) if (*params/sizeof(cell) < x) return 0; +// Stuff in utils.cpp + +edict_t *UTIL_FindEntityByString(edict_t *Start, const char *Keyword, const char *Value); + +int UTIL_FindBuildingHive(void); + +BOOL UTIL_CheckForPublic(const char *publicname); +BOOL UTIL_CheckForNative(const char *NativeName); + +class CPlayer; + +CPlayer *UTIL_PlayerByCID(int CID); + +// Converts something such as RESOURCES into OFFSET_WIN_RESOURCES or OFFSET_LIN_RESOURCES +#ifdef __linux__ +#define MAKE_OFFSET(Offset) OFFSET_LIN_##Offset +#define MAKE_MEMBER_OFFSET(Offs) (Offs - OFFSET_LIN_MEMBERFUNCSTART) +#else +#define MAKE_OFFSET(Offset) OFFSET_WIN_##Offset +#define MAKE_MEMBER_OFFSET(Offs) (Offs - OFFSET_WIN_MEMBERFUNCSTART) +#endif // __linux__ + +template +inline Output get_private_p(edict_t *pEntity, int offset) +{ + return (Output)(*(void**)((char*)(pEntity->pvPrivateData)+offset)); +}; + +/** + * Converts the private data pointer into an edict by + * looking up the entvar pointer (first entry in cbaseentity) + * and then getting pContainingEntity from that + */ +inline edict_t *private_to_edict(void *PrivateData) +{ + if (PrivateData==NULL) + { + return NULL; + } + return (*((entvars_t **)((char *)PrivateData + MAKE_OFFSET(ENTVAR))))->pContainingEntity; +}; +inline int clamp(int value, int min, int max) +{ + if (value < min) + { + return min; + } + if (value > max) + { + return max; + } + + return value; +} +inline REAL clamp(REAL value, REAL min, REAL max) +{ + if (value < min) + { + return min; + } + if (value > max) + { + return max; + } + + return value; +} +inline int clamp(int value, int min) +{ + if (value < min) + { + return min; + } + + return value; +} + +inline REAL clamp(REAL value, REAL min) +{ + if (value < min) + { + return min; + } + + return value; +} + +inline int get_private(edict_t *pEntity, int offset) +{ + return *(int*)((char*)(pEntity->pvPrivateData)+offset); +} + +inline REAL get_private_f(edict_t *pEntity, int offset) +{ + return *(REAL*)((char*)(pEntity->pvPrivateData)+offset); +} + +inline void set_private(edict_t *pEntity, int offset, int value) +{ + *(int*)((char*)(pEntity->pvPrivateData)+offset) = value; +} +inline int inc_private(edict_t *pEntity, int offset, int value) +{ + return *(int*)((char*)(pEntity->pvPrivateData)+offset) = *(int*)((char*)(pEntity->pvPrivateData)+offset) + value; +} +inline int inc_private(edict_t *pEntity, int offset, int value, int min) +{ + return *(int*)((char*)(pEntity->pvPrivateData)+offset) = clamp(*(int*)((char*)(pEntity->pvPrivateData)+offset) + value, min); +} +inline int inc_private(edict_t *pEntity, int offset, int value, int min, int max) +{ + return *(int*)((char*)(pEntity->pvPrivateData)+offset) = clamp(*(int*)((char*)(pEntity->pvPrivateData)+offset) + value, min, max); +} + +inline void set_private_f(edict_t *pEntity, int offset, REAL value) +{ + *(REAL*)((char*)(pEntity->pvPrivateData)+offset) = value; +} +inline REAL inc_private_f(edict_t *pEntity, int offset, REAL value) +{ + return *(REAL*)((char*)(pEntity->pvPrivateData)+offset) = *(REAL*)((char*)(pEntity->pvPrivateData)+offset) + value; +} +inline REAL inc_private_f(edict_t *pEntity, int offset, REAL value, REAL min) +{ + return *(REAL*)((char*)(pEntity->pvPrivateData)+offset) = clamp(*(REAL*)((char*)(pEntity->pvPrivateData)+offset) + value, min); +} +inline REAL inc_private_f(edict_t *pEntity, int offset, REAL value, REAL min, REAL max) +{ + return *(REAL*)((char*)(pEntity->pvPrivateData)+offset) = clamp(*(REAL*)((char*)(pEntity->pvPrivateData)+offset) + value, min, max); +} + +inline unsigned char get_private_b(edict_t *pEntity, int offset) +{ + return *(((unsigned char*)pEntity->pvPrivateData)+offset); +}; +inline unsigned char set_private_b(edict_t *pEntity, int offset, unsigned char value) +{ + return *(((unsigned char*)pEntity->pvPrivateData)+offset)=value; +}; + + + #endif // UTILFUNCTIONS_H diff --git a/dlls/ns/utils.cpp b/dlls/ns/utils.cpp new file mode 100644 index 00000000..f75bf1e7 --- /dev/null +++ b/dlls/ns/utils.cpp @@ -0,0 +1,192 @@ +/* AMX Mod X + * Natural Selection 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 "sdk/amxxmodule.h" + + +#include "ns.h" +#include "utilfunctions.h" + +#include "CPlayer.h" + + +/** + * Scans through all hives and finds the one currently building + */ +int UTIL_FindBuildingHive(void) +{ + edict_t *Entity=NULL; + + while ((Entity = UTIL_FindEntityByString(Entity,"classname","team_hive"))) + { + // is alive active not fully built + if (Entity->v.health > 0 && Entity->v.solid > 0 && Entity->v.fuser1 < 1000) + { + return ENTINDEX_NEW(Entity); + } + } + return 0; +} + +edict_t *UTIL_FindEntityByString(edict_t *Start, const char *Keyword, const char *Value) +{ + edict_t *Entity; + + Entity=FIND_ENTITY_BY_STRING(Start, Keyword, Value); + + if(!FNullEnt(Entity)) + { + return Entity; + } + + return NULL; +} + +/** + * Returns TRUE if the provided native is used in a loaded plugin + * FALSE otherwise. + */ +BOOL UTIL_CheckForNative(const char *NativeName) +{ + AMX *amx; + char blah[64]; + int FunctionIndex; + int i=0; + + strncpy(blah,NativeName,63); + + // Loop through all running scripts + while((amx=MF_GetScriptAmx(i++))!=NULL) + { + // Scan for native + if (MF_AmxFindNative(amx, blah, &FunctionIndex) == AMX_ERR_NONE) + { + // Native was found. + return TRUE; + + } + } + + return FALSE; // no native found in any loaded script +} +/** + * Scans an amxx plugin for a public + * returns whether or not that public exists + */ +BOOL UTIL_CheckForPublic(const char *publicname) +{ + AMX *amx; + char blah[64]; + int FunctionIndex; + int i=0; + + strncpy(blah,publicname,63); + + // Loop through all running scripts + while((amx=MF_GetScriptAmx(i++))!=NULL) + { + // Scan for public + if (MF_AmxFindPublic(amx, blah, &FunctionIndex) == AMX_ERR_NONE) + { + // Public was found. + return TRUE; + + } + } + + return FALSE; // no public found in any loaded script +} + +CPlayer *UTIL_PlayerByCID(int CID) +{ + int i=0; + while (i++maxClients) + { + if (GETPLAYERUSERID(g_player[i].GetEdict())==CID) + { + return &g_player[i]; + } + } + + return NULL; +} + +/** + * Converts a log string (eg: "sawce<1>") + * into a player index + */ +int UTIL_LogToIndex(const char *LogLine) +{ + char NameBuffer[33] ; // Temporary buffer to store the CID String + char *StrLocation; // Location in the LogLine pointer + unsigned int Count=0; // Count for how many <'s we've passed + size_t Length; // Length of LogLine + + Length=strlen(LogLine); + StrLocation=const_cast(LogLine) + Length; // Should now point to the last > + + while (Length--) + { + if (*StrLocation--=='<') + { + if (++Count==3) // 3rd match is end of CID + { + break; + } + } + } + + if (Count!=3) // Invalid name somehow?? + { + return 0; + } + + if (Length > 32) // The name is too long somehow? stop here... + { + return 0; + } + strncpy(NameBuffer,LogLine,Length); + + Count=0; + + while ((int)Count++maxClients) + { + if (strcmp(NameBuffer,STRING(INDEXENT_NEW(Count)->v.netname))==0) + { + return Count; + } + } + + return 0; +} +