// vim: set ts=4 sw=4 tw=99 noet: // // AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). // Copyright (C) The AMX Mod X Development Team. // // This software is licensed under the GNU General Public License, version 3 or higher. // Additional exceptions apply. For full license details, see LICENSE.txt or visit: // https://alliedmods.net/amxmodx-license // // Natural Selection Module // /* 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: 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; }; }; #endif