From aaede2f612c7a82ce63d69d8a07a2a7ae28caa2b Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 12 Mar 2017 21:12:29 +0500 Subject: [PATCH] Merge original "Adrenalin Gamer" source code by @martinwebrant. --- cl_dll/StudioModelRenderer.cpp | 32 + cl_dll/aghl/AgUDPClient.h | 129 + cl_dll/aghl/AgVGUIPassword.cpp | 276 +++ cl_dll/aghl/AgVGUIPassword.h | 43 + cl_dll/aghl/AgVGuiMapBrowser.cpp | 606 +++++ cl_dll/aghl/AgVGuiMapBrowser.h | 70 + cl_dll/aghl/Agglobal.cpp | 524 ++++ cl_dll/aghl/agbase64.cpp | 151 ++ cl_dll/aghl/agbase64.h | 11 + cl_dll/aghl/agcrc32.cpp | 84 + cl_dll/aghl/agcrc32.h | 18 + cl_dll/aghl/agcrc32enforcer.cpp | 140 ++ cl_dll/aghl/agcrc32enforcer.h | 14 + cl_dll/aghl/agdownload.cpp | 98 + cl_dll/aghl/agdownload.h | 22 + cl_dll/aghl/agglobal.h | 55 + cl_dll/aghl/aghudcountdown.cpp | 137 + cl_dll/aghl/aghudcountdown.h | 23 + cl_dll/aghl/aghudctf.cpp | 159 ++ cl_dll/aghl/aghudctf.h | 35 + cl_dll/aghl/aghudcustomtimer.cpp | 67 + cl_dll/aghl/aghudcustomtimer.h | 23 + cl_dll/aghl/aghudglobal.cpp | 417 ++++ cl_dll/aghl/aghudglobal.h | 43 + cl_dll/aghl/aghudirc.cpp | 194 ++ cl_dll/aghl/aghudirc.h | 29 + cl_dll/aghl/aghudlocation.cpp | 409 +++ cl_dll/aghl/aghudlocation.h | 51 + cl_dll/aghl/aghudlongjump.cpp | 67 + cl_dll/aghl/aghudlongjump.h | 21 + cl_dll/aghl/aghudnextmap.cpp | 67 + cl_dll/aghl/aghudnextmap.h | 22 + cl_dll/aghl/aghudplayerid.cpp | 106 + cl_dll/aghl/aghudplayerid.h | 27 + cl_dll/aghl/aghudscoreboard.cpp | 254 ++ cl_dll/aghl/aghudscoreboard.h | 32 + cl_dll/aghl/aghudsettings.cpp | 159 ++ cl_dll/aghl/aghudsettings.h | 34 + cl_dll/aghl/aghudsplash.cpp | 79 + cl_dll/aghl/aghudsplash.h | 23 + cl_dll/aghl/aghudsuddendeath.cpp | 64 + cl_dll/aghl/aghudsuddendeath.h | 21 + cl_dll/aghl/aghudtimeout.cpp | 75 + cl_dll/aghl/aghudtimeout.h | 23 + cl_dll/aghl/aghudtimer.cpp | 154 ++ cl_dll/aghl/aghudtimer.h | 26 + cl_dll/aghl/aghudvote.cpp | 107 + cl_dll/aghl/aghudvote.h | 32 + cl_dll/aghl/agicq.cpp | 28 + cl_dll/aghl/agicq.h | 10 + cl_dll/aghl/agirc.cpp | 305 +++ cl_dll/aghl/agirc.h | 46 + cl_dll/aghl/aglocation.cpp | 35 + cl_dll/aghl/aglocation.h | 22 + cl_dll/aghl/agmapi.cpp | 39 + cl_dll/aghl/agmapi.h | 10 + cl_dll/aghl/agmatchreport.cpp | 84 + cl_dll/aghl/agmatchreport.h | 21 + cl_dll/aghl/agminidump.cpp | 151 ++ cl_dll/aghl/agmodel.cpp | 292 +++ cl_dll/aghl/agmodel.h | 46 + cl_dll/aghl/agmodelcheck.cpp | 128 + cl_dll/aghl/agmodelcheck.h | 37 + cl_dll/aghl/agpak.cpp | 135 + cl_dll/aghl/agpak.h | 15 + cl_dll/aghl/agvariablechecker.cpp | 329 +++ cl_dll/aghl/agvariablechecker.h | 72 + cl_dll/aghl/agversioninfo.cpp | 198 ++ cl_dll/aghl/agversioninfo.h | 169 ++ cl_dll/aghl/agvguiirc.cpp | 241 ++ cl_dll/aghl/agvguiirc.h | 38 + cl_dll/aghl/agvguiwinamp.cpp | 270 ++ cl_dll/aghl/agvguiwinamp.h | 23 + cl_dll/aghl/agwallhack.cpp | 732 ++++++ cl_dll/aghl/agwallhack.h | 67 + cl_dll/aghl/crossthreadsmessagingdevice.cpp | 106 + cl_dll/aghl/crossthreadsmessagingdevice.h | 36 + cl_dll/aghl/dbghelp.h | 2471 +++++++++++++++++++ cl_dll/aghl/irc.cpp | 603 +++++ cl_dll/aghl/irc.h | 257 ++ cl_dll/aghl/socket.cpp | 152 ++ cl_dll/aghl/socket.h | 64 + cl_dll/ammo.cpp | 30 + cl_dll/cdll_int.cpp | 40 +- cl_dll/cl_util.h | 50 +- cl_dll/death.cpp | 25 +- cl_dll/ev_hldm.cpp | 8 +- cl_dll/health.cpp | 6 +- cl_dll/hud.cpp | 51 +- cl_dll/hud.h | 41 +- cl_dll/hud_redraw.cpp | 26 + cl_dll/hud_spectator.cpp | 29 +- cl_dll/in_camera.cpp | 7 +- cl_dll/input.cpp | 38 +- cl_dll/inputw32.cpp | 45 +- cl_dll/saytext.cpp | 31 +- cl_dll/statusbar.cpp | 9 +- cl_dll/view.cpp | 2 +- dlls/aghl/agadmin.cpp | 21 + dlls/aghl/agadmin.h | 24 + dlls/aghl/agadmincache.cpp | 261 ++ dlls/aghl/agadmincache.h | 40 + dlls/aghl/agarena.cpp | 356 +++ dlls/aghl/agarena.h | 80 + dlls/aghl/agclient.cpp | 799 ++++++ dlls/aghl/agclient.h | 25 + dlls/aghl/agcommand.cpp | 553 +++++ dlls/aghl/agcommand.h | 50 + dlls/aghl/agctf.cpp | 1511 ++++++++++++ dlls/aghl/agctf.h | 133 + dlls/aghl/agdom.cpp | 640 +++++ dlls/aghl/agdom.h | 114 + dlls/aghl/aggame.cpp | 34 + dlls/aghl/aggame.h | 28 + dlls/aghl/aggamemode.cpp | 326 +++ dlls/aghl/aggamemode.h | 53 + dlls/aghl/aggamerules.cpp | 1256 ++++++++++ dlls/aghl/aggamerules.h | 111 + dlls/aghl/agglobal.cpp | 1096 ++++++++ dlls/aghl/agglobal.h | 223 ++ dlls/aghl/aginfointermission.cpp | 68 + dlls/aghl/aginfointermission.h | 50 + dlls/aghl/aglms.cpp | 297 +++ dlls/aghl/aglms.h | 39 + dlls/aghl/aglocation.cpp | 27 + dlls/aghl/aglocation.h | 24 + dlls/aghl/aglocationcache.cpp | 131 + dlls/aghl/aglocationcache.h | 29 + dlls/aghl/agmatch.cpp | 265 ++ dlls/aghl/agmatch.h | 31 + dlls/aghl/agmsgstat.cpp | 189 ++ dlls/aghl/agmsgstat.h | 80 + dlls/aghl/agrunt.cpp | 1186 +++++++++ dlls/aghl/agscore.cpp | 24 + dlls/aghl/agscore.h | 23 + dlls/aghl/agscorecache.cpp | 135 + dlls/aghl/agscorecache.h | 32 + dlls/aghl/agscorelog.cpp | 153 ++ dlls/aghl/agscorelog.h | 34 + dlls/aghl/agsettings.cpp | 753 ++++++ dlls/aghl/agsettings.h | 36 + dlls/aghl/agspectator.cpp | 547 ++++ dlls/aghl/agstats.cpp | 216 ++ dlls/aghl/agstats.h | 82 + dlls/aghl/agsuddendeath.cpp | 60 + dlls/aghl/agsuddendeath.h | 21 + dlls/aghl/agtimeout.cpp | 200 ++ dlls/aghl/agtimeout.h | 36 + dlls/aghl/agtimer.cpp | 100 + dlls/aghl/agtimer.h | 55 + dlls/aghl/agvote.cpp | 536 ++++ dlls/aghl/agvote.h | 41 + dlls/aghl/agwallhack.cpp | 47 + dlls/aghl/agwallhack.h | 27 + dlls/cbase.h | 12 + dlls/client.cpp | 185 +- dlls/combat.cpp | 8 + dlls/crossbow.cpp | 18 + dlls/crowbar.cpp | 18 + dlls/egon.cpp | 22 + dlls/enginecallback.h | 6 + dlls/explode.cpp | 15 +- dlls/explode.h | 5 +- dlls/func_tank.cpp | 12 +- dlls/game.cpp | 7 + dlls/gamerules.cpp | 48 +- dlls/gamerules.h | 125 +- dlls/gauss.cpp | 72 +- dlls/h_battery.cpp | 16 +- dlls/healthkit.cpp | 14 +- dlls/hornetgun.cpp | 28 + dlls/items.cpp | 3 + dlls/mp5.cpp | 26 +- dlls/multiplay_gamerules.cpp | 316 ++- dlls/nodes.cpp | 15 +- dlls/player.cpp | 977 +++++++- dlls/player.h | 335 ++- dlls/python.cpp | 8 +- dlls/rpg.cpp | 41 +- dlls/shotgun.cpp | 14 +- dlls/singleplay_gamerules.cpp | 5 +- dlls/squeakgrenade.cpp | 10 + dlls/teamplay_gamerules.cpp | 205 +- dlls/teamplay_gamerules.h | 13 +- dlls/triggers.cpp | 19 +- dlls/util.cpp | 19 + dlls/util.h | 14 + dlls/weapons.cpp | 39 +- dlls/weapons.h | 1 + pm_shared/pm_shared.c | 32 +- 190 files changed, 28501 insertions(+), 433 deletions(-) create mode 100644 cl_dll/aghl/AgUDPClient.h create mode 100644 cl_dll/aghl/AgVGUIPassword.cpp create mode 100644 cl_dll/aghl/AgVGUIPassword.h create mode 100644 cl_dll/aghl/AgVGuiMapBrowser.cpp create mode 100644 cl_dll/aghl/AgVGuiMapBrowser.h create mode 100644 cl_dll/aghl/Agglobal.cpp create mode 100644 cl_dll/aghl/agbase64.cpp create mode 100644 cl_dll/aghl/agbase64.h create mode 100644 cl_dll/aghl/agcrc32.cpp create mode 100644 cl_dll/aghl/agcrc32.h create mode 100644 cl_dll/aghl/agcrc32enforcer.cpp create mode 100644 cl_dll/aghl/agcrc32enforcer.h create mode 100644 cl_dll/aghl/agdownload.cpp create mode 100644 cl_dll/aghl/agdownload.h create mode 100644 cl_dll/aghl/agglobal.h create mode 100644 cl_dll/aghl/aghudcountdown.cpp create mode 100644 cl_dll/aghl/aghudcountdown.h create mode 100644 cl_dll/aghl/aghudctf.cpp create mode 100644 cl_dll/aghl/aghudctf.h create mode 100644 cl_dll/aghl/aghudcustomtimer.cpp create mode 100644 cl_dll/aghl/aghudcustomtimer.h create mode 100644 cl_dll/aghl/aghudglobal.cpp create mode 100644 cl_dll/aghl/aghudglobal.h create mode 100644 cl_dll/aghl/aghudirc.cpp create mode 100644 cl_dll/aghl/aghudirc.h create mode 100644 cl_dll/aghl/aghudlocation.cpp create mode 100644 cl_dll/aghl/aghudlocation.h create mode 100644 cl_dll/aghl/aghudlongjump.cpp create mode 100644 cl_dll/aghl/aghudlongjump.h create mode 100644 cl_dll/aghl/aghudnextmap.cpp create mode 100644 cl_dll/aghl/aghudnextmap.h create mode 100644 cl_dll/aghl/aghudplayerid.cpp create mode 100644 cl_dll/aghl/aghudplayerid.h create mode 100644 cl_dll/aghl/aghudscoreboard.cpp create mode 100644 cl_dll/aghl/aghudscoreboard.h create mode 100644 cl_dll/aghl/aghudsettings.cpp create mode 100644 cl_dll/aghl/aghudsettings.h create mode 100644 cl_dll/aghl/aghudsplash.cpp create mode 100644 cl_dll/aghl/aghudsplash.h create mode 100644 cl_dll/aghl/aghudsuddendeath.cpp create mode 100644 cl_dll/aghl/aghudsuddendeath.h create mode 100644 cl_dll/aghl/aghudtimeout.cpp create mode 100644 cl_dll/aghl/aghudtimeout.h create mode 100644 cl_dll/aghl/aghudtimer.cpp create mode 100644 cl_dll/aghl/aghudtimer.h create mode 100644 cl_dll/aghl/aghudvote.cpp create mode 100644 cl_dll/aghl/aghudvote.h create mode 100644 cl_dll/aghl/agicq.cpp create mode 100644 cl_dll/aghl/agicq.h create mode 100644 cl_dll/aghl/agirc.cpp create mode 100644 cl_dll/aghl/agirc.h create mode 100644 cl_dll/aghl/aglocation.cpp create mode 100644 cl_dll/aghl/aglocation.h create mode 100644 cl_dll/aghl/agmapi.cpp create mode 100644 cl_dll/aghl/agmapi.h create mode 100644 cl_dll/aghl/agmatchreport.cpp create mode 100644 cl_dll/aghl/agmatchreport.h create mode 100644 cl_dll/aghl/agminidump.cpp create mode 100644 cl_dll/aghl/agmodel.cpp create mode 100644 cl_dll/aghl/agmodel.h create mode 100644 cl_dll/aghl/agmodelcheck.cpp create mode 100644 cl_dll/aghl/agmodelcheck.h create mode 100644 cl_dll/aghl/agpak.cpp create mode 100644 cl_dll/aghl/agpak.h create mode 100644 cl_dll/aghl/agvariablechecker.cpp create mode 100644 cl_dll/aghl/agvariablechecker.h create mode 100644 cl_dll/aghl/agversioninfo.cpp create mode 100644 cl_dll/aghl/agversioninfo.h create mode 100644 cl_dll/aghl/agvguiirc.cpp create mode 100644 cl_dll/aghl/agvguiirc.h create mode 100644 cl_dll/aghl/agvguiwinamp.cpp create mode 100644 cl_dll/aghl/agvguiwinamp.h create mode 100644 cl_dll/aghl/agwallhack.cpp create mode 100644 cl_dll/aghl/agwallhack.h create mode 100644 cl_dll/aghl/crossthreadsmessagingdevice.cpp create mode 100644 cl_dll/aghl/crossthreadsmessagingdevice.h create mode 100644 cl_dll/aghl/dbghelp.h create mode 100644 cl_dll/aghl/irc.cpp create mode 100644 cl_dll/aghl/irc.h create mode 100644 cl_dll/aghl/socket.cpp create mode 100644 cl_dll/aghl/socket.h create mode 100644 dlls/aghl/agadmin.cpp create mode 100644 dlls/aghl/agadmin.h create mode 100644 dlls/aghl/agadmincache.cpp create mode 100644 dlls/aghl/agadmincache.h create mode 100644 dlls/aghl/agarena.cpp create mode 100644 dlls/aghl/agarena.h create mode 100644 dlls/aghl/agclient.cpp create mode 100644 dlls/aghl/agclient.h create mode 100644 dlls/aghl/agcommand.cpp create mode 100644 dlls/aghl/agcommand.h create mode 100644 dlls/aghl/agctf.cpp create mode 100644 dlls/aghl/agctf.h create mode 100644 dlls/aghl/agdom.cpp create mode 100644 dlls/aghl/agdom.h create mode 100644 dlls/aghl/aggame.cpp create mode 100644 dlls/aghl/aggame.h create mode 100644 dlls/aghl/aggamemode.cpp create mode 100644 dlls/aghl/aggamemode.h create mode 100644 dlls/aghl/aggamerules.cpp create mode 100644 dlls/aghl/aggamerules.h create mode 100644 dlls/aghl/agglobal.cpp create mode 100644 dlls/aghl/agglobal.h create mode 100644 dlls/aghl/aginfointermission.cpp create mode 100644 dlls/aghl/aginfointermission.h create mode 100644 dlls/aghl/aglms.cpp create mode 100644 dlls/aghl/aglms.h create mode 100644 dlls/aghl/aglocation.cpp create mode 100644 dlls/aghl/aglocation.h create mode 100644 dlls/aghl/aglocationcache.cpp create mode 100644 dlls/aghl/aglocationcache.h create mode 100644 dlls/aghl/agmatch.cpp create mode 100644 dlls/aghl/agmatch.h create mode 100644 dlls/aghl/agmsgstat.cpp create mode 100644 dlls/aghl/agmsgstat.h create mode 100644 dlls/aghl/agrunt.cpp create mode 100644 dlls/aghl/agscore.cpp create mode 100644 dlls/aghl/agscore.h create mode 100644 dlls/aghl/agscorecache.cpp create mode 100644 dlls/aghl/agscorecache.h create mode 100644 dlls/aghl/agscorelog.cpp create mode 100644 dlls/aghl/agscorelog.h create mode 100644 dlls/aghl/agsettings.cpp create mode 100644 dlls/aghl/agsettings.h create mode 100644 dlls/aghl/agspectator.cpp create mode 100644 dlls/aghl/agstats.cpp create mode 100644 dlls/aghl/agstats.h create mode 100644 dlls/aghl/agsuddendeath.cpp create mode 100644 dlls/aghl/agsuddendeath.h create mode 100644 dlls/aghl/agtimeout.cpp create mode 100644 dlls/aghl/agtimeout.h create mode 100644 dlls/aghl/agtimer.cpp create mode 100644 dlls/aghl/agtimer.h create mode 100644 dlls/aghl/agvote.cpp create mode 100644 dlls/aghl/agvote.h create mode 100644 dlls/aghl/agwallhack.cpp create mode 100644 dlls/aghl/agwallhack.h diff --git a/cl_dll/StudioModelRenderer.cpp b/cl_dll/StudioModelRenderer.cpp index b7c3c1c6..d679c46d 100644 --- a/cl_dll/StudioModelRenderer.cpp +++ b/cl_dll/StudioModelRenderer.cpp @@ -1587,11 +1587,19 @@ void CStudioModelRenderer::StudioRenderFinal_Software( void ) if( m_pCvarDrawEntities->value == 2 ) { +//++ BulliT +#ifdef _DEBUG IEngineStudio.StudioDrawBones(); +#endif +//-- Martin Webrant } else if( m_pCvarDrawEntities->value == 3 ) { +//++ BulliT +#ifdef _DEBUG IEngineStudio.StudioDrawHulls(); +#endif +//-- Martin Webrant } else { @@ -1604,14 +1612,22 @@ void CStudioModelRenderer::StudioRenderFinal_Software( void ) if( m_pCvarDrawEntities->value == 4 ) { +//++ BulliT +#ifdef _DEBUG gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); IEngineStudio.StudioDrawHulls(); gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); +#endif +//-- Martin Webrant } if( m_pCvarDrawEntities->value == 5 ) { +//++ BulliT +#ifdef _DEBUG IEngineStudio.StudioDrawAbsBBox(); +#endif +//-- Martin Webrant } IEngineStudio.RestoreRenderer(); @@ -1633,11 +1649,19 @@ void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) if( m_pCvarDrawEntities->value == 2 ) { +//++ BulliT +#ifdef _DEBUG IEngineStudio.StudioDrawBones(); +#endif +//-- Martin Webrant } else if( m_pCvarDrawEntities->value == 3 ) { +//++ BulliT +#ifdef _DEBUG IEngineStudio.StudioDrawHulls(); +#endif +//-- Martin Webrant } else { @@ -1659,14 +1683,22 @@ void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) if( m_pCvarDrawEntities->value == 4 ) { +//++ BulliT +#ifdef _DEBUG gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); IEngineStudio.StudioDrawHulls(); gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); +#endif +//-- Martin Webrant } if( m_pCvarDrawEntities->value == 5 ) { +//++ BulliT +#ifdef _DEBUG IEngineStudio.StudioDrawAbsBBox(); +#endif +//-- Martin Webrant } IEngineStudio.RestoreRenderer(); diff --git a/cl_dll/aghl/AgUDPClient.h b/cl_dll/aghl/AgUDPClient.h new file mode 100644 index 00000000..5b42f33c --- /dev/null +++ b/cl_dll/aghl/AgUDPClient.h @@ -0,0 +1,129 @@ +//A simple UDP client. + +#pragma comment(lib,"wsock32.lib") + +class AgUDPClient +{ +public: + static bool Init() + { + WSADATA wsaData; + if (WSAStartup(MAKEWORD(1,1), &wsaData)) + return false; + return true; + } + + static bool Cleanup() + { + if (WSACleanup()) + return false; + return true; + } + + AgUDPClient() + { + m_Socket = INVALID_SOCKET; + ZeroMemory(&m_ServerAddress,sizeof(m_ServerAddress)); + } + + bool Connect(const char* pszAddress, unsigned short usPort) + { + m_Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (m_Socket == INVALID_SOCKET) + return false; + + m_ServerAddress.sin_family = AF_INET; + m_ServerAddress.sin_port = htons(usPort); + m_ServerAddress.sin_addr.s_addr = inet_addr(pszAddress); + + if (m_ServerAddress.sin_addr.s_addr == INADDR_NONE) + { + //Resolve hostname. + struct hostent* host = gethostbyname(pszAddress); + if (host == NULL) + return false; //Could not resolve hostname + CopyMemory(&m_ServerAddress.sin_addr, + host->h_addr_list[0],host->h_length); + } + + if (connect(m_Socket,(struct sockaddr *)&m_ServerAddress, sizeof(m_ServerAddress)) == SOCKET_ERROR) + return false; + + return true; + } + + bool WaitForRecieve(UINT uiMilliSeconds = INFINITE) + { + fd_set ReadSet; + FD_ZERO(&ReadSet); + FD_SET(m_Socket, &ReadSet); + if (1 != select(0, &ReadSet, NULL, NULL, TimeVal(uiMilliSeconds))) + return false; + return true; + } + + bool WaitForSend(UINT uiMilliSeconds = INFINITE) + { + fd_set WriteSet; + FD_ZERO(&WriteSet); + FD_SET(m_Socket, &WriteSet); + if (1 != select(0, NULL, &WriteSet, NULL, TimeVal(uiMilliSeconds))) + return false; + return true; + } + + bool WaitForError(UINT uiMilliSeconds = INFINITE) + { + fd_set ErrorSet; + FD_ZERO(&ErrorSet); + FD_SET(m_Socket, &ErrorSet); + if (1 != select(0, NULL, NULL, &ErrorSet, TimeVal(uiMilliSeconds))) + return false; + return true; + } + + unsigned long Send(const char* pData, const unsigned long lSize) + { + return send(m_Socket, pData, lSize, 0); + } + + unsigned long Receive(char* pData, const unsigned long lSize) + { + return recv(m_Socket, pData, lSize, 0); + } + +protected: + class TimeVal + { + public: + TimeVal(UINT uiMilliSeconds) + { + m_bNull = false; + if (uiMilliSeconds == INFINITE) + m_bNull = true; + else if(uiMilliSeconds <= 0) + { + m_TimeVal.tv_sec = 0; + m_TimeVal.tv_usec = 0; + } + else + { + m_TimeVal.tv_sec = uiMilliSeconds / 1000; + m_TimeVal.tv_usec = (uiMilliSeconds % 1000) * 1000; + } + } + + operator timeval*() + { + if (m_bNull) + return NULL; + return &m_TimeVal; + } + protected: + bool m_bNull; + timeval m_TimeVal; + }; + + SOCKET m_Socket; + struct sockaddr_in m_ServerAddress; +}; diff --git a/cl_dll/aghl/AgVGUIPassword.cpp b/cl_dll/aghl/AgVGUIPassword.cpp new file mode 100644 index 00000000..82c009ec --- /dev/null +++ b/cl_dll/aghl/AgVGUIPassword.cpp @@ -0,0 +1,276 @@ +//++ BulliT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" +#include +#include + +#include "hud.h" +#include "cl_util.h" +#include +#include "vgui_TeamFortressViewport.h" +#include "AgVGuiPassword.h" + + +using namespace vgui; + +namespace +{ + class TextHandler : public ActionSignal + { + private: + + AgVGuiPassword* _AgVGuiPassword; + + public: + + TextHandler(AgVGuiPassword* AgVGuiPassword) + { + _AgVGuiPassword=AgVGuiPassword; + } + + public: + + virtual void actionPerformed(Panel* panel) + { + _AgVGuiPassword->doConnect(); + } + }; + + class ConnectHandler : public ActionSignal + { + private: + + AgVGuiPassword* _AgVGuiPassword; + + public: + + ConnectHandler(AgVGuiPassword* AgVGuiPassword) + { + _AgVGuiPassword=AgVGuiPassword; + } + + public: + + virtual void actionPerformed(Panel* panel) + { + _AgVGuiPassword->doConnect(); + } + }; + + + class TextInput : public vgui::TextEntry + { + public: + TextInput(const char* text,int x,int y,int wide,int tall) : TextEntry(text,x,y,wide,tall) + { + }; + + virtual void keyPressed(KeyCode code,Panel* panel) + { + if (gViewPort->m_pPassword->isVisible()) + TextEntry::keyPressed(code,panel); + }; + virtual void keyTyped(KeyCode code,Panel* panel) + { + if (gViewPort->m_pPassword->isVisible()) + TextEntry::keyTyped(code,panel); + }; + virtual void keyReleased(KeyCode code,Panel* panel) + { + if (gViewPort->m_pPassword->isVisible()) + TextEntry::keyReleased(code,panel); + }; + }; + +} + +#define VGUIPASSWORD_TITLE_X XRES(16) +#define VGUIPASSWORD_TITLE_Y YRES(16) +#define TEXT_SIZE_Y YRES(16) + +AgVGuiPassword::AgVGuiPassword(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0)) ); + + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); +// SchemeHandle_t hVGUIPasswordText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the title + m_pLabel = new Label( "", VGUIPASSWORD_TITLE_X, VGUIPASSWORD_TITLE_Y ); + m_pLabel->setParent( this ); + m_pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + m_pLabel->setFont( Scheme::sf_primary1 ); + + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + m_pLabel->setFgColor( r, g, b, a ); + m_pLabel->setFgColor( Scheme::sc_primary1 ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + m_pLabel->setBgColor( r, g, b, a ); + m_pLabel->setContentAlignment( vgui::Label::a_west ); + m_pLabel->setText("Enter Password"); + + int iXSize,iYSize; + getSize( iXSize,iYSize ); + + int iTemp = iYSize - YRES(24) - VGUIPASSWORD_TITLE_Y - BUTTON_SIZE_Y; //Hack to get it to work with Visual 7.0 beta 2 + m_pTextEntry = new TextInput("",XRES(16), iTemp, iXSize - 2*XRES(16), TEXT_SIZE_Y); + m_pTextEntry->setParent(this); + m_pTextEntry->addActionSignal(new TextHandler(this)); + + m_pConnect = new CommandButton("Connect",XRES(16), iYSize - YRES(16) - BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + m_pConnect->addActionSignal(new ConnectHandler(this)); + m_pConnect->setParent(this); + + ReadPasswords(); +} + + +void AgVGuiPassword::doConnect() +{ + char szPassword[256]; + szPassword[0] = '\0'; + m_pTextEntry->getText(0,szPassword,sizeof(szPassword)); + + AgAddressToPasswordMap::iterator itrPasswords = m_mapPasswords.find(m_sAddress.c_str()); + if (itrPasswords != m_mapPasswords.end()) + (*itrPasswords).second = szPassword; + else + m_mapPasswords.insert(AgAddressToPasswordMap::value_type(m_sAddress,szPassword)); + SavePasswords(); + + char szCMD[256]; + sprintf(szCMD,"password %s\n", szPassword); + ClientCmd(szCMD); + + sprintf(szCMD, "connect %s\n", m_sAddress.c_str() ); + ClientCmd(szCMD); + + gViewPort->HidePassword(); +} + +void AgVGuiPassword::paintBackground() +{ + // Transparent black background + drawSetColor( 0,0,0, 100 ); + drawFilledRect(0,0,_size[0],_size[1]); +} + +int AgVGuiPassword::KeyInput(int down, int keynum, const char *pszCurrentBinding) +{ + if (!down) + return 1; + + if (!isVisible()) + return 1; + + if (K_ESCAPE == keynum) + { + gViewPort->HidePassword(); + return 0; + } + + if (m_pTextEntry->hasFocus()) + return 0; + + return 1; +} + + +void AgVGuiPassword::Connect(const char* pszHostname, const char* pszAddress, bool bPassworded) +{ + m_sAddress = pszAddress; + + if (!bPassworded) + { + doConnect(); + return; + } + else + { + char szMessage[256]; + sprintf(szMessage,"Enter password for %s",pszHostname); + m_pLabel->setText(szMessage,strlen(szMessage)); + + AgString sPassword; + AgAddressToPasswordMap::iterator itrPasswords = m_mapPasswords.find(pszAddress); + if (itrPasswords != m_mapPasswords.end()) + sPassword = (*itrPasswords).second; + + m_pTextEntry->setText(sPassword.c_str(),sPassword.length()); + gViewPort->ShowPassword(); + } +} + +void AgVGuiPassword::ReadPasswords() +{ + char szData[4096]; + char szFile[MAX_PATH]; + sprintf(szFile,"%s/passwords.txt",AgGetDirectory()); + FILE* pFile = fopen(szFile,"r"); + if (!pFile) + return; + + int iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile); + fclose(pFile); + if (0 >= iRead) + return; + szData[iRead] = '\0'; + + char* pszPasswordString = strtok( szData, "\n"); + while (pszPasswordString != NULL) + { + char szAddress[64],szPassword[64]; + szAddress[0] = '\0'; + szPassword[0] = '\0'; + sscanf(pszPasswordString,"%s %s\n",szAddress,szPassword); + + AgString sAddress(szAddress); + AgString sPassword(szPassword); + AgTrim(sAddress); + AgTrim(sPassword); + m_mapPasswords.insert(AgAddressToPasswordMap::value_type(sAddress,sPassword)); + pszPasswordString = strtok( NULL, "\n"); + } +} + +void AgVGuiPassword::SavePasswords() +{ + char szFile[MAX_PATH]; + sprintf(szFile,"%s/passwords.txt",AgGetDirectory()); + FILE* pFile = fopen(szFile,"wb"); + if (!pFile) + { + // file error + char szMsg[128]; + sprintf(szMsg,"Couldn't create/save password file %s.\n",szFile); + ConsolePrint(szMsg); + return; + } + + //Loop and write the file. + for (AgAddressToPasswordMap::iterator itrPasswords = m_mapPasswords.begin() ;itrPasswords != m_mapPasswords.end(); ++itrPasswords) + fprintf(pFile,"%s %s\n",(*itrPasswords).first.c_str(),(*itrPasswords).second.c_str()); + + fflush(pFile); + fclose(pFile); +} + +//-- Martin Webrant diff --git a/cl_dll/aghl/AgVGUIPassword.h b/cl_dll/aghl/AgVGUIPassword.h new file mode 100644 index 00000000..d24e0d07 --- /dev/null +++ b/cl_dll/aghl/AgVGUIPassword.h @@ -0,0 +1,43 @@ +//++ BulliT + +#if !defined(_AG_VGUI_Password_) +#define _AG_VGUI_Password_ + +#include +#include + +namespace vgui +{ +class TextEntry; +class TextPanel; +class EditPanel; +} + +class AgVGuiPassword : public vgui::Panel +{ +private: + vgui::Label* m_pLabel; + vgui::TextEntry* m_pTextEntry; + CommandButton* m_pConnect; + + AgString m_sAddress; + typedef map > AgAddressToPasswordMap; + AgAddressToPasswordMap m_mapPasswords; + + void ReadPasswords(); + void SavePasswords(); + +public: + AgVGuiPassword(int x,int y,int wide,int tall); +public: + virtual void doConnect(); + virtual void paintBackground(); + + virtual int KeyInput(int down, int keynum, const char *pszCurrentBinding); + + void Connect(const char* pszHostname, const char* pszAddress, bool bPassworded); +}; + +#endif //_AG_VGUI_Password_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/AgVGuiMapBrowser.cpp b/cl_dll/aghl/AgVGuiMapBrowser.cpp new file mode 100644 index 00000000..3e3f99e9 --- /dev/null +++ b/cl_dll/aghl/AgVGuiMapBrowser.cpp @@ -0,0 +1,606 @@ + +#include +#include +#include +#include +#include +#include +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" + +#include "hud.h" +#include "cl_util.h" + +#include "vgui_TeamFortressViewport.h" +#include "AgVGuiMapBrowser.h" +#include "parsemsg.h" +#include + +static int g_iStartIndex = 0; +static AgString s_sMapList; +static bool s_bHaveAllMaps = true; +static AgStringSet s_setMaps; +static AgStringSet s_setLocalMaps; +extern cvar_t* g_pcl_show_local_maps; + +const char* GetMap(unsigned int iRow) +{ + if (iRow < s_setMaps.size()) + { + AgStringSet::iterator itrMaps = s_setMaps.begin(); + for (unsigned int i = 0; i < iRow && itrMaps != s_setMaps.end(); i++, itrMaps++) + {} + + if (itrMaps != s_setMaps.end()) + return (*itrMaps).c_str(); + } + return NULL; +} + + +using namespace vgui; + +namespace +{ + class MapBrowserTablePanel; + + class MapBrowserTablePanel_InputSignal : public InputSignal + { + MapBrowserTablePanel* m_pMapBrowser; + public: + MapBrowserTablePanel_InputSignal(MapBrowserTablePanel* pMapBrowser) + { + m_pMapBrowser = pMapBrowser; + } + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void cursorEntered(Panel* panel){}; + virtual void cursorExited(Panel* Panel) {}; + virtual void mousePressed(MouseCode code,Panel* panel); + virtual void mouseDoublePressed(MouseCode code,Panel* panel); + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; + }; + + #define CELL_HEIGHT YRES(15) + + class MapBrowserTablePanel : public TablePanel + { + private: + Label *m_pLabel; + int m_nMouseOverRow; + + public: + + MapBrowserTablePanel( int x,int y,int wide,int tall,int columnCount) : TablePanel( x,y,wide,tall,columnCount) + { + m_pLabel = new Label( "", 0, 0 ); + + m_nMouseOverRow = 0; + setCellEditingEnabled(false); + } + + public: + void setMouseOverRow( int row ) + { + m_nMouseOverRow = row; + + DoUpdateMap(); + } + + void DoChangeMap( void ) + { + stopCellEditing(); + DoCancel(); + const char* pszMap = GetMap(m_nMouseOverRow + g_iStartIndex); + + if (pszMap && strlen(pszMap)) + { + char szCommand[256]; + sprintf(szCommand,"agmap %s",pszMap); + ServerCmd(szCommand); + } + } + + void DoChangeNextMap( void ) + { + DoCancel(); + const char* pszMap = GetMap(m_nMouseOverRow + g_iStartIndex); + + if (pszMap && strlen(pszMap)) + { + char szCommand[256]; + sprintf(szCommand,"agnextmap %s",pszMap); + ServerCmd(szCommand); + } + } + + void DoCancel( void ) + { + ClientCmd( "togglemapbrowser\n" ); + } + + + void DoPrev( void ) + { + g_iStartIndex -= getRowCount(); + if (g_iStartIndex < 0) + g_iStartIndex = 0; + + DoUpdateMap(); + } + + + void DoNext( void ) + { + g_iStartIndex += getRowCount(); + if (g_iStartIndex > (int)s_setMaps.size()) + g_iStartIndex = 0; + + DoUpdateMap(); + } + + void DoUpdateMap( void ) + { + AgVGuiMapBrowser* pVGUI = (AgVGuiMapBrowser*)getParent(); + pVGUI->UpdateMap(GetMap(m_nMouseOverRow + g_iStartIndex)); + } + + virtual int getRowCount() + { + int rowcount; + int height, width; + + getSize( width, height ); + height = max( 0, height ); + rowcount = height / CELL_HEIGHT; + + return rowcount; + } + + virtual int getCellTall(int row) + { + return CELL_HEIGHT - 2; + } + + virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) + { + const char* pszMap = GetMap(row + g_iStartIndex); + if ( row == m_nMouseOverRow ) + { + m_pLabel->setFgColor( 255, 255, 255, 0 ); + + } + else + { + m_pLabel->setFgColor( 200, 240, 63, 100 ); + if (pszMap && strlen(pszMap)) + { + AgStringSet::iterator itrLocalMaps = s_setLocalMaps.find(pszMap); + if (itrLocalMaps == s_setLocalMaps.end()) + m_pLabel->setFgColor( 200, 0, 0, 100 ); + } + } + m_pLabel->setBgColor( 0, 0, 0, 200 ); + m_pLabel->setContentAlignment( vgui::Label::a_west ); + m_pLabel->setFont( Scheme::sf_primary2 ); + + if ( pszMap ) + { + // Fill out with the correct data + switch ( column ) + { + case 0: + { + m_pLabel->setText( pszMap ); + } + break; + default: + break; + } + } + else + { + if ( !row && !column ) + { + if ( !s_bHaveAllMaps ) + { + m_pLabel->setText( "Please wait..." ); + } + else + { + // m_pLabel->setText( "Press 'Refresh' to search for servers..." ); + } + } + else + { + m_pLabel->setText( "" ); + } + } + + return m_pLabel; + } + + virtual Panel* startCellEditing(int column,int row) + { + return null; + } + }; + + enum Action + { + Close, More, Previous, Change, ChangeNext, + }; + + class MapBrowserHandler : public ActionSignal + { + Action m_act; + MapBrowserTablePanel* m_pMapBrowser; + public: + MapBrowserHandler(Action act, MapBrowserTablePanel* pMapBrowser) + { + m_act = act; + m_pMapBrowser = pMapBrowser; + } + public: + virtual void actionPerformed(Panel* panel) + { + switch (m_act) + { + case Close: + gViewPort->ToggleMapBrowser(); + break; + case More: + m_pMapBrowser->DoNext(); + break; + case Change: + m_pMapBrowser->DoChangeMap(); + break; + case ChangeNext: + m_pMapBrowser->DoChangeNextMap(); + break; + default: + break; + } + } + }; + + void MapBrowserTablePanel_InputSignal::mousePressed(MouseCode code,Panel* panel) + { + int x, y; + int therow = 2; + + if ( code != MOUSE_LEFT ) + return; + + panel->getApp()->getCursorPos(x,y); + panel->screenToLocal( x, y ); + + therow = y / (CELL_HEIGHT); + + // Figure out which row it's on + m_pMapBrowser->setMouseOverRow( therow ); + } + + void MapBrowserTablePanel_InputSignal::mouseDoublePressed(MouseCode code,Panel* panel) + { + int x, y; + int therow = 2; + + if ( code != MOUSE_LEFT ) + return; + + panel->getApp()->getCursorPos(x,y); + panel->screenToLocal( x, y ); + + therow = y / (CELL_HEIGHT-1); + + // Figure out which row it's on + m_pMapBrowser->setMouseOverRow( therow ); + m_pMapBrowser->DoChangeMap(); + } +} + +#define MAPBROWSER_TITLE_X XRES(16) +#define MAPBROWSER_TITLE_Y YRES(16) + +#define MAPBROWSER_BUTTON_SIZE_X XRES(100) +#define MAPBROWSER_BUTTON_SIZE_Y YRES(24) +#define MAPBROWSER_BUTTON_SPACER_Y YRES(8) +#define MAPBROWSER_BUTTON_SPACER_X XRES(8) + +#define TABLE_X XRES(8) +#define TABLE_Y YRES(60) +#define HEADER_SIZE_X XRES(100) +#define HEADER_SIZE_Y 0 //YRES(18) + +#define NUM_COLUMNS 1 + +AgVGuiMapBrowser::AgVGuiMapBrowser(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0)) ); + + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hIRCText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the title + m_pLabel = new Label( "", MAPBROWSER_TITLE_X, MAPBROWSER_TITLE_Y ); + m_pLabel->setParent( this ); + m_pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + m_pLabel->setFont( Scheme::sf_primary1 ); + + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + m_pLabel->setFgColor( r, g, b, a ); +// m_pLabel->setFgColor( Scheme::sc_primary1 ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + m_pLabel->setBgColor( r, g, b, a ); + m_pLabel->setContentAlignment( vgui::Label::a_west ); + m_pLabel->setText("AG Map Browser"); + + int iXSize,iYSize; + getSize( iXSize,iYSize ); + + Label* pHeaderLabel = new Label("Maps"); + pHeaderLabel->setContentAlignment( vgui::Label::a_west ); + pHeaderLabel->setFgColor( Scheme::sc_primary1 ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pHeaderLabel->setBgColor( r, g, b, a ); + pHeaderLabel->setFont( Scheme::sf_primary2 ); + + m_pHeaderPanel= new HeaderPanel(TABLE_X,TABLE_Y,HEADER_SIZE_X,HEADER_SIZE_Y); + m_pHeaderPanel->setParent(this); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + m_pHeaderPanel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + m_pHeaderPanel->setBgColor( r, g, b, a ); + m_pHeaderPanel->addSectionPanel(pHeaderLabel); + m_pHeaderPanel->setSliderPos( 0, HEADER_SIZE_X ); + + m_pTablePanel = new MapBrowserTablePanel( TABLE_X, TABLE_Y + HEADER_SIZE_Y, HEADER_SIZE_X, iYSize - (TABLE_Y + HEADER_SIZE_Y + MAPBROWSER_BUTTON_SIZE_Y*2 + MAPBROWSER_BUTTON_SPACER_Y), NUM_COLUMNS ); + m_pTablePanel->setParent(this); + m_pTablePanel->setHeaderPanel(m_pHeaderPanel); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + m_pTablePanel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + m_pTablePanel->setBgColor( r, g, b, a ); + m_pTablePanel->addInputSignal(new MapBrowserTablePanel_InputSignal((MapBrowserTablePanel*)m_pTablePanel)); + + int bw = MAPBROWSER_BUTTON_SIZE_X; + int bh = MAPBROWSER_BUTTON_SIZE_Y; + int btny = iYSize - YRES(16) - BUTTON_SIZE_Y;//tall - MAPBROWSER_BUTTON_SIZE_Y - MAPBROWSER_BUTTON_SPACER_Y; + int btnx = TABLE_X; + + CommandButton* pMore = new CommandButton("More",btnx, btny, bw, bh); + pMore->addActionSignal(new MapBrowserHandler(More,(MapBrowserTablePanel*)m_pTablePanel)); + pMore->setParent(this); + + btnx += MAPBROWSER_BUTTON_SPACER_X + MAPBROWSER_BUTTON_SIZE_X; + + CommandButton* pChange = new CommandButton("Change Now",btnx, btny, bw, bh); + pChange->addActionSignal(new MapBrowserHandler(Change,(MapBrowserTablePanel*)m_pTablePanel)); + pChange->setParent(this); + + btnx += MAPBROWSER_BUTTON_SPACER_X + MAPBROWSER_BUTTON_SIZE_X; + + CommandButton* pChangeNext = new CommandButton("Change Next",btnx, btny, bw, bh); + pChangeNext->addActionSignal(new MapBrowserHandler(ChangeNext,(MapBrowserTablePanel*)m_pTablePanel)); + pChangeNext->setParent(this); + + btnx += MAPBROWSER_BUTTON_SPACER_X + MAPBROWSER_BUTTON_SIZE_X; + + CommandButton* pClose = new CommandButton("Close",btnx, btny, bw, bh); + pClose->addActionSignal(new MapBrowserHandler(Close,(MapBrowserTablePanel*)m_pTablePanel)); + pClose->setParent(this); + + // Create the Scroll panel + m_pTextScrollPanel = new CTFScrollPanel( TABLE_X + HEADER_SIZE_X + XRES(16), TABLE_Y + HEADER_SIZE_Y, iXSize - (TABLE_X + HEADER_SIZE_X + XRES(16)), iYSize - (TABLE_Y + HEADER_SIZE_Y + MAPBROWSER_BUTTON_SIZE_Y + MAPBROWSER_BUTTON_SPACER_Y + MAPBROWSER_TITLE_Y + YRES(8))); + m_pTextScrollPanel->setParent(this); + m_pTextScrollPanel->setScrollBarVisible(false, false); + m_pTextScrollPanel->setScrollBarAutoVisible(true, true); + + + // Create the text panel + m_pTextPanel = new TextPanel( "", 0,0, 64,64); + m_pTextPanel->setParent( m_pTextScrollPanel->getClient() ); + + // get the font and colors from the scheme + m_pTextPanel->setFont( pSchemes->getFont(hIRCText) ); + pSchemes->getFgColor( hIRCText, r, g, b, a ); + m_pTextPanel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hIRCText, r, g, b, a ); + m_pTextPanel->setBgColor( r, g, b, a ); + m_pTextPanel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Map_Description_not_available")); + + m_pTextScrollPanel->setScrollValue( 0, 0 ); +} + + +void AgVGuiMapBrowser::paintBackground() +{ + // Transparent black background + drawSetColor( 0,0,0, 100 ); + drawFilledRect(0,0,_size[0],_size[1]); +} + +void AgVGuiMapBrowser::UpdateMap(const char* pszMap) +{ + char* pText = NULL; + + if (pszMap) + { + char szMapFile[MAX_PATH]; + sprintf(szMapFile,"maps/%s.txt",pszMap); + pText = (char*)gEngfuncs.COM_LoadFile(szMapFile, 5, NULL); + } + + //force the scrollbars on so clientClip will take them in account after the validate + m_pTextScrollPanel->setScrollBarAutoVisible(false, false); + m_pTextScrollPanel->setScrollBarVisible(true, true); + m_pTextScrollPanel->validate(); + + if (pText) + m_pTextPanel->setText(pText); + else + m_pTextPanel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Map_Description_not_available")); + + + // Get the total size of the MOTD text and resize the text panel + int iScrollSizeX, iScrollSizeY; + + // First, set the size so that the client's wdith is correct at least because the + // width is critical for getting the "wrapped" size right. + // You'll see a horizontal scroll bar if there is a single word that won't wrap in the + // specified width. + m_pTextPanel->getTextImage()->setSize(m_pTextScrollPanel->getClientClip()->getWide(), m_pTextScrollPanel->getClientClip()->getTall()); + m_pTextPanel->getTextImage()->getTextSizeWrapped( iScrollSizeX, iScrollSizeY ); + + // Now resize the textpanel to fit the scrolled size + m_pTextPanel->setSize( iScrollSizeX , iScrollSizeY ); + + //turn the scrollbars back into automode + m_pTextScrollPanel->setScrollBarAutoVisible(true, true); + m_pTextScrollPanel->setScrollBarVisible(false, false); + m_pTextScrollPanel->setScrollValue( 0, 0 ); + + m_pTextScrollPanel->validate(); + + if (pText) + gEngfuncs.COM_FreeFile(pText); +} + +int AgVGuiMapBrowser::MsgFunc_MapList( const char *pszName, int iSize, void *pbuf ) +{ + if (s_bHaveAllMaps) + s_sMapList = ""; + + BEGIN_READ( pbuf, iSize ); + s_bHaveAllMaps = 0 == READ_BYTE(); + s_sMapList += READ_STRING(); + + if (s_bHaveAllMaps) + { + s_setMaps.empty(); + AgToLower(s_sMapList); + + int iStart = 0; + int iEnd = 0; + do + { + iEnd = s_sMapList.find("#",iStart); + + if (-1 != iEnd) + { + AgString sMap = s_sMapList.substr(iStart,iEnd-iStart); + AgTrim(sMap); + if (sMap.length()) + { + s_setMaps.insert(sMap); + } + iStart = iEnd + 1; + } + } + while (-1 != iEnd); + + s_setMaps.insert("boot_camp"); + s_setMaps.insert("bounce"); + s_setMaps.insert("datacore"); + s_setMaps.insert("lambda_bunker"); + s_setMaps.insert("snark_pit"); + s_setMaps.insert("stalkyard"); + s_setMaps.insert("subtransit"); + s_setMaps.insert("undertow"); + + ((MapBrowserTablePanel*)m_pTablePanel)->DoUpdateMap(); + + s_sMapList = ""; + } + + return 1; +} + +void AgVGuiMapBrowser::GetMaps() +{ + if (s_bHaveAllMaps && 0 == s_setMaps.size()) + { + if (0 == s_setLocalMaps.size()) + GetLocalMaps(); + ServerCmd("maplist\n"); + } +} + +void AgVGuiMapBrowser::GetLocalMaps() +{ + char szDirAG[MAX_PATH]; + char szDirVALVE[MAX_PATH]; + + strcpy(szDirAG,AgGetDirectory()); + strcat(szDirAG,"/maps"); + strcpy(szDirVALVE,AgGetDirectoryValve()); + strcat(szDirVALVE,"/maps"); + + AgStringSet setFiles; + AgStringSet::iterator itrFiles; + + AgDirList(szDirAG,setFiles); + AgDirList(szDirVALVE,setFiles); + + for (itrFiles = setFiles.begin() ;itrFiles != setFiles.end();++itrFiles) + { + AgString sFile = *itrFiles; + AgToLower(sFile); + if (!strstr(sFile.c_str(),".bsp")) + continue; + sFile = sFile.substr(0,sFile.length()-4); + AgTrim(sFile); + s_setLocalMaps.insert(sFile); + } + + s_setLocalMaps.insert("boot_camp"); + s_setLocalMaps.insert("bounce"); + s_setLocalMaps.insert("datacore"); + s_setLocalMaps.insert("lambda_bunker"); + s_setLocalMaps.insert("snark_pit"); + s_setLocalMaps.insert("stalkyard"); + s_setLocalMaps.insert("subtransit"); + s_setLocalMaps.insert("undertow"); +} + + +int AgVGuiMapBrowser::KeyInput(int down, int keynum, const char *pszCurrentBinding) +{ + if (!down) + return 1; + + if (!isVisible()) + return 1; + + if (K_ESCAPE == keynum || pszCurrentBinding && 0 == _stricmp("togglemapbrowser",pszCurrentBinding)) + { + gViewPort->ToggleMapBrowser(); + return 0; + } + + if (K_MWHEELUP == keynum) + { + ((MapBrowserTablePanel*)m_pTablePanel)->DoPrev(); + return 0; + } + + if (K_MWHEELDOWN == keynum) + { + ((MapBrowserTablePanel*)m_pTablePanel)->DoNext(); + return 0; + } + + return 1; +} \ No newline at end of file diff --git a/cl_dll/aghl/AgVGuiMapBrowser.h b/cl_dll/aghl/AgVGuiMapBrowser.h new file mode 100644 index 00000000..c5a51a67 --- /dev/null +++ b/cl_dll/aghl/AgVGuiMapBrowser.h @@ -0,0 +1,70 @@ + +#ifndef AGVGUIMAPBROWSER_H +#define AGVGUIMAPBROWSER_H + +#include + + +class AgVGuiMapBrowser : public vgui::Panel +{ +private: + vgui::HeaderPanel * m_pHeaderPanel; + vgui::TablePanel* m_pTablePanel; + CTransparentPanel* m_pBackgroundPanel; + Label* m_pLabel; + vgui::ScrollPanel* m_pTextScrollPanel; + vgui::TextPanel* m_pTextPanel; +public: + AgVGuiMapBrowser(int x,int y,int wide,int tall); +public: + virtual void paintBackground(); + virtual int KeyInput(int down, int keynum, const char *pszCurrentBinding); + + int MsgFunc_MapList(const char *pszName, int iSize, void *pbuf); + void GetMaps(); + void GetLocalMaps(); + + void UpdateMap(const char* pszMap); +}; + +/* +namespace vgui +{ +class Button; +class TablePanel; +class HeaderPanel; +} + +class CTransparentPanel; +class CommandButton; + +// Scoreboard positions +#define SB_X_INDENT (20 * ((float)ScreenHeight / 640)) +#define SB_Y_INDENT (20 * ((float)ScreenHeight / 480)) + +class AgVGuiMapBrowser : public CTransparentPanel +{ +private: + HeaderPanel * _headerPanel; + TablePanel* _tablePanel; + ScrollPanel* _scrollPanel; + + CommandButton* _ChangeMapButton; + CommandButton* _ChangeNextMapButton; + CommandButton* _InfoButton; + CommandButton* _CancelButton; + CommandButton* _NextPageButton; + + void DoNext(); + +public: + AgVGuiMapBrowser(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); + virtual int KeyInput(int down, int keynum, const char *pszCurrentBinding); + + int MsgFunc_MapList(const char *pszName, int iSize, void *pbuf); + void GetMaps(); +}; +*/ +#endif \ No newline at end of file diff --git a/cl_dll/aghl/Agglobal.cpp b/cl_dll/aghl/Agglobal.cpp new file mode 100644 index 00000000..094b4f74 --- /dev/null +++ b/cl_dll/aghl/Agglobal.cpp @@ -0,0 +1,524 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include "agglobal.h" +#include +#include "agmodelcheck.h" + +cvar_t* g_phud_spectatebar = NULL; +cvar_t* g_phud_timer = NULL; +cvar_t* g_phud_playerid = NULL; +cvar_t* g_phud_settings = NULL; +cvar_t* g_phud_weapon = NULL; +cvar_t* g_phud_color = NULL; +cvar_t* g_pcl_matchreport = NULL; +cvar_t* g_pcl_playtalk = NULL; +cvar_t* g_pcl_weaponswitch = NULL; +//cvar_t* g_pcl_weaponweights = NULL; +cvar_t* g_pcl_disablespecs = NULL; +cvar_t* g_pcl_liveupdate = NULL; +cvar_t* g_pcl_scores = NULL; +cvar_t* g_pcl_scores_pos = NULL; +cvar_t* g_pcl_only_team_talk = NULL; +cvar_t* g_pcl_show_colors = NULL; +cvar_t* g_pcl_old_scoreboard = NULL; +cvar_t* g_pcl_ctf_volume = NULL; +cvar_t* g_pcl_show_local_maps = NULL; +cvar_t* g_pcl_location_keywords = NULL; +cvar_t* g_pcl_show_banner = NULL; + + +cvar_t* g_pirc_server = NULL; +cvar_t* g_pirc_nick = NULL; +cvar_t* g_pirc_port = NULL; +cvar_t* g_pirc_userid = NULL; +cvar_t* g_pirc_password = NULL; +cvar_t* g_pirc_fullname = NULL; +cvar_t* g_pirc_autojoin = NULL; +cvar_t* g_pirc_autocommand = NULL; +cvar_t* g_pirc_autocommand2 = NULL; +cvar_t* g_pirc_autocommand3 = NULL; + +// Colors +int iNumConsoleColors = 16; +int arrConsoleColors[16][3] = +{ + { 255, 170, 0 }, // HL console (default) + { 255, 0, 0 }, // Red + { 0, 255, 0 }, // Green + { 255, 255, 0 }, // Yellow + { 0, 0, 255 }, // Blue + { 0, 255, 255 }, // Cyan + { 255, 0, 255 }, // Violet + { 136, 136, 136 }, // Q + { 255, 255, 255 }, // White + { 0, 0, 0 }, // Black + { 200, 90, 70 }, // Redb + { 145, 215, 140 }, // Green + { 225, 205, 45 }, // Yellow + { 125, 165, 210 }, // Blue + { 70, 70, 70 }, + { 200, 200, 200 }, +}; + +int arrHudColor[3] = +{ + 255, 160, 0 +}; + +extern int iTeamColors[5][3]; +extern float g_ColorConsole[3]; +//-- Martin Webrant +#ifdef _DEBUG +void AgTest(); +#endif + +void AgUpdateHudColor() +{ + //Hud color + sscanf(CVAR_GET_STRING("hud_color"), "%i %i %i", &arrHudColor[0], &arrHudColor[1], &arrHudColor[2] ); + iTeamColors[0][0] = arrHudColor[0]; + iTeamColors[0][1] = arrHudColor[1]; + iTeamColors[0][2] = arrHudColor[2]; + + //Console color + sscanf(CVAR_GET_STRING("con_color"), "%i %i %i", &arrConsoleColors[0][0], &arrConsoleColors[0][1], &arrConsoleColors[0][2] ); + g_ColorConsole[0] = arrConsoleColors[0][0] / 255.0; + g_ColorConsole[1] = arrConsoleColors[0][1] / 255.0; + g_ColorConsole[2] = arrConsoleColors[0][2] / 255.0; +} + +void AgGetHudColor(int &r, int &g, int &b) +{ + r = arrHudColor[0]; + g = arrHudColor[1]; + b = arrHudColor[2]; +} + +//extern void COM_Log( char *pszFile, char *fmt, ...); + +void AgInitClientDll() +{ + g_phud_spectatebar = gEngfuncs.pfnRegisterVariable ( "hud_spectatebar", "1", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_phud_timer = gEngfuncs.pfnRegisterVariable ( "hud_timer", "1", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_phud_playerid = gEngfuncs.pfnRegisterVariable ( "hud_playerid", "1", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_phud_settings = gEngfuncs.pfnRegisterVariable ( "hud_settings", "1", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_phud_weapon = gEngfuncs.pfnRegisterVariable ( "hud_weapon", "0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_phud_color = gEngfuncs.pfnRegisterVariable ( "hud_color", "255 160 0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + + g_pcl_matchreport = gEngfuncs.pfnRegisterVariable ( "cl_matchreport", "1", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pcl_playtalk = gEngfuncs.pfnRegisterVariable ( "cl_playtalk", "0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + + g_pcl_weaponswitch = gEngfuncs.pfnRegisterVariable ( "cl_autowepswitch", "1", FCVAR_CLIENTDLL|FCVAR_ARCHIVE|FCVAR_USERINFO); + //g_pcl_weaponweights = gEngfuncs.pfnRegisterVariable ( "cl_weaponweights", "", FCVAR_CLIENTDLL|FCVAR_ARCHIVE|FCVAR_USERINFO); //weapon weight factors (for auto-switching) (-1 = noswitch) + + g_pcl_disablespecs = gEngfuncs.pfnRegisterVariable ( "cl_disablespecs", "0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE|FCVAR_USERINFO); + g_pcl_liveupdate = gEngfuncs.pfnRegisterVariable ( "cl_liveupdate", "0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); //Special for Mr. T-rex :P + g_pcl_scores = gEngfuncs.pfnRegisterVariable ( "cl_scores", "0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pcl_scores_pos = gEngfuncs.pfnRegisterVariable ( "cl_scores_pos", "30 50", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + + g_pcl_only_team_talk= gEngfuncs.pfnRegisterVariable ( "cl_only_team_talk", "0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pcl_show_colors = gEngfuncs.pfnRegisterVariable ( "cl_show_colors", "1", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pcl_old_scoreboard = gEngfuncs.pfnRegisterVariable ( "cl_old_scoreboard", "0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pcl_ctf_volume = gEngfuncs.pfnRegisterVariable ( "cl_ctf_volume", "1", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + + g_pirc_server = gEngfuncs.pfnRegisterVariable ( "irc_server", "irc.quakenet.eu.org", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pirc_port = gEngfuncs.pfnRegisterVariable ( "irc_port", "6667", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pirc_nick = gEngfuncs.pfnRegisterVariable ( "irc_nick", "", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pirc_userid = gEngfuncs.pfnRegisterVariable ( "irc_userid", "", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pirc_password = gEngfuncs.pfnRegisterVariable ( "irc_password", "", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pirc_fullname = gEngfuncs.pfnRegisterVariable ( "irc_fullname", "", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pirc_autojoin = gEngfuncs.pfnRegisterVariable ( "irc_autojoin", "#pmers", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pirc_autocommand = gEngfuncs.pfnRegisterVariable ( "irc_autocommand","", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pirc_autocommand2 = gEngfuncs.pfnRegisterVariable ( "irc_autocommand2","", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pirc_autocommand3 = gEngfuncs.pfnRegisterVariable ( "irc_autocommand3","", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + + g_pcl_show_local_maps = gEngfuncs.pfnRegisterVariable ("cl_show_local_maps", "0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + + g_pcl_location_keywords = gEngfuncs.pfnRegisterVariable ("cl_location_keywords", "0", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + g_pcl_show_banner = gEngfuncs.pfnRegisterVariable ("cl_show_banner", "1", FCVAR_CLIENTDLL|FCVAR_ARCHIVE); + + //Can use opforce stuff + gEngfuncs.COM_AddAppDirectoryToSearchPath("opforce","opforce"); + + //Setup colors + AgUpdateHudColor(); + +// COM_Log(NULL,"Modulehandle - %lx\n",GetModuleHandle("client.dll")); +} + + +int GetColor(char cChar) +{ + int iColor = -1; + if (cChar >= '0' && cChar <= '9') + iColor = cChar - '0'; + return iColor; +} + +int AgDrawHudStringCentered(int xpos, int ypos, int iMaxX, const char *szIt, int r, int g, int b ) +{ + // calc center + int iSizeX = 0; + char* pszIt = (char*)szIt; + for ( ; *pszIt != 0 && *pszIt != '\n'; pszIt++ ) + iSizeX += gHUD.m_scrinfo.charWidths[ *pszIt ]; // variable-width fonts look cool + + //Subtract half sizex from xpos to center it. + xpos = xpos - iSizeX / 2; + + int rx = r, gx = g, bx = b; + + pszIt = (char*)szIt; + // draw the string until we hit the null character or a newline character + for ( ; *pszIt != 0 && *pszIt != '\n'; pszIt++ ) + { + if (*pszIt == '^') + { + pszIt++; + int iColor = GetColor(*pszIt); + if (iColor < iNumConsoleColors && iColor >= 0) + { + if (0 >= iColor || 0 == g_pcl_show_colors->value) + { + rx = r; + gx = g; + bx = b; + } + else + { + rx = arrConsoleColors[iColor][0]; + gx = arrConsoleColors[iColor][1]; + bx = arrConsoleColors[iColor][2]; + } + pszIt++; + if (*pszIt == 0 || *pszIt == '\n') + break; + } + else + pszIt--; + } + + int next = xpos + gHUD.m_scrinfo.charWidths[ *pszIt ]; // variable-width fonts look cool + if ( next > iMaxX ) + return xpos; + TextMessageDrawChar( xpos, ypos, *pszIt, rx, gx, bx ); + xpos = next; + } + return xpos; +} + +int AgDrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) +{ + + int rx = r, gx = g, bx = b; + + // draw the string until we hit the null character or a newline character + for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + if (*szIt == '^') + { + szIt++; + int iColor = GetColor(*szIt); + if (iColor < iNumConsoleColors && iColor >= 0) + { + if (0 >= iColor || 0 == g_pcl_show_colors->value) + { + rx = r; + gx = g; + bx = b; + } + else + { + rx = arrConsoleColors[iColor][0]; + gx = arrConsoleColors[iColor][1]; + bx = arrConsoleColors[iColor][2]; + } + szIt++; + if (*szIt == 0 || *szIt == '\n') + break; + } + else + szIt--; + } + + int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool + if ( next > iMaxX ) + return xpos; + + TextMessageDrawChar( xpos, ypos, *szIt, rx, gx, bx ); + xpos = next; + } + + return xpos; +} + +int AgDrawConsoleString( int x, int y, const char *string, float r, float g, float b ) +{ + if (0 == g_pcl_show_colors->value) + { + char* pszString = strdup(string); + AgStripColors((char*)pszString); + int iRet = gEngfuncs.pfnDrawConsoleString( x, y, (char*) pszString ); + free(pszString); + return iRet; + } + + + char szText[512]; + char* pText = szText; + *pText = '\0'; + char* pszColor = (char*)string; + while (*pszColor) + { + if ('^' == *pszColor) + { + int iColor = GetColor(*(pszColor+1)); + if (iColor < iNumConsoleColors && iColor >= 0) + //User wants a new color + { + //Draw first part with previous color. + *pText = '\0'; + *pszColor = '\0'; + int xPrev = gEngfuncs.pfnDrawConsoleString( x, y, (char*)szText); + *pszColor = '^'; + pszColor++; + pszColor++; + + float rx = r, gx = g, bx = b; + //Set the color. + if (iColor > 0) + { + rx = arrConsoleColors[iColor][0] / 255.0; + gx = arrConsoleColors[iColor][1] / 255.0; + bx = arrConsoleColors[iColor][2] / 255.0; + } + if (!(rx == 0 && gx == 0 && bx == 0)) + gEngfuncs.pfnDrawSetTextColor(rx, gx, bx); + + //Draw the rest of the string (that may contain new colors) + return AgDrawConsoleString( xPrev , y, pszColor, r, g, b); + } + } + *pText = *pszColor; + pText++; + pszColor++; + } + *pText = '\0'; + + if (!(r == 0 && g == 0 && b == 0)) + gEngfuncs.pfnDrawSetTextColor(r, g, b); + + return gEngfuncs.pfnDrawConsoleString( x, y, (char*) szText ); +/* + int iLength = strlen(string); + char* pszColor = strchr(string,'^'); + + if (pszColor) + { + //Extract color. + ++pszColor; + int iColor = GetColor(*pszColor); + ++pszColor; + + //Check if we got a valid color. + if (iColor < iNumConsoleColors && iColor >= 0) + { + char szTerm = *(pszColor-2); + *(pszColor-2) = '\0'; + + //Draw the first part with the previous color. + int xPrev = gEngfuncs.pfnDrawConsoleString( x, y, (char*)string); + *(pszColor-2) = szTerm; + + float rx = r, gx = g, bx = b; + //Set the color. + if (iColor != 0) + { + rx = arrConsoleColors[iColor][0] / 255.0; + gx = arrConsoleColors[iColor][1] / 255.0; + bx = arrConsoleColors[iColor][2] / 255.0; + } + if (!(rx == 0 && gx == 0 && bx == 0)) + gEngfuncs.pfnDrawSetTextColor(rx, gx, bx); + + //Draw the rest of the string (that may contain new colors) + return AgDrawConsoleString( xPrev , y, pszColor, r, g, b); + } + } + + if (!(r == 0 && g == 0 && b == 0)) + gEngfuncs.pfnDrawSetTextColor(r, g, b); + + return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string ); + */ +} + +void AgStripColors(char* pszString) +{ + char* pszIt = pszString; + while ('\0' != *pszIt) + { + if ('^' == *pszIt) + { + ++pszIt; + if (*pszIt >= '0' && *pszIt <= '9') + { + --pszIt; + memmove(pszIt,pszIt+2,strlen(pszIt+2)+1); + } + } + else + ++pszIt; + } +} + +AgString AgMapname() +{ + return gHUD.m_Location.m_szMap; + + /* + AgString sMap; + sMap = gEngfuncs.pfnGetLevelName(); + if (0 == sMap.size()) + return sMap; + + sMap = sMap.substr(sMap.find("/")+1); + sMap = sMap.substr(0,sMap.find(".")); + return sMap; + */ +} + +void AgTrim(AgString& sTrim) +{ + if (0 == sTrim.length()) + return; + + int b = sTrim.find_first_not_of(" \t\r\n"); + int e = sTrim.find_last_not_of(" \t\r\n"); + if(b == -1) // No non-whitespaces + sTrim = ""; + else + sTrim = string(sTrim, b, e - b + 1); +} + +void AgLog(const char* pszLog) +{ + char szFile[MAX_PATH]; + sprintf(szFile,"%s/aglog.txt", AgGetDirectory()); + FILE* pFile = fopen(szFile,"a+"); + if (!pFile) + { + return; + } + + time_t clock; + time( &clock ); + fprintf(pFile,"%s : %s",pszLog,asctime(localtime(&clock))); + fflush(pFile); + fclose(pFile); +} + + +void AgDirList(const AgString& sDir, AgStringSet& setFiles) +{ +#ifdef _WIN32 + WIN32_FIND_DATA FindData; + char szSearchDirectory[_MAX_PATH]; + sprintf(szSearchDirectory,"%s/*.*",sDir.c_str()); + HANDLE hFind = FindFirstFile(szSearchDirectory, &FindData); + + if (INVALID_HANDLE_VALUE != hFind) + { + do + { + if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + AgString sFile; + sFile = FindData.cFileName; + setFiles.insert(sFile); + } + } + while (FindNextFile(hFind, &FindData)); + FindClose(hFind); + } +#else + DIR* pDirectory = opendir(sDir.c_str()); + if (pDirectory) + { +struct dirent* pFile = NULL; + + while (NULL != (pFile = readdir(pDirectory))) + { + AgString sFile; + sFile = pFile->d_name; + setFiles.insert(sFile); + } + closedir(pDirectory); + } +#endif +} + +void AgToLower(AgString& strLower) +{ + size_t i = 0; + while (i < strLower.length()) + { + strLower[i] = tolower(strLower[i]); + i++; + } +} + + +const char* AgGetGame() +{ + static char szGame[MAX_PATH]; + strcpy(szGame, gEngfuncs.pfnGetGameDirectory()); + char* pszGameDir = strrchr(szGame, '/'); + if (pszGameDir) + return pszGameDir + 1; + return szGame; +} + +const char* AgGetDirectory() +{ + static char szGame[MAX_PATH]; + strcpy(szGame, gEngfuncs.pfnGetGameDirectory()); + char* pszGameDir = strrchr(szGame, '/'); + if (pszGameDir) + { + return szGame; + } + else + { + static char szDirectory[MAX_PATH] = ""; + if (strlen(szDirectory)) + return szDirectory; + + ::GetCurrentDirectory(MAX_PATH, szDirectory); + + strcat(szDirectory, "/"); + strcat(szDirectory, szGame); + return szDirectory; + } +} + +const char* AgGetDirectoryValve() +{ + static char szDirectory[MAX_PATH] = ""; + if (szDirectory[0] != '\0') + return szDirectory; + + strcpy(szDirectory, AgGetDirectory()); + int iStart = strlen(szDirectory)-1; + while ('/' != szDirectory[iStart]) + { + szDirectory[iStart] = '\0'; + iStart--; + } + szDirectory[iStart] = '\0'; + return szDirectory; +} + +//-- Martin Webrant diff --git a/cl_dll/aghl/agbase64.cpp b/cl_dll/aghl/agbase64.cpp new file mode 100644 index 00000000..27c7ec01 --- /dev/null +++ b/cl_dll/aghl/agbase64.cpp @@ -0,0 +1,151 @@ +//++ BulliT + +#include "agbase64.h" +#include +#include + +// define the US-ASCII chars +static char s_szBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\0"; + +// how many bits per byte? +#define NUM_BITS 8 +#define BYTES_TO_READ 60 // only for my test method Encode-file + +// define masks for Base64-encode +static int i_aMsbMask[] = { 0xfc, 0xf0, 0xc0, 0x00 }; +static int i_aLsbMask[] = { 0x00, 0x03, 0x0f, 0x3f }; + +// Define array for conversion between chars in base64 message and their weight according to array s_szBase64 +// This could be done by counting offset in s_szBase64. But sorry, too slow! +// start with asccii 2B (ie '+') +static int i_a64CharWeight [] = +{ + 62, -1, -1, -1, 63, // I have defined '+' and '/' + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // I have defined 0 through 9 + -1, -1, -1, -1, -1, -1, -1, // have undefined ascii 3A to 40 + // lets define 'A' to 'Z' + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, // A - Z + -1, -1, -1, -1, -1, -1, // have undefined ascii 5B to 40 + // lets define 'a' to 'z' + 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, + 49,50,51 // defined 'a' to 'z' +}; + +static int i_aDecodeMsbMask[] = { 0x3f, 0x0f, 0x03 }; +static int i_aDecodeLsbMask[] = { 0x30, 0x3c, 0x3f }; + + +//Decodes base64-encoded string. +//Assumptions: Incoming buffer (pszBuffer) is large enough. +void AgBase64Decode(const char* pszString,unsigned long ulInLen,unsigned char* pszBuffer, unsigned short& usOutLen) +{ + char* p = (char*)pszBuffer; + const char* pszSource = (const char*)pszString; + usOutLen = 0; + assert(0 == (ulInLen % 4)); // base-64 coded text should always be done in parts of 4 bytes + + while(ulInLen > 0) + { + int iAsciiO = i_a64CharWeight[*pszSource++ - 0x2B]; + for (int i = 1; i <= 3; i++) + { + int iAsciiChar = (iAsciiO & i_aDecodeMsbMask[i-1]) << (2*i); + int iChar = i_a64CharWeight[*pszSource++ - 0x2B]; + iAsciiChar += (iChar & i_aDecodeLsbMask[i-1]) >> (6-2*i); + iAsciiO = iChar; + *p++ = (char)iAsciiChar; + --ulInLen; + if (!('\0' == *(p-1) && '\0' == iAsciiChar)) //BAD BAD BAD! need to check what chars is padded better. + ++usOutLen; + } + --ulInLen; + } + +} + + +//Encodes incoming string to Base64. +//Assumptions: Incoming buffer (pszBuffer) is large enough. +//Haven't bothered to optimize this one since we only do it when we create file. +void AgBase64Encode(const unsigned char* pszString,unsigned long ulInLen,char* pszBuffer) +{ + assert(pszString); + assert(pszBuffer); + + char* p = (char*)pszString; + + while (ulInLen > 0) + { + int iAsciiO = 0; + // encode 3 characters (will become 4 chars when Base64 encoded) + for (int i = 0; i < 4; i++) + { + int iAsciiN = 0; + + if (ulInLen) + iAsciiN = (int)*p; + + int iMsbRightShift = NUM_BITS - (6-2*i); + int iLsbLeftShift = NUM_BITS - iMsbRightShift; + + int iChar64 = ((iAsciiN & i_aMsbMask[i]) >> iMsbRightShift); + iChar64 += ((iAsciiO & i_aLsbMask[i]) << iLsbLeftShift); + + iAsciiO = iAsciiN; + + assert(iChar64 >= 0 && iChar64 <= 63); + + if (i < 3) + { + p++; + if (ulInLen) + ulInLen--; + } + + *pszBuffer++ = s_szBase64[iChar64]; + } + + } + *pszBuffer = 0; +} + +//-- Martin Webrant + +/* + +static char* s_szBadCodes[] = +{ + "glhack", + "opengl.ini", + "TWCheat", + "B.teraphy", + "Flautz", + "sw!zz3r", + "ANAKiN", + "hooker.dll", + "UPX!", //whb31 + "c:\\opengl32.dll", + "hlh.dll", + "GRiM-F_H", + "ChromaxS", + "ogc.dll", + "Unhooker", // eller hlh.dll + "eZ!$7v", //Swizz hack + "coders.dll", //wh_beta4, wh_beta5 + "ogc.cfg", + "xqz2", //xqz2_b71 + "xqb6", //xqz2_b80 + "p@gram", //XQZ2Beta85 +}; + + int ix = 0; + for (ix = 0; ix < sizeof(s_szBadCodes)/sizeof(s_szBadCodes[0]); ix++) + { + char szBuff[256]; + AgBase64Encode((unsigned char*)s_szBadCodes[ix],strlen(s_szBadCodes[ix]),szBuff); + + char szTest[512]; + sprintf(szTest,"\"%s\", //%s\n",szBuff,s_szBadCodes[ix]); + OutputDebugString(szTest); + } +*/ \ No newline at end of file diff --git a/cl_dll/aghl/agbase64.h b/cl_dll/aghl/agbase64.h new file mode 100644 index 00000000..75c13d5c --- /dev/null +++ b/cl_dll/aghl/agbase64.h @@ -0,0 +1,11 @@ +//++ BulliT + +#ifndef __AG_BASE64_H__ +#define __AG_BASE64_H__ + +void AgBase64Decode(const char* pszString, unsigned long ulInLen, unsigned char* pszBuffer, unsigned short& ulOutLen); +void AgBase64Encode(const unsigned char* pszString, unsigned long ulInLen, char* pszBuffer); + +#endif //__AG_BASE64_H__ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agcrc32.cpp b/cl_dll/aghl/agcrc32.cpp new file mode 100644 index 00000000..f20bb48b --- /dev/null +++ b/cl_dll/aghl/agcrc32.cpp @@ -0,0 +1,84 @@ +//++ BulliT + +#include "agcrc32.h" + +// fixed CRC32 table (read only) +const WORD32 CRC32TAB[] = +{ + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + + +WORD32 AgCRC32(const void* pData, WORD32 lNumOfBytes) +{ + WORD32 lX; + WORD32 lI; + WORD32 lNewCRC32; + WORD8* pRun = (WORD8*) pData; + + lNewCRC32 = 0xFFFFFFFF; + if (lNumOfBytes == 0) + return lNewCRC32; + + for (lI = 0; lI < lNumOfBytes; lI++) + { + lX = pRun[lI] ^ (lNewCRC32 & 0x000000FF); + lNewCRC32 >>= 8; + lNewCRC32 ^= CRC32TAB[lX]; + } + return lNewCRC32; +} + + +//-- Martin Webrant diff --git a/cl_dll/aghl/agcrc32.h b/cl_dll/aghl/agcrc32.h new file mode 100644 index 00000000..10db8f36 --- /dev/null +++ b/cl_dll/aghl/agcrc32.h @@ -0,0 +1,18 @@ +//++ BulliT + +#ifndef __AG_CRC32_H__ +#define __AG_CRC32_H__ + +#ifdef WIN32 +typedef unsigned __int8 WORD8; // unsigned 8bit integer, prefix "b" +typedef unsigned __int32 WORD32; // unsigned 8bit integer, prefix "l" +#else +typedef unsigned char WORD8; +typedef unsigned int WORD32; +#endif + +WORD32 AgCRC32(const void* pData, WORD32 lNumOfBytes); + +#endif //__AG_CRC_H__ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agcrc32enforcer.cpp b/cl_dll/aghl/agcrc32enforcer.cpp new file mode 100644 index 00000000..4f3f4f95 --- /dev/null +++ b/cl_dll/aghl/agcrc32enforcer.cpp @@ -0,0 +1,140 @@ +#include "agcrc32enforcer.h" +#include "hud.h" +#include "cl_util.h" + +static char szDisconnect[] = "disconnect\n"; + +struct FILES +{ + char* pszFile; + WORD32 w32CheckSum; +}; + +static FILES s_Files[] = +{ + "gfx.wad", 1240178454, +// "halflife.wad", 1657905259, + "liquids.wad", 1067140096, + "models/player/hgrunt/hgrunt.mdl", 4178952236, + "models/player/scientist/scientist.mdl", 801952511, + "models/player/gordon/gordon.mdl", 1899521925, + "models/player/helmet/helmet.mdl", 413544432, + "models/player/robo/robo.mdl", 1066728661, + "models/player/barney/barney.mdl", 2342238586, + "models/player/recon/recon.mdl", 196824764, + "models/player/zombie/zombie.mdl", 2613106147, + "models/player/gman/gman.mdl", 363240166, + "models/player.mdl", 348061911, + "models/flag.mdl", 1312518787, + "models/p_crowbar.mdl", 2596481415, + "models/p_9mmhandgun.mdl", 459325257, + "models/p_9mmAR.mdl", 786579345, + "models/p_357.mdl", 96835772, + "models/p_gauss.mdl", 2413538144, + "models/p_rpg.mdl", 3201388383, + "models/p_crossbow.mdl", 1075131750, + "models/p_egon.mdl", 1795269724, + "models/p_tripmine.mdl", 2904825111, + "models/p_satchel.mdl", 1240685151, + "models/p_satchel_radio.mdl", 3737744643, + "models/p_shotgun.mdl", 2602382707, + "models/p_grenade.mdl", 3427694132, + "models/p_squeak.mdl", 472781321, + "models/p_hgun.mdl", 2327206545, +// "models/player/blue/blue.mdl", 3578029767, +// "models/player/red/red.mdl", 834545538, +}; + +WORD32 AgCRC32EnforceFileInternal(char* pszFile) +{ + int iLength = 0; + void* pFile = gEngfuncs.COM_LoadFile(pszFile, 5, &iLength); + if (pFile) + { + WORD32 w32CheckSumFile = AgCRC32(pFile, iLength); + gEngfuncs.COM_FreeFile(pFile); + return w32CheckSumFile; + } + return -1; +} + +bool AgCRC32EnforceFile(char* pszFile, WORD32 w32CheckSum) +{ + if (w32CheckSum != AgCRC32EnforceFileInternal(pszFile)) + { + char szMessage[256]; + sprintf(szMessage,"File check enforced and %s is either damaged or changed. Run scandisk and reinstall file.\n", pszFile); + AgLog(szMessage); + ConsolePrint(szMessage); + + ServerCmd( "say Disconnected for using invalid file.\n" ); + ClientCmd( szDisconnect ); + return false; + } + return true; +} + +bool AgCRC32EnforceFiles() +{ + bool bPassed = true; + for (int i = 0; i < sizeof(s_Files)/sizeof(s_Files[0]); i++) + { + if (s_Files[i].w32CheckSum != AgCRC32EnforceFileInternal(s_Files[i].pszFile)) + { + char szMessage[256]; + sprintf(szMessage,"File check enforced and %s is either damaged or changed. Run scandisk and reinstall file.\n", s_Files[i].pszFile); + AgLog(szMessage); + ConsolePrint(szMessage); +#ifndef _DEBUG + bPassed = false; +#endif + } + } + +/* + if (bPassed) + { + //Need special check for the 2 blue models... +#define OLD_BLUE 3578029767 +#define NEW_BLUE 945015980 +#define PLAYER 348061911 + +#define OLD_RED 834545538 +#define NEW_RED 2809992869 +#define PLAYER 348061911 + WORD32 w32CheckSumBlue = AgCRC32EnforceFileInternal("models/player/blue/blue.mdl"); + WORD32 w32CheckSumRed = AgCRC32EnforceFileInternal("models/player/red/red.mdl"); + + if (!(w32CheckSumBlue == OLD_BLUE || w32CheckSumBlue == NEW_BLUE || w32CheckSumBlue == PLAYER)) + { + char szMessage[256]; + sprintf(szMessage,"File check enforced and %s is either damaged or changed. Run scandisk and reinstall file.\n", "models/player/blue/blue.mdl"); + AgLog(szMessage); + ConsolePrint(szMessage); + #ifndef _DEBUG + bPassed = false; + #endif + } + + if (!(w32CheckSumRed == OLD_RED || w32CheckSumRed == NEW_RED || w32CheckSumRed == PLAYER)) + { + char szMessage[256]; + sprintf(szMessage,"File check enforced and %s is either damaged or changed. Run scandisk and reinstall file.\n", "models/player/red/red.mdl"); + AgLog(szMessage); + ConsolePrint(szMessage); + #ifndef _DEBUG + bPassed = false; + #endif + } + + } +*/ + if (!bPassed) + { + ServerCmd( "say Disconnected for using invalid file.\n" ); + ClientCmd( szDisconnect ); + return false; + } + + return true; +} \ No newline at end of file diff --git a/cl_dll/aghl/agcrc32enforcer.h b/cl_dll/aghl/agcrc32enforcer.h new file mode 100644 index 00000000..d688efce --- /dev/null +++ b/cl_dll/aghl/agcrc32enforcer.h @@ -0,0 +1,14 @@ +//++ BulliT + +#ifndef __AG_CRC32ENFORCER_H__ +#define __AG_CRC32ENFORCER_H__ + +#include "agcrc32.h" + +bool AgCRC32EnforceFile(char* pszFile, WORD32 w32CheckSum); + +bool AgCRC32EnforceFiles(); + +#endif //__AG_CRC32ENFORCER_H__ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agdownload.cpp b/cl_dll/aghl/agdownload.cpp new file mode 100644 index 00000000..19bac8a7 --- /dev/null +++ b/cl_dll/aghl/agdownload.cpp @@ -0,0 +1,98 @@ +// AgDownload.cpp: implementation of the AgDownload class. +// +////////////////////////////////////////////////////////////////////// + + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "agdownload.h" +#include "urlmon.h" +#pragma comment(lib, "urlmon.lib") + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +class AgDownloadCallBack : public IBindStatusCallback +{ +protected: + DWORD m_dwWhenToTimeout; +public: + AgDownloadCallBack(DWORD dwWhenToTimeout = 0) + { + m_dwWhenToTimeout = dwWhenToTimeout; + } + virtual ~AgDownloadCallBack() + { + }; + + // IBindStatusCallback methods. Note that the only method called by IE + // is OnProgress(), so the others just return E_NOTIMPL. + + STDMETHOD(OnStartBinding)(DWORD dwReserved,IBinding __RPC_FAR *pib) { return E_NOTIMPL; } + STDMETHOD(GetPriority)(/* [out] */ LONG __RPC_FAR *pnPriority) { return E_NOTIMPL; } + STDMETHOD(OnLowResource)(/* [in] */ DWORD reserved){ return E_NOTIMPL; } + STDMETHOD(OnProgress)(/* [in] */ ULONG ulProgress,/* [in] */ ULONG ulProgressMax,/* [in] */ ULONG ulStatusCode,/* [in] */ LPCWSTR wszStatusText) + { + if (m_dwWhenToTimeout > 0 && m_dwWhenToTimeout < GetTickCount()) + return E_ABORT; + return S_OK; + } + + STDMETHOD(OnStopBinding)(/* [in] */ HRESULT hresult,/* [unique][in] */ LPCWSTR szError) { return E_NOTIMPL; } + STDMETHOD(GetBindInfo)(/* [out] */ DWORD __RPC_FAR *grfBINDF,/* [unique][out][in] */ BINDINFO __RPC_FAR *pbindinfo) { return E_NOTIMPL; } + STDMETHOD(OnDataAvailable)(/* [in] */ DWORD grfBSCF,/* [in] */ DWORD dwSize,/* [in] */ FORMATETC __RPC_FAR *pformatetc,/* [in] */ STGMEDIUM __RPC_FAR *pstgmed) { return E_NOTIMPL; } + STDMETHOD(OnObjectAvailable)(/* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown __RPC_FAR *punk) { return E_NOTIMPL; } + STDMETHOD_(ULONG,AddRef)() { return 0; } + STDMETHOD_(ULONG,Release)() { return 0; } + STDMETHOD(QueryInterface)( /* [in] */ REFIID riid, /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) { return E_NOTIMPL; } +}; + +AgDownload::AgDownload() +{ + +} + +AgDownload::~AgDownload() +{ + +} + +void AgDownload::DownloadFile(const char* pszURL, const char* pszSaveAs) +{ + AgDownloadCallBack callback(GetTickCount() + 7000); + HRESULT hr = URLDownloadToFile(NULL, pszURL, pszSaveAs, 0, &callback); + + if (SUCCEEDED(hr)) + { + ConsolePrint("Download completed successfully!\n"); + } + else + { + char szMsg[512]; + LPTSTR lpszErrorMessage; + + if (FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, hr, + MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpszErrorMessage, 0, NULL)) + { + sprintf(szMsg, "Download failed. Error = 0x%08lX\n\n%s\n", (DWORD)hr, lpszErrorMessage); + LocalFree(lpszErrorMessage); + } + else + { + sprintf(szMsg,"Download failed. Error = 0x%08lX\n\nNo message available.\n", (DWORD)hr); + } + + ConsolePrint(szMsg); + } + +} diff --git a/cl_dll/aghl/agdownload.h b/cl_dll/aghl/agdownload.h new file mode 100644 index 00000000..73c9bb22 --- /dev/null +++ b/cl_dll/aghl/agdownload.h @@ -0,0 +1,22 @@ +// AgDownload.h: interface for the AgDownload class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_AGDOWNLOAD_H__67A39740_D747_4453_AC71_32320604FAAB__INCLUDED_) +#define AFX_AGDOWNLOAD_H__67A39740_D747_4453_AC71_32320604FAAB__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgDownload +{ +public: + AgDownload(); + virtual ~AgDownload(); + + void DownloadFile(const char* pszURL, const char* pszSaveAs); + +}; + +#endif // !defined(AFX_AGDOWNLOAD_H__67A39740_D747_4453_AC71_32320604FAAB__INCLUDED_) diff --git a/cl_dll/aghl/agglobal.h b/cl_dll/aghl/agglobal.h new file mode 100644 index 00000000..aa99db55 --- /dev/null +++ b/cl_dll/aghl/agglobal.h @@ -0,0 +1,55 @@ +//++ BulliT + + +#if !defined(_AG_GLOBAL_) +#define _AG_GLOBAL_ + +#pragma warning(disable:4786) +#pragma warning(disable:4710) +#pragma warning(disable:4511) +#pragma warning(disable:4512) +#pragma warning(disable:4514) +#pragma warning(disable:4663) +#pragma warning(disable:4711) +#pragma warning(disable:4710) +#pragma warning(disable:4100) + +#include +#define NOWINRES +#define NOIME +#define _WIN32_WINNT 0x0400 +#include + +#define _bool_h 1 +#include +#include +#include +#include +#include +#include +typedef string AgString; +typedef list AgStringList; +typedef set > AgStringSet; + +void AgInitClientDll(); +int AgDrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ); +int AgDrawHudStringCentered(int xpos, int ypos, int iMaxX, const char *szIt, int r, int g, int b ); +int AgDrawConsoleString( int x, int y, const char *string, float r = 0, float g = 0, float b = 0 ); +void AgSetTextColor(int r, int g, int b); +void AgStripColors(char* pszString); +void AgDirList(const AgString& sDir, AgStringSet& setFiles); + +AgString AgMapname(); +void AgTrim(AgString& sTrim); +void AgLog(const char* pszLog); +void AgToLower(AgString& strLower); + +void AgUpdateHudColor(); +void AgGetHudColor(int &r, int &g, int &b); + +const char* AgGetGame(); +const char* AgGetDirectory(); +const char* AgGetDirectoryValve(); + +#endif _AG_GLOBAL_ +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudcountdown.cpp b/cl_dll/aghl/aghudcountdown.cpp new file mode 100644 index 00000000..37fa7d0e --- /dev/null +++ b/cl_dll/aghl/aghudcountdown.cpp @@ -0,0 +1,137 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" +#include "agglobal.h" + +DECLARE_MESSAGE(m_Countdown, Countdown ) + + +int AgHudCountdown::Init(void) +{ + HOOK_MESSAGE( Countdown ); + + m_btCountdown = -1; + m_iFlags = 0; + gHUD.AddHudElem(this); + + return 1; +}; + +int AgHudCountdown::VidInit(void) +{ + + return 1; +}; + +void AgHudCountdown::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; + m_btCountdown = -1; +} + +#define RGB_WHITEISH 0x00FFFFFF //255,255,255 + +int AgHudCountdown::Draw(float fTime) +{ + if (gHUD.m_iIntermission) + return 0; + + char szText[128]; + szText[0] = '\0'; + int r, g, b; + UnpackRGB(r,g,b, RGB_YELLOWISH); + if (50 != m_btCountdown) + { + int iWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + //int iHeight = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top; + + gHUD.DrawHudNumber( ScreenWidth / 2 - iWidth/2, gHUD.m_scrinfo.iCharHeight*10, DHN_DRAWZERO , m_btCountdown, r, g, b); + if (0 != strlen(m_szPlayer1) && 0 != strlen(m_szPlayer2)) + { + sprintf(szText,"%s vs %s",m_szPlayer1,m_szPlayer2); + //Write arena text. + AgDrawHudStringCentered(ScreenWidth / 2, gHUD.m_scrinfo.iCharHeight*7,ScreenWidth,szText,r,g,b); + } + else + { + //Write match text. + strcpy(szText,"Match about to start"); + AgDrawHudStringCentered(ScreenWidth / 2, gHUD.m_scrinfo.iCharHeight*7,ScreenWidth,szText,r,g,b); + } + } + else + { + if (0 != strlen(m_szPlayer1)) + { + sprintf(szText,"Last round won by %s",m_szPlayer1); + AgDrawHudStringCentered(ScreenWidth / 2 , gHUD.m_scrinfo.iCharHeight*7 ,ScreenWidth,szText,r,g,b); + } + else + { + strcpy(szText,"Waiting for players to get ready"); + AgDrawHudStringCentered(ScreenWidth / 2 , gHUD.m_scrinfo.iCharHeight*7 ,ScreenWidth,szText,r,g,b); + } + + } + + return 0; +} + + +int AgHudCountdown::MsgFunc_Countdown(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + //Update data + m_btCountdown = READ_BYTE(); + char btSound = READ_BYTE(); + strcpy(m_szPlayer1,READ_STRING()); + strcpy(m_szPlayer2,READ_STRING()); + + if (0 <= m_btCountdown) + { + m_iFlags |= HUD_ACTIVE; + + if (btSound) + { + //Play countdown sound + if (0 == m_btCountdown) + { + gEngfuncs.pfnPlaySoundByName("barney/ba_bring.wav",1); + } + else if (1 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/one.wav",1); + else if (2 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/two.wav",1); + else if (3 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/three.wav",1); + else if (4 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/four.wav",1); + else if (5 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/five.wav",1); + else if (6 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/six.wav",1); + else if (7 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/seven.wav",1); + else if (8 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/eight.wav",1); + else if (9 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/nine.wav",1); + else if (10 == m_btCountdown) + gEngfuncs.pfnPlaySoundByName("fvox/ten.wav",1); + } + } + else + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} + + + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudcountdown.h b/cl_dll/aghl/aghudcountdown.h new file mode 100644 index 00000000..0e578f54 --- /dev/null +++ b/cl_dll/aghl/aghudcountdown.h @@ -0,0 +1,23 @@ +//++ BulliT + +#if !defined(_AG_COUNTDOWN_HUD_) +#define _AG_COUNTDOWN_HUD_ + +class AgHudCountdown: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_Countdown(const char *pszName, int iSize, void *pbuf); + +private: + char m_btCountdown; + char m_szPlayer1[32]; + char m_szPlayer2[32]; +}; + +#endif //_AG_COUNTDOWN_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudctf.cpp b/cl_dll/aghl/aghudctf.cpp new file mode 100644 index 00000000..2ebc31e3 --- /dev/null +++ b/cl_dll/aghl/aghudctf.cpp @@ -0,0 +1,159 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ScorePanel.h" + +DECLARE_MESSAGE(m_CTF, CTF ) +DECLARE_MESSAGE(m_CTF, CTFSound ) +DECLARE_MESSAGE(m_CTF, CTFFlag ) + +int g_iPlayerFlag1 = 0; +int g_iPlayerFlag2 = 0; + + +int AgHudCTF::Init(void) +{ + HOOK_MESSAGE( CTF ); + HOOK_MESSAGE( CTFSound ); + HOOK_MESSAGE( CTFFlag ); + + m_iFlags = 0; + m_iFlagStatus1 = 0; + m_iFlagStatus2 = 0; + g_iPlayerFlag1 = 0; + g_iPlayerFlag2 = 0; + + + gHUD.AddHudElem(this); + return 1; +}; + +int AgHudCTF::VidInit(void) +{ + int iSprite = 0; + iSprite = gHUD.GetSpriteIndex("icon_ctf_home"); + m_IconFlagStatus[Home].spr = gHUD.GetSprite(iSprite); + m_IconFlagStatus[Home].rc = gHUD.GetSpriteRect(iSprite); + + iSprite = gHUD.GetSpriteIndex("icon_ctf_stolen"); + m_IconFlagStatus[Stolen].spr = gHUD.GetSprite(iSprite); + m_IconFlagStatus[Stolen].rc = gHUD.GetSpriteRect(iSprite); + + iSprite = gHUD.GetSpriteIndex("icon_ctf_lost"); + m_IconFlagStatus[Lost].spr = gHUD.GetSprite(iSprite); + m_IconFlagStatus[Lost].rc = gHUD.GetSpriteRect(iSprite); + + iSprite = gHUD.GetSpriteIndex("icon_ctf_carry"); + m_IconFlagStatus[Carry].spr = gHUD.GetSprite(iSprite); + m_IconFlagStatus[Carry].rc = gHUD.GetSpriteRect(iSprite); + + m_iFlagStatus1 = 0; + m_iFlagStatus2 = 0; + g_iPlayerFlag1 = 0; + g_iPlayerFlag2 = 0; + + return 1; +} + +void AgHudCTF::Reset(void) +{ + if (CTF != AgGametype() || gHUD.m_iIntermission) + m_iFlags &= ~HUD_ACTIVE; +} + +int AgHudCTF::Draw(float fTime) +{ + if (m_iFlagStatus1 == Off + ||m_iFlagStatus2 == Off || gHUD.m_iIntermission) + { + Reset(); + return 0; + } + + int x = 30; + int y = ScreenHeight / 2; + + //Draw Blue + if (m_IconFlagStatus[m_iFlagStatus1].spr) + { + SPR_Set(m_IconFlagStatus[m_iFlagStatus1].spr, iTeamColors[1][0], iTeamColors[1][1], iTeamColors[1][2]); + int yBlue = y - ((m_IconFlagStatus[m_iFlagStatus2].rc.bottom - m_IconFlagStatus[m_iFlagStatus2].rc.top) + 5); + SPR_DrawAdditive( 0, x, yBlue, &m_IconFlagStatus[m_iFlagStatus1].rc ); + } + //Draw Red + if (m_IconFlagStatus[m_iFlagStatus2].spr) + { + //y += (m_IconFlagStatus[m_iFlagStatus2].rc.bottom - m_IconFlagStatus[m_iFlagStatus2].rc.top) + 5; + SPR_Set(m_IconFlagStatus[m_iFlagStatus2].spr, iTeamColors[2][0], iTeamColors[2][1], iTeamColors[2][2]); + SPR_DrawAdditive( 0, x, y, &m_IconFlagStatus[m_iFlagStatus2].rc ); + } + + return 0; +} + + +int AgHudCTF::MsgFunc_CTF(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + m_iFlagStatus1 = READ_BYTE(); + m_iFlagStatus2 = READ_BYTE(); + + if (m_iFlagStatus1 != Off + &&m_iFlagStatus2 != Off) + m_iFlags |= HUD_ACTIVE; + else + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} + +static char* s_szSounds[] = +{ + "ctf/youhaveflag.wav", + "ctf/teamhaveflag.wav", + "ctf/enemyhaveflag.wav", + "ctf/blueflagreturned.wav", + "ctf/redflagreturned.wav", + "ctf/bluescores.wav", + "ctf/redscores.wav", + "ctf/blueflagstolen.wav", + "ctf/redflagstolen.wav", + //Not used but can be good to have... + "ctf/blueleads", + "ctf/redleads", + "ctf/teamstied", + "ctf/suddendeath", + "ctf/stolen" + "ctf/capture" +}; + +extern cvar_t* g_pcl_ctf_volume; +int AgHudCTF::MsgFunc_CTFSound(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + int iSound = READ_BYTE(); + if (iSound >= 0 && iSound < sizeof(s_szSounds)/sizeof(s_szSounds[0])) + gEngfuncs.pfnPlaySoundByName( s_szSounds[iSound], g_pcl_ctf_volume->value); + return 1; +} + + +int AgHudCTF::MsgFunc_CTFFlag(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + g_iPlayerFlag1 = READ_BYTE(); + g_iPlayerFlag2 = READ_BYTE(); + return 1; +} + + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudctf.h b/cl_dll/aghl/aghudctf.h new file mode 100644 index 00000000..c5733c86 --- /dev/null +++ b/cl_dll/aghl/aghudctf.h @@ -0,0 +1,35 @@ +//++ BulliT + +#if !defined(_AG_CTF_HUD_) +#define _AG_CTF_HUD_ + + +class AgHudCTF: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_CTF(const char *pszName, int iSize, void *pbuf); + int MsgFunc_CTFSound(const char *pszName, int iSize, void *pbuf); + int MsgFunc_CTFFlag(const char *pszName, int iSize, void *pbuf); + +private: + typedef struct + { + + HSPRITE spr; + wrect_t rc; + } icon_flagstatus_t; + icon_flagstatus_t m_IconFlagStatus[4]; + enum enumFlagStatus { Off = -1, Home = 0, Stolen = 1, Lost = 2, Carry = 3}; + int m_iFlagStatus1; + int m_iFlagStatus2; +}; + +extern int g_iPlayerFlag1; +extern int g_iPlayerFlag2; +#endif //_AG_CTF_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudcustomtimer.cpp b/cl_dll/aghl/aghudcustomtimer.cpp new file mode 100644 index 00000000..e0fad18d --- /dev/null +++ b/cl_dll/aghl/aghudcustomtimer.cpp @@ -0,0 +1,67 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudCustomTimer.h" + +DECLARE_COMMAND(m_CustomTimer, CustomTimer); + +int AgHudCustomTimer::Init(void) +{ + m_flTurnoff = 0; + m_iFlags = 0; + + gHUD.AddHudElem(this); + + HOOK_COMMAND("customtimer",CustomTimer); + + return 1; +}; + +int AgHudCustomTimer::VidInit(void) +{ + return 1; +}; + +void AgHudCustomTimer::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; +} + +int AgHudCustomTimer::Draw(float fTime) +{ + if (m_flTurnoff < gHUD.m_flTime || gHUD.m_iIntermission) + { + gEngfuncs.pfnPlaySoundByName("fvox/bell.wav",1); + Reset(); + return 1; + } + + char szText[32]; + int r, g, b; + UnpackRGB(r,g,b, RGB_GREENISH); + + sprintf(szText,"Timer %d",(int)(m_flTurnoff - gHUD.m_flTime)); + AgDrawHudStringCentered(ScreenWidth / 2, gHUD.m_scrinfo.iCharHeight*4 ,ScreenWidth,szText,r,g,b); + + return 0; +} + +void AgHudCustomTimer::UserCmd_CustomTimer() +{ + if (2 == gEngfuncs.Cmd_Argc()) + { + m_flTurnoff = gHUD.m_flTime + atof(gEngfuncs.Cmd_Argv(1)); + m_iFlags |= HUD_ACTIVE; + } +} + + + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudcustomtimer.h b/cl_dll/aghl/aghudcustomtimer.h new file mode 100644 index 00000000..a3c848ed --- /dev/null +++ b/cl_dll/aghl/aghudcustomtimer.h @@ -0,0 +1,23 @@ +//++ BulliT + +#if !defined(_AG_CUSTOMTIMER_HUD_) +#define _AG_CUSTOMTIMER_HUD_ + +class AgHudCustomTimer: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + +private: + float m_flTurnoff; + +public: + void UserCmd_CustomTimer(); +}; + +#endif //_AG_CUSTOMTIMER_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudglobal.cpp b/cl_dll/aghl/aghudglobal.cpp new file mode 100644 index 00000000..386c3a6b --- /dev/null +++ b/cl_dll/aghl/aghudglobal.cpp @@ -0,0 +1,417 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "event_api.h" +#include +#include +#include +#include "com_weapons.h" +#include "parsemsg.h" +#include "demo.h" +#include "demo_api.h" +#include "agglobal.h" +#include "aghudglobal.h" +#include "agmodelcheck.h" + +#ifdef AG_USE_CHEATPROTECTION +#include "agwallhack.h" +#include "agcrc32enforcer.h" +#endif + +#include "AgVariableChecker.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ScorePanel.h" +#include "AgVGuiMapBrowser.h" +#include "AgDownload.h" + +DECLARE_MESSAGE(m_Global, PlaySound ) +DECLARE_MESSAGE(m_Global, CheatCheck ) +DECLARE_MESSAGE(m_Global, WhString ) +DECLARE_MESSAGE(m_Global, SpikeCheck ) +DECLARE_MESSAGE(m_Global, Gametype ) +DECLARE_MESSAGE(m_Global, AuthID ) +DECLARE_MESSAGE(m_Global, MapList ) +DECLARE_MESSAGE(m_Global, CRC32 ) +DECLARE_COMMAND(m_Global, Winamp); +DECLARE_COMMAND(m_Global, ToggleWinamp); +DECLARE_COMMAND(m_Global, ToggleMapBrowser); +DECLARE_COMMAND(m_Global, LoadAuthID); +DECLARE_COMMAND(m_Global, UnloadAuthID); +DECLARE_COMMAND(m_Global, AgRecord); + +int g_iPure = 1; +BYTE g_GameType = STANDARD; + +typedef map > AgPlayerToAuthID; +typedef map > AgAuthIDToRealName; +static AgPlayerToAuthID s_mapAuthID; +static AgAuthIDToRealName s_mapRealName; + + +static int s_iCheckWallhack = 0; +extern cvar_t* g_pcl_scores; +int AgHudGlobal::Init(void) +{ + m_iFlags = 0; + + gHUD.AddHudElem(this); + + HOOK_MESSAGE( PlaySound ); + HOOK_MESSAGE( CheatCheck ); + HOOK_MESSAGE( WhString ); + HOOK_MESSAGE( SpikeCheck ); + HOOK_MESSAGE( Gametype ); + HOOK_MESSAGE( AuthID ); + HOOK_MESSAGE( MapList ); + HOOK_MESSAGE( CRC32 ); + HOOK_COMMAND("winamp",Winamp); + HOOK_COMMAND("togglewinamp",ToggleWinamp); + HOOK_COMMAND("togglemapbrowser",ToggleMapBrowser); + HOOK_COMMAND("loadauthid",LoadAuthID); + HOOK_COMMAND("unloadauthid",UnloadAuthID); + HOOK_COMMAND("agrecord",AgRecord); + return 1; +}; + +int AgHudGlobal::VidInit(void) +{ + if (!gEngfuncs.pDemoAPI->IsRecording()) + s_mapAuthID.clear(); + return 1; +}; + +void AgHudGlobal::Reset(void) +{ + m_iFlags |= HUD_ACTIVE; + m_fCheckColor = 0; +} + +int iOverLay = 0; + +int AgHudGlobal::Draw(float fTime) +{ + if (m_fCheckColor < gHUD.m_flTime) + { + AgUpdateHudColor(); + m_fCheckColor = gHUD.m_flTime + 1; //every second + } + if (g_pcl_scores->value < 1) + return 1; + + int xpos, ypos; + xpos = 30; + ypos = 50; + sscanf(CVAR_GET_STRING("cl_scores_pos"), "%i %i", &xpos, &ypos); + + int r,g,b; + + if (gViewPort && gViewPort->m_pScoreBoard) + { + for (int iRow = 0, iLines = 0; iRow < gViewPort->m_pScoreBoard->m_iRows && iLines < g_pcl_scores->value; iRow++) + { + if (gViewPort->m_pScoreBoard->m_iIsATeam[iRow] == 1 && gHUD.m_Teamplay) + { + char szScore[64]; + team_info_t* team_info = &g_TeamInfo[gViewPort->m_pScoreBoard->m_iSortedRows[iRow]]; + sprintf(szScore,"%-5i %s",team_info->frags,team_info->name); + + r = iTeamColors[team_info->teamnumber % iNumberOfTeamColors][0]; + g = iTeamColors[team_info->teamnumber % iNumberOfTeamColors][1]; + b = iTeamColors[team_info->teamnumber % iNumberOfTeamColors][2]; + + FillRGBA( xpos - 10, ypos + 2 , iOverLay, gHUD.m_scrinfo.iCharHeight * 0.9, r, g, b, 20 ); + + ScaleColors(r,g,b,135); + + int ixposnew = gHUD.DrawHudString( xpos, ypos, ScreenWidth, szScore, r, g, b ); + iOverLay = max(ixposnew - xpos + 20,iOverLay); + ypos += gHUD.m_scrinfo.iCharHeight * 0.9; + iLines++; + } + else if (gViewPort->m_pScoreBoard->m_iIsATeam[iRow] == 0 && !gHUD.m_Teamplay) + { + char szScore[64]; + hud_player_info_t* pl_info = &g_PlayerInfoList[gViewPort->m_pScoreBoard->m_iSortedRows[iRow]]; + extra_player_info_t* pl_info_extra = &g_PlayerExtraInfo[gViewPort->m_pScoreBoard->m_iSortedRows[iRow]]; + sprintf(szScore,"%-5i %s",pl_info_extra->frags,pl_info->name); + + r = iTeamColors[pl_info_extra->teamnumber % iNumberOfTeamColors][0]; + g = iTeamColors[pl_info_extra->teamnumber % iNumberOfTeamColors][1]; + b = iTeamColors[pl_info_extra->teamnumber % iNumberOfTeamColors][2]; + + FillRGBA( xpos - 10, ypos + 2, iOverLay, gHUD.m_scrinfo.iCharHeight * 0.9, r, g, b, 10 ); + + ScaleColors(r,g,b,135); + + int ixposnew = gHUD.DrawHudString( xpos, ypos, ScreenWidth, szScore, r, g, b ); + iOverLay = max(ixposnew - xpos + 20,iOverLay); + ypos += gHUD.m_scrinfo.iCharHeight * 0.9; + iLines++; + } + } + } + return 1; +} + + +int AgHudGlobal::MsgFunc_PlaySound(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + vec3_t origin; + /*int iPlayer = */READ_BYTE(); + for ( int i = 0 ; i < 3 ; i++) + origin[i] = READ_COORD(); + char* pszSound = READ_STRING(); + + gEngfuncs.pfnPlaySoundByName( pszSound, 1); + //this does not work - gEngfuncs.pfnPlaySoundByNameAtLocation( pszSound, 1, origin); + + //gEngfuncs.pEventAPI->EV_PlaySound( -1, origin, 0, pszName, 1.0, ATTN_NORM, 0, PITCH_NORM ); + + return 1; +} + +extern bool AgCRC32EnforceFiles(); + +int AgHudGlobal::MsgFunc_CheatCheck(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + int iPure = READ_BYTE(); + + g_iPure = iPure; + +#ifdef AG_USE_CHEATPROTECTION + if (0 < g_iPure) + AgCRC32EnforceFiles(); + + g_VariableChecker.Activate(); + + DWORD dwTime = GetTickCount(); + +#ifdef _DEBUG + AgLog( "Checking for spikes\n" ); +#endif //_DEBUG + if (!g_ModelCheck.Check()) + return 1; + + if (s_iCheckWallhack) + { +#ifdef AG_USE_CHEATPROTECTION +#ifdef _DEBUG + AgLog( "Checking for wallhack\n" ); +#endif //_DEBUG + if (!g_Wallhack.Check()) + return 1; +#endif + } + +#ifdef _DEBUG + char szTime[64]; + sprintf(szTime,"Cheat check took %dms\n",int((GetTickCount() - dwTime))); + ConsolePrint(szTime); + AgLog(szTime); +#endif + +#endif //AG_USE_CHEATPROTECTION + + return 1; +} + + +int AgHudGlobal::MsgFunc_WhString(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); +#ifdef AG_USE_CHEATPROTECTION + g_Wallhack.AddBadStrings(READ_STRING()); +#else + READ_STRING(); +#endif + s_iCheckWallhack = 1; + return 1; +} + +int AgHudGlobal::MsgFunc_SpikeCheck(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); +#ifdef AG_USE_CHEATPROTECTION + g_ModelCheck.CheckOne(READ_STRING()); +#else + READ_STRING(); +#endif + return 1; +} + +int AgHudGlobal::MsgFunc_Gametype(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + g_GameType = READ_BYTE(); + return 1; +} + +int AgHudGlobal::MsgFunc_AuthID(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + int iPlayer = READ_BYTE(); + AgString sAuthID = READ_STRING(); + + int iCutId = sAuthID.find("_"); + if (-1 != iCutId) + sAuthID = sAuthID.substr(iCutId+1); + + AgPlayerToAuthID::iterator itrAuthID = s_mapAuthID.find(iPlayer); + if (itrAuthID == s_mapAuthID.end()) + s_mapAuthID.insert(AgPlayerToAuthID::value_type(iPlayer,sAuthID)); + else + (*itrAuthID).second = sAuthID; + + return 1; +} + +int AgHudGlobal::MsgFunc_MapList( const char *pszName, int iSize, void *pbuf ) +{ + if (gViewPort && gViewPort->m_pMapBrowser) + return gViewPort->m_pMapBrowser->MsgFunc_MapList( pszName, iSize, pbuf ); + return 1; +} + +int AgHudGlobal::MsgFunc_CRC32( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + int iCheckSum = READ_LONG(); +#ifdef AG_USE_CHEATPROTECTION + AgCRC32EnforceFile(READ_STRING(), iCheckSum); +#else + READ_STRING(); +#endif + return 1; +} + +void AgHudGlobal::UserCmd_Winamp() +{ + gViewPort->UserCmd_Winamp(); +} + +void AgHudGlobal::UserCmd_ToggleWinamp() +{ + gViewPort->ToggleWinamp(); +} + +void AgHudGlobal::UserCmd_ToggleMapBrowser() +{ + gViewPort->ToggleMapBrowser(); +} + +void AgHudGlobal::UserCmd_LoadAuthID() +{ + char* pszFileName = "realnames.txt"; + if (gEngfuncs.Cmd_Argc() == 2) + { + char szSaveAs[MAX_PATH]; + AgString sUrl = gEngfuncs.Cmd_Argv(1); + sprintf(szSaveAs,"%s/%s",AgGetDirectory(),pszFileName); + sUrl = "http://" + sUrl; + AgDownload download; + download.DownloadFile(sUrl.c_str(), szSaveAs); + } + + int iFilePos = 0, iFileSize = 0; + char* pFile = (char*)gEngfuncs.COM_LoadFile(pszFileName, 5, NULL); + if (!pFile) + { + char szMessage[256]; + sprintf(szMessage, "Could not load file %s\n", pszFileName); + ConsolePrint(szMessage); + return; + } + AgString sRealNames(pFile); + gEngfuncs.COM_FreeFile(pFile); + + int iPosNewLine = sRealNames.find_first_of("\n"); + while (-1 != iPosNewLine) + { + AgString sAuthID, sRealName; + int iPosRealName = sRealNames.find_first_of(" \t"); + sAuthID = sRealNames.substr(0,iPosRealName); + sRealName = sRealNames.substr(iPosRealName+1,min(32,iPosNewLine - iPosRealName)); + + AgTrim(sAuthID); + AgTrim(sRealName); + + if ("//" != sAuthID.substr(0,2)) + { + if (sAuthID.size() && sRealName.size()) + s_mapRealName.insert(AgAuthIDToRealName::value_type(sAuthID, sRealName)); + } + else + { + AgString sComment = sRealNames.substr(2,iPosNewLine-2); + AgTrim(sComment); + sComment += "\n"; + ConsolePrint(sComment.c_str()); + } + + sRealNames = sRealNames.substr(iPosNewLine+1); + iPosNewLine = sRealNames.find_first_of("\n"); + } + + char szCount[64]; + sprintf(szCount,"Loaded auth id's - %d\n",(int)s_mapRealName.size()); + ConsolePrint(szCount); +} + +void AgHudGlobal::UserCmd_UnloadAuthID() +{ + ConsolePrint("Unloaded all auth id's\n"); + s_mapRealName.clear(); +} + +AgString AgGetAuthID(int iPlayer) +{ + AgPlayerToAuthID::iterator itrAuthID = s_mapAuthID.find(iPlayer); + if (itrAuthID != s_mapAuthID.end()) + { + return (*itrAuthID).second; + } + return ""; +} + +AgString AgGetRealName(int iPlayer) +{ + if (s_mapRealName.size()) + { + AgString sRealName; + AgPlayerToAuthID::iterator itrAuthID = s_mapAuthID.find(iPlayer); + if (itrAuthID != s_mapAuthID.end()) + { + AgAuthIDToRealName::iterator itrRealName = s_mapRealName.find((*itrAuthID).second); + if (itrRealName != s_mapRealName.end()) + return (*itrRealName).second; + } + } + return g_PlayerInfoList[iPlayer].name; +} + +void AgHudGlobal::UserCmd_AgRecord() +{ + time_t t_now; + time(&t_now); + struct tm* now = localtime(&t_now); + now->tm_year += 1900; + + char szExtra[128]; + if (gEngfuncs.Cmd_Argc() == 2) + sprintf(szExtra, "_%s",gEngfuncs.Cmd_Argv(1)); + else + szExtra[0] = '\0'; + + char szCMD[128]; + sprintf(szCMD, "record %04d%02d%02d_%02d%02d%02d_%s%s\n",now->tm_year, now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec, AgMapname().c_str(), szExtra); + ClientCmd(szCMD); +} + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudglobal.h b/cl_dll/aghl/aghudglobal.h new file mode 100644 index 00000000..a1a8fc23 --- /dev/null +++ b/cl_dll/aghl/aghudglobal.h @@ -0,0 +1,43 @@ +//++ BulliT + +#if !defined(_AG_GLOBAL_HUD_) +#define _AG_GLOBAL_HUD_ + +class AgHudGlobal: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_PlaySound(const char *pszName, int iSize, void *pbuf); + int MsgFunc_CheatCheck(const char *pszName, int iSize, void *pbuf); + int MsgFunc_WhString(const char *pszName, int iSize, void *pbuf); + int MsgFunc_SpikeCheck(const char *pszName, int iSize, void *pbuf); + int MsgFunc_Gametype(const char *pszName, int iSize, void *pbuf); + int MsgFunc_AuthID(const char *pszName, int iSize, void *pbuf); + int MsgFunc_MapList(const char *pszName, int iSize, void *pbuf); + int MsgFunc_CRC32(const char *pszName, int iSize, void *pbuf); + void UserCmd_Winamp(); + void UserCmd_ToggleWinamp(); + void UserCmd_ToggleMapBrowser(); + void UserCmd_LoadAuthID(); + void UserCmd_UnloadAuthID(); + void UserCmd_AgRecord(); +protected: + float m_fCheckColor; +}; + +enum enumGameType { STANDARD = 0, ARENA = 1, LMS = 2, CTF = 3, ARCADE = 4, SGBOW = 5, INSTAGIB = 6}; +extern BYTE g_GameType; +inline BYTE AgGametype() +{ + return g_GameType; +}; + +AgString AgGetAuthID(int iPlayer); +AgString AgGetRealName(int iPlayer); + +#endif //_AG_GLOBAL_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudirc.cpp b/cl_dll/aghl/aghudirc.cpp new file mode 100644 index 00000000..e24a689d --- /dev/null +++ b/cl_dll/aghl/aghudirc.cpp @@ -0,0 +1,194 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudirc.h" +#include "vgui_TeamFortressViewport.h" + +DECLARE_COMMAND(m_IRC, IRCConnect); +DECLARE_COMMAND(m_IRC, IRCConnect2); +DECLARE_COMMAND(m_IRC, IRCDisconnect); +DECLARE_COMMAND(m_IRC, IRCCommand); +DECLARE_COMMAND(m_IRC, IRCToggle); + +extern irc::CIrcSession g_ircSession; +extern cvar_t* g_pirc_server; +extern cvar_t* g_pirc_nick; +extern cvar_t* g_pirc_port; +extern cvar_t* g_pirc_userid; +extern cvar_t* g_pirc_password; +extern cvar_t* g_pirc_fullname; + +AgIRC* g_pIRC = NULL; + +int AgHudIRC::Init(void) +{ + m_iFlags = 0; + + gHUD.AddHudElem(this); + + HOOK_COMMAND("IRCConnect",IRCConnect); + HOOK_COMMAND("IRCConnect2",IRCConnect2); + HOOK_COMMAND("IRCDisconnect",IRCDisconnect); + HOOK_COMMAND("IRC",IRCCommand); + HOOK_COMMAND("toggleirc",IRCToggle); + + return 1; +}; + +int AgHudIRC::VidInit(void) +{ + return 1; +}; + +void AgHudIRC::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; +} + +int AgHudIRC::Draw(float fTime) +{ + return 0; +} + +void AgHudIRC::UserCmd_IRCConnect() +{ + IRCConnect(false); +} + +void AgHudIRC::UserCmd_IRCConnect2() +{ + IRCConnect(true); +} + + +void AgHudIRC::IRCConnect(bool bSilent) +{ + if (!gViewPort) + return; + + char szUser[UNLEN],szComputer[UNLEN]; + DWORD dwSize = UNLEN; + GetComputerName(szComputer,&dwSize); + szComputer[dwSize] = '\0'; + dwSize = UNLEN; + GetUserName(szUser,&dwSize); + szUser[dwSize] = '\0'; + + CIrcSessionInfo si; + + si.sServer = gEngfuncs.pfnGetCvarString("irc_server"); + si.iPort = gEngfuncs.pfnGetCvarFloat("irc_port"); + si.sNick = gEngfuncs.pfnGetCvarString("irc_nick"); + si.sUserID = gEngfuncs.pfnGetCvarString("irc_userid"); + si.sFullName = gEngfuncs.pfnGetCvarString("irc_fullname"); + si.sPassword = gEngfuncs.pfnGetCvarString("irc_password"); + si.bIdentServer = true; + si.iIdentServerPort = 113; + si.sIdentServerType = "UNIX"; + + if (0 == si.sNick.size()) + { + int iPlayer = gEngfuncs.GetLocalPlayer()->index; // Get the local player's index + si.sNick = gEngfuncs.PlayerInfo_ValueForKey(iPlayer,"name"); + si.sNick += "|AG"; + } + + if (0 == si.sUserID.size()) + { + si.sUserID = szComputer; + } + + if (0 == si.sFullName.size()) + { + si.sFullName = szUser; + } + + if (!bSilent) + { + if (gEngfuncs.Cmd_Argc() > 1) + si.sServer = gEngfuncs.Cmd_Argv(1); + + if (gEngfuncs.Cmd_Argc() > 2) + si.iPort = atoi(gEngfuncs.Cmd_Argv(2)); + + if (gEngfuncs.Cmd_Argc() > 3) + si.sNick = gEngfuncs.Cmd_Argv(3); + + if (gEngfuncs.Cmd_Argc() > 4) + si.sUserID = gEngfuncs.Cmd_Argv(4); + + if (gEngfuncs.Cmd_Argc() > 5) + si.sFullName = gEngfuncs.Cmd_Argv(5); + + if (gEngfuncs.Cmd_Argc() > 6) + si.sPassword = gEngfuncs.Cmd_Argv(6); + } + + if (g_pIRC) + { + g_pIRC->Disconnect("http://www.planethalflife.com/agmod"); + } + else + g_pIRC = new AgIRC(); + + if (bSilent) + g_pIRC->SilentMode(); + + g_pIRC->Connect(&si); +} + +void AgHudIRC::UserCmd_IRCDisconnect() +{ + if (!gViewPort) + return; + if (!g_pIRC) + return; + g_pIRC->Disconnect("http://www.planethalflife.com/agmod"); + delete g_pIRC; + g_pIRC = NULL; +} + +void AgHudIRC::UserCmd_IRCCommand() +{ + if (!gViewPort) + return; + if (!g_pIRC) + return; + + AgString sCommand; + + for (int i = 1; i < gEngfuncs.Cmd_Argc(); i++ ) + { + const char *param = gEngfuncs.Cmd_Argv( i ); + if ( param ) + { + if (0 != sCommand.size()) + sCommand += " "; + sCommand += param; + } + } + + + g_pIRC->Command(sCommand); + +} + +void AgHudIRC::UserCmd_IRCToggle() +{ + if ( gViewPort ) + { + gViewPort->ToggleIRC(); + } +} + + + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudirc.h b/cl_dll/aghl/aghudirc.h new file mode 100644 index 00000000..76459f54 --- /dev/null +++ b/cl_dll/aghl/aghudirc.h @@ -0,0 +1,29 @@ +//++ BulliT + +#if !defined(_AG_IRC_HUD_) +#define _AG_IRC_HUD_ + +#include "irc.h" +#include "AgIRC.h" + +class AgHudIRC: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + + void IRCConnect(bool bSilent); + +public: + void UserCmd_IRCConnect(); + void UserCmd_IRCConnect2(); + void UserCmd_IRCDisconnect(); + void UserCmd_IRCCommand(); + void UserCmd_IRCToggle(); +}; + +#endif //_AG_IRC_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudlocation.cpp b/cl_dll/aghl/aghudlocation.cpp new file mode 100644 index 00000000..e9c0c1d9 --- /dev/null +++ b/cl_dll/aghl/aghudlocation.cpp @@ -0,0 +1,409 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudlocation.h" + + +DECLARE_MESSAGE(m_Location, Location ); +DECLARE_MESSAGE(m_Location, InitLoc ); +DECLARE_COMMAND(m_Location, OpenLocation ); +DECLARE_COMMAND(m_Location, CloseLocation ); +DECLARE_COMMAND(m_Location, AddLocation ); +DECLARE_COMMAND(m_Location, DeleteLocation ); +DECLARE_COMMAND(m_Location, ShowLocations ); + +Vector vPlayerLocations[MAX_PLAYERS+1]; + +int AgHudLocation::Init(void) +{ + m_fAt = 0; + m_fNear = 0; + m_iFlags = 0; + m_szMap[0] = '\0'; + + for (int i = 1; i <= MAX_PLAYERS; i++) + vPlayerLocations[i] = Vector(0,0,0); + + gHUD.AddHudElem(this); + + HOOK_MESSAGE( Location ); + HOOK_MESSAGE( InitLoc ); +#ifdef _DEBUG + HOOK_COMMAND("+location",OpenLocation); + HOOK_COMMAND("-location",CloseLocation); +#endif + HOOK_COMMAND("agaddloc",AddLocation); + HOOK_COMMAND("agdelloc",DeleteLocation); + HOOK_COMMAND("aglistloc",ShowLocations); + return 1; +}; + +AgHudLocation::~AgHudLocation() +{ + //Delete all. + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + delete *itrLocations; + m_lstLocations.clear(); +} + +int AgHudLocation::VidInit(void) +{ + return 1; +}; + +void AgHudLocation::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; +} + +int AgHudLocation::Draw(float fTime) +{ + cl_entity_t* pPlayer = gEngfuncs.GetLocalPlayer(); // Get the local player's index + int r, g, b; + UnpackRGB(r,g,b, RGB_GREENISH); + int iPos = 5; + for (int i = 1; i < gEngfuncs.GetMaxClients(); i++ ) + { + if (i == pPlayer->index) + continue; + + if ('\0' != g_PlayerExtraInfo[i].teamname[0] && + '\0' != g_PlayerExtraInfo[i].teamname[pPlayer->index] && + 0 == stricmp(g_PlayerExtraInfo[i].teamname, g_PlayerExtraInfo[pPlayer->index].teamname)) + { + //Show his location - it's a team m8. + char szText[128]; + sprintf(szText,"%s [%s]",g_PlayerInfoList[i].name,Location(vPlayerLocations[i]).c_str()); + gHUD.DrawHudString(ScreenWidth/20, ScreenHeight/8 + gHUD.m_scrinfo.iCharHeight*iPos,ScreenWidth,szText,r,g,b); + iPos++; + } + } + + return 5 != iPos; +} + + +void AgHudLocation::UserCmd_OpenLocation() +{ + m_iFlags |= HUD_ACTIVE; +} + +void AgHudLocation::UserCmd_CloseLocation() +{ + m_iFlags &= ~HUD_ACTIVE; +} + +void AgHudLocation::UserCmd_AddLocation() +{ + if (2 == gEngfuncs.Cmd_Argc()) + { + AgString sLocation = gEngfuncs.Cmd_Argv(1); + if (0 == sLocation.size()) + return; + + AgLocation* pLocation = new AgLocation; + pLocation->m_sLocation = sLocation; + //pLocation->m_vPosition = vPlayerLocations[gEngfuncs.GetLocalPlayer()->index]; + pLocation->m_vPosition = gEngfuncs.GetLocalPlayer()->attachment[0]; + + m_lstLocations.push_back(pLocation); + pLocation->Show(); + + Save(); + + char szMsg[128]; + sprintf(szMsg,"Added Location %s.\n",(const char*)sLocation.c_str()); + ConsolePrint(szMsg); + } +} + +void AgHudLocation::UserCmd_DeleteLocation() +{ + if (2 == gEngfuncs.Cmd_Argc()) + { + AgString sLocation = gEngfuncs.Cmd_Argv(1); + if (0 == sLocation.size()) + return; + + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + { + if (0 == stricmp((*itrLocations)->m_sLocation.c_str(),sLocation.c_str())) + { + char szMsg[128]; + sprintf(szMsg,"Deleted Location %s.\n",(const char*)sLocation.c_str()); + ConsolePrint(szMsg); + + AgLocation* pLocation = *itrLocations; + m_lstLocations.erase(itrLocations); + delete pLocation; + Save(); + break; + } + } + } +} + +void AgHudLocation::UserCmd_ShowLocations() +{ + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + { + char szMsg[128]; + sprintf(szMsg,"%s\n",(const char*)(*itrLocations)->m_sLocation.c_str()); + ConsolePrint(szMsg); + (*itrLocations)->Show(); + } +} + + +void AgHudLocation::InitDistances() +{ + if (2 > m_lstLocations.size()) + return; //No use. + + float fMinDistance = -1; + float fMaxdistance = 0; + + //Calculate max/min distance between all locations. + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + { + for (AgLocationList::iterator itr = m_lstLocations.begin() ;itr != m_lstLocations.end(); ++itr) + { + if (*itrLocations != *itr) + { + float fDistance = ((*itr)->m_vPosition - (*itrLocations)->m_vPosition).Length(); + + if (fDistance < fMinDistance || -1 == fMinDistance) + fMinDistance = fDistance; + + if (fDistance > fMaxdistance) + fMaxdistance = fDistance; + } + + } + } + + //Now calculate when you are at/near a location or at atleast when its closest. + m_fAt = fMinDistance / 2; //You are at a location if you are one fourth between to locations. + m_fNear = fMinDistance / 1.1; //Over halfway of the mindistance you are at the "side". +} + +bool AgHudLocation::NearestLocation(const Vector& vPosition, AgLocation*& pLocation, float& fNearestdistance) +{ + fNearestdistance = -1; + pLocation = NULL; + + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + { + float fDistance = (vPosition - (*itrLocations)->m_vPosition).Length(); + + if (fDistance < fNearestdistance || -1 == fNearestdistance) + { + fNearestdistance = fDistance; + pLocation = *itrLocations; + } + } + + return NULL != pLocation; +} + +extern cvar_t* g_pcl_location_keywords; + +AgString AgHudLocation::Location(const Vector& vLocation) +{ + AgString sLocation; + if (2 > m_lstLocations.size()) + return sLocation; + + AgLocation* pLocation = NULL; + float fNearestDistance = 0; + + if (NearestLocation(vLocation, pLocation, fNearestDistance)) + { + if (pLocation) + { + /* +#ifdef _DEBUG + pLocation->Show(); +#endif + */ + if (fNearestDistance < m_fAt || g_pcl_location_keywords->value < 1) + { + sLocation = pLocation->m_sLocation; + } + else if (fNearestDistance < m_fNear) + { + sLocation.append("Near "); + sLocation.append(pLocation->m_sLocation); + } + else + { + sLocation.append(pLocation->m_sLocation); + sLocation.append(" Side"); + } + } + } + + return sLocation; +} + +void AgHudLocation::Load() +{ + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + delete *itrLocations; + m_lstLocations.clear(); + + char szData[8196]; + + char szFile[MAX_PATH]; + sprintf(szFile,"%s/locs/%s.loc",AgGetDirectory(),m_szMap); + FILE* pFile = fopen(szFile,"r"); + if (!pFile) + { + // file error + char szMsg[128]; + sprintf(szMsg,"Couldn't open location file %s.\n",szFile); + ConsolePrint(szMsg); + return; + } + + enum enumParseState { Location, X, Y, Z }; + enumParseState ParseState = Location; + AgLocation* pLocation = new AgLocation; + int iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile); + if (0 >= iRead) + return; + szData[iRead] = '\0'; + + char* pszParse = NULL; + pszParse = strtok(szData, "#"); + if (pszParse) + { + while (pszParse) + { + if (Location == ParseState) + { + pLocation->m_sLocation = pszParse; + ParseState = X; + } + else if (X == ParseState) + { + pLocation->m_vPosition.x = atof(pszParse); + ParseState = Y; + } + else if (Y == ParseState) + { + pLocation->m_vPosition.y = atof(pszParse); + ParseState = Z; + } + else if (Z == ParseState) + { + pLocation->m_vPosition.z = atof(pszParse); + m_lstLocations.push_back(pLocation); + pLocation = new AgLocation; + ParseState = Location; + } + pszParse = strtok(NULL, "#"); + } + } + delete pLocation; + + fclose(pFile); + + InitDistances(); +} + +void AgHudLocation::Save() +{ + InitDistances(); + + if (0 == m_lstLocations.size()) + return; + + char szFile[MAX_PATH]; + sprintf(szFile,"%s/locs/%s.loc",AgGetDirectory(),m_szMap); + FILE* pFile = fopen(szFile,"wb"); + if (!pFile) + { + // file error + char szMsg[128]; + sprintf(szMsg,"Couldn't create/save location file %s.\n",szFile); + ConsolePrint(szMsg); + return; + } + + //Loop and write the file. + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + { + //Append. + AgLocation* pLocation = *itrLocations; + fprintf(pFile,"%s#%f#%f#%f#",(const char*)pLocation->m_sLocation.c_str(),pLocation->m_vPosition.x,pLocation->m_vPosition.y,pLocation->m_vPosition.z); + } + + fflush(pFile); + fclose(pFile); +} + + +void AgHudLocation::ParseAndEditSayString(char* pszSay, int iPlayer) +{ + //Make backup + char* pszText = (char*)malloc(strlen(pszSay)+1); + char* pszSayTemp = pszText; + strcpy(pszText,pszSay); + //Now parse for %L and edit it. + + while (*pszSayTemp) //Dont overflow the string. Stop when its 200 chars. + { + if ('%' == *pszSayTemp) + { + pszSayTemp++; + if ('l' == *pszSayTemp || 'L' == *pszSayTemp || 'd' == *pszSayTemp || 'D' == *pszSayTemp ) + { + //Location files. + pszSay = pszSay + sprintf(pszSay,Location(vPlayerLocations[iPlayer]).c_str()); + pszSayTemp++; + continue; + } + else + { + pszSay[0] = '%'; + pszSay++; + continue; + } + } + + *pszSay = *pszSayTemp; + pszSay++; + pszSayTemp++; + } + *pszSay = '\0'; + + free(pszText); +} + + +int AgHudLocation::MsgFunc_Location(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + vec3_t origin; + int iPlayer = READ_BYTE(); + for ( int i = 0 ; i < 3 ; i++) + vPlayerLocations[iPlayer][i] = READ_COORD(); + return 1; +} + +int AgHudLocation::MsgFunc_InitLoc(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + strcpy(m_szMap,READ_STRING()); + Load(); + return 1; +} + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudlocation.h b/cl_dll/aghl/aghudlocation.h new file mode 100644 index 00000000..42a0dee3 --- /dev/null +++ b/cl_dll/aghl/aghudlocation.h @@ -0,0 +1,51 @@ +//++ BulliT + +#if !defined(_AG_LOCATION_HUD_) +#define _AG_LOCATION_HUD_ +#include "aglocation.h" + +class AgHudLocation: public CHudBase +{ +public: + virtual ~AgHudLocation(); + + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + +private: + typedef list AgLocationList; + AgLocationList m_lstLocations; + float m_fAt; + float m_fNear; + + bool NearestLocation(const Vector& vPosition, AgLocation*& pLocation, float& fNearest); + + + void InitDistances(); + void Load(); + void Save(); + + AgString Location(const Vector& vPosition); + +public: + char m_szMap[32]; + + void ParseAndEditSayString(char* pszSay, int iPlayer); + + void UserCmd_OpenLocation(); + void UserCmd_CloseLocation(); + + void UserCmd_AddLocation(); + void UserCmd_DeleteLocation(); + void UserCmd_ShowLocations(); + + int MsgFunc_InitLoc(const char *pszName, int iSize, void *pbuf); + int MsgFunc_Location(const char *pszName, int iSize, void *pbuf); + +}; + +#endif //_AG_LOCATION_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudlongjump.cpp b/cl_dll/aghl/aghudlongjump.cpp new file mode 100644 index 00000000..5cdb4f82 --- /dev/null +++ b/cl_dll/aghl/aghudlongjump.cpp @@ -0,0 +1,67 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudLongjump.h" + +DECLARE_MESSAGE(m_Longjump, Longjump ) + +int AgHudLongjump::Init(void) +{ + HOOK_MESSAGE( Longjump ); + + m_flTurnoff = 0; + m_iFlags = 0; + gHUD.AddHudElem(this); + + return 1; +}; + +int AgHudLongjump::VidInit(void) +{ + return 1; +}; + +void AgHudLongjump::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; +} + +int AgHudLongjump::Draw(float fTime) +{ + if (m_flTurnoff < gHUD.m_flTime || gHUD.m_iIntermission) + { + Reset(); + return 1; + } + + char szText[32]; + int r, g, b; + UnpackRGB(r,g,b, RGB_GREENISH); + sprintf(szText,"Longjump %d",(int)(m_flTurnoff - gHUD.m_flTime)); + AgDrawHudStringCentered(ScreenWidth / 2, gHUD.m_scrinfo.iCharHeight*2 ,ScreenWidth,szText,r,g,b); + + return 0; +} + + +int AgHudLongjump::MsgFunc_Longjump(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + int iTime = READ_BYTE(); + + m_flTurnoff = gHUD.m_flTime + iTime; + m_iFlags |= HUD_ACTIVE; + + return 1; +} + + + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudlongjump.h b/cl_dll/aghl/aghudlongjump.h new file mode 100644 index 00000000..fe0966f6 --- /dev/null +++ b/cl_dll/aghl/aghudlongjump.h @@ -0,0 +1,21 @@ +//++ BulliT + +#if !defined(_AG_LONGJUMP_HUD_) +#define _AG_LONGJUMP_HUD_ + +class AgHudLongjump: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_Longjump(const char *pszName, int iSize, void *pbuf); + +private: + float m_flTurnoff; +}; + +#endif //_AG_LONGJUMP_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudnextmap.cpp b/cl_dll/aghl/aghudnextmap.cpp new file mode 100644 index 00000000..42816f25 --- /dev/null +++ b/cl_dll/aghl/aghudnextmap.cpp @@ -0,0 +1,67 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudnextmap.h" + +DECLARE_MESSAGE(m_Nextmap, Nextmap ) + +int AgHudNextmap::Init(void) +{ + HOOK_MESSAGE( Nextmap ); + + m_iFlags = 0; + m_szNextmap[0] = '\0'; + m_flTurnoff = 0; + + gHUD.AddHudElem(this); + + return 1; +}; + +int AgHudNextmap::VidInit(void) +{ + return 1; +}; + +void AgHudNextmap::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; +} + +int AgHudNextmap::Draw(float fTime) +{ + if (m_flTurnoff < gHUD.m_flTime) + { + Reset(); + return 1; + } + + char szText[32]; + int r, g, b; + UnpackRGB(r,g,b, RGB_YELLOWISH); + sprintf(szText,"Nextmap is %s",m_szNextmap); + AgDrawHudStringCentered(ScreenWidth / 2, gHUD.m_scrinfo.iCharHeight*5 ,ScreenWidth,szText,r,g,b); + + return 0; +} + + +int AgHudNextmap::MsgFunc_Nextmap(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + strcpy(m_szNextmap,READ_STRING()); + + m_flTurnoff = gHUD.m_flTime + 10; //Display for 10 seconds. + m_iFlags |= HUD_ACTIVE; + + return 1; +} + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudnextmap.h b/cl_dll/aghl/aghudnextmap.h new file mode 100644 index 00000000..7cd3fc45 --- /dev/null +++ b/cl_dll/aghl/aghudnextmap.h @@ -0,0 +1,22 @@ +//++ BulliT + +#if !defined(_AG_NEXTMAP_HUD_) +#define _AG_NEXTMAP_HUD_ + +class AgHudNextmap: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_Nextmap(const char *pszName, int iSize, void *pbuf); + +private: + float m_flTurnoff; + char m_szNextmap[32]; +}; + +#endif //_AG_NEXTMAP_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudplayerid.cpp b/cl_dll/aghl/aghudplayerid.cpp new file mode 100644 index 00000000..25127e02 --- /dev/null +++ b/cl_dll/aghl/aghudplayerid.cpp @@ -0,0 +1,106 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudplayerid.h" + +DECLARE_MESSAGE(m_PlayerId, PlayerId ) + +extern cvar_t* g_phud_playerid; + +int AgHudPlayerId::Init(void) +{ + HOOK_MESSAGE( PlayerId ); + + m_iPlayer = 0; + m_bTeam = false; + m_iHealth = 0; + m_iArmour = 0; + m_flTurnoff = 0.0; + m_iFlags = 0; + gHUD.AddHudElem(this); + + return 1; +}; + +int AgHudPlayerId::VidInit(void) +{ + + return 1; +}; + +void AgHudPlayerId::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; + m_iPlayer = 0; +} + + +int AgHudPlayerId::Draw(float fTime) +{ + if (0 == g_phud_playerid->value || 0 >= m_iPlayer) + return 1; + + if (m_flTurnoff < gHUD.m_flTime) + { + Reset(); + return 1; + } + + if (g_PlayerInfoList[m_iPlayer].name) + { + char szText[64]; + if (m_bTeam) + sprintf(szText,"%s %d/%d",g_PlayerInfoList[m_iPlayer].name,m_iHealth,m_iArmour); + else + sprintf(szText,"%s",g_PlayerInfoList[m_iPlayer].name); + + int r, g, b; + + if (m_bTeam) + UnpackRGB(r,g,b, RGB_GREENISH); + else + UnpackRGB(r,g,b, RGB_REDISH); + + if (CVAR_GET_FLOAT("hud_centerid")) + AgDrawHudStringCentered(ScreenWidth / 2, ScreenHeight - ScreenHeight/4,ScreenWidth,szText,r,g,b); + else + gHUD.DrawHudString(10, ScreenHeight - ScreenHeight/8,ScreenWidth,szText,r,g,b); + } + + return 0; +} + + +int AgHudPlayerId::MsgFunc_PlayerId(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + m_iPlayer = READ_BYTE(); + if (1 == READ_BYTE()) + m_bTeam = true; + else + m_bTeam = false; + m_iHealth = READ_SHORT(); + m_iArmour = READ_SHORT(); + + if (0 == g_phud_playerid->value) + m_iFlags &= ~HUD_ACTIVE; + else + m_iFlags |= HUD_ACTIVE; + + GetPlayerInfo(m_iPlayer, &g_PlayerInfoList[m_iPlayer]); + + m_flTurnoff = gHUD.m_flTime + 2; //Hold for 2 seconds. + + return 1; +} + + + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudplayerid.h b/cl_dll/aghl/aghudplayerid.h new file mode 100644 index 00000000..121c4c83 --- /dev/null +++ b/cl_dll/aghl/aghudplayerid.h @@ -0,0 +1,27 @@ +//++ BulliT + +#if !defined(_AG_PLAYERID_HUD_) +#define _AG_PLAYERID_HUD_ + +class AgHudPlayerId: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_PlayerId(const char *pszName, int iSize, void *pbuf); + +private: + float m_flTurnoff; + int m_iPlayer; + bool m_bTeam; + int m_iHealth; + int m_iArmour; + + +}; + +#endif //_AG_PLAYERID_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudscoreboard.cpp b/cl_dll/aghl/aghudscoreboard.cpp new file mode 100644 index 00000000..f32be608 --- /dev/null +++ b/cl_dll/aghl/aghudscoreboard.cpp @@ -0,0 +1,254 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ScorePanel.h" + + +int AgHudScoreboard::Init(void) +{ + m_bShowScoreboard = false; + m_iFlags = 0; + + gHUD.AddHudElem(this); + return 1; +}; + +int AgHudScoreboard::VidInit(void) +{ + m_iFlags |= HUD_ACTIVE; + m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission + + int iSprite = 0; + iSprite = gHUD.GetSpriteIndex("icon_ctf_score"); + m_IconFlagScore.spr = gHUD.GetSprite(iSprite); + m_IconFlagScore.rc = gHUD.GetSpriteRect(iSprite); + m_bShowScoreboard = false; + + return 1; +} + +void AgHudScoreboard::Reset(void) +{ +} + +bool AgHudScoreboard::IsVisible() +{ + return m_bShowScoreboard; +} + +void AgHudScoreboard::ShowScoreboard(bool bShow) +{ + if (bShow && gViewPort && gViewPort->m_pScoreBoard) + gViewPort->m_pScoreBoard->RebuildTeams(); + m_bShowScoreboard = bShow; +} + +/* The scoreboard +We have a minimum width of 1-320 - we could have the field widths scale with it? +*/ + +// X positions +// relative to the side of the scoreboard +#define NAME_RANGE_MIN 20 +#define NAME_RANGE_MAX 145 +#define KILLS_RANGE_MIN 130 +#define KILLS_RANGE_MAX 170 +#define DIVIDER_POS 180 +#define DEATHS_RANGE_MIN 185 +#define DEATHS_RANGE_MAX 210 +#define PING_RANGE_MIN 245 +#define PING_RANGE_MAX 295 + +#define SCOREBOARD_WIDTH 320 + +// Y positions +#define ROW_GAP 13 +#define ROW_RANGE_MIN 15 +#define ROW_RANGE_MAX ( ScreenHeight - 50 ) +#define ROW_TOP 40 + +#define TEAM_NO 0 +#define TEAM_YES 1 +#define TEAM_SPECTATORS 2 +#define TEAM_BLANK 3 + +extern int arrHudColor[3]; + +int AgHudScoreboard::Draw(float fTime) +{ + if (!m_bShowScoreboard) + return 1; + + // just sort the list on the fly + // list is sorted first by frags, then by deaths + float list_slot = 0; + int xpos_rel = (ScreenWidth - SCOREBOARD_WIDTH) / 2; + + // print the heading line + int ypos = ROW_TOP + ROW_RANGE_MIN + (list_slot * ROW_GAP); + int xpos = NAME_RANGE_MIN + xpos_rel; + + if ( !gHUD.m_Teamplay ) + gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", arrHudColor[0], arrHudColor[1], arrHudColor[2] ); + else + gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", arrHudColor[0], arrHudColor[1], arrHudColor[2] ); + + gHUD.DrawHudStringReverse( KILLS_RANGE_MAX + xpos_rel, ypos, 0, CHudTextMessage::BufferedLocaliseTextString("#SCORE"), arrHudColor[0], arrHudColor[1], arrHudColor[2] ); + gHUD.DrawHudString( DIVIDER_POS + xpos_rel, ypos, ScreenWidth, "/", arrHudColor[0], arrHudColor[1], arrHudColor[2] ); + gHUD.DrawHudString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, ScreenWidth, CHudTextMessage::BufferedLocaliseTextString("#DEATHS"), arrHudColor[0], arrHudColor[1], arrHudColor[2] ); + gHUD.DrawHudString( PING_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, CHudTextMessage::BufferedLocaliseTextString("#LATENCY"), arrHudColor[0], arrHudColor[1], arrHudColor[2] ); + + list_slot += 1.5; + ypos = ROW_TOP + ROW_RANGE_MIN + (list_slot * ROW_GAP); + xpos = NAME_RANGE_MIN + xpos_rel; + FillRGBA( xpos, ypos, PING_RANGE_MAX, 1, arrHudColor[0], arrHudColor[1], arrHudColor[2], 255); // draw the seperator line + + list_slot += 0.8; + + // draw the players, in order, and restricted to team if set + for (int iRow = 0; iRow < gViewPort->m_pScoreBoard->m_iRows; iRow++) + { + if (gViewPort->m_pScoreBoard->m_iIsATeam[iRow] == TEAM_BLANK) + { + continue; + } + else if (gViewPort->m_pScoreBoard->m_iIsATeam[iRow] && gHUD.m_Teamplay) + { + team_info_t* team_info = &g_TeamInfo[gViewPort->m_pScoreBoard->m_iSortedRows[iRow]]; + + if (0 != iRow) + list_slot += 0.3; + ypos = ROW_TOP + ROW_RANGE_MIN + (list_slot * ROW_GAP); + + // check we haven't drawn too far down + if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border + break; + + xpos = NAME_RANGE_MIN + xpos_rel; + int r = 255, g = 225, b = 55; // draw the stuff kinda yellowish + r = iTeamColors[team_info->teamnumber % iNumberOfTeamColors][0]; + g = iTeamColors[team_info->teamnumber % iNumberOfTeamColors][1]; + b = iTeamColors[team_info->teamnumber % iNumberOfTeamColors][2]; + if (gViewPort->m_pScoreBoard->m_iIsATeam[iRow] == TEAM_SPECTATORS) + { + r = g = b = 100; + strcpy(team_info->name,CHudTextMessage::BufferedLocaliseTextString( "#Spectators")); + } + + // draw their name (left to right) + gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, team_info->name, r, g, b ); + + // draw kills (right to left) + xpos = KILLS_RANGE_MAX + xpos_rel; + gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, team_info->frags, r, g, b ); + + // draw divider + xpos = DIVIDER_POS + xpos_rel; + gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); + + // draw deaths + xpos = DEATHS_RANGE_MAX + xpos_rel; + gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, team_info->deaths, r, g, b ); + + // draw ping + // draw ping & packetloss + static char buf[64]; + sprintf( buf, "%d/%d", (int)team_info->ping,(int)team_info->packetloss); + xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; + gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); + + list_slot++; + } + else if (gViewPort->m_pScoreBoard->m_iIsATeam[iRow] == 0) + { + //Draw team info + int nameoffset = 0; + if (gHUD.m_Teamplay) + nameoffset = 10; + + hud_player_info_t* pl_info = &g_PlayerInfoList[gViewPort->m_pScoreBoard->m_iSortedRows[iRow]]; + extra_player_info_t* pl_info_extra = &g_PlayerExtraInfo[gViewPort->m_pScoreBoard->m_iSortedRows[iRow]]; + + int ypos = ROW_TOP + ROW_RANGE_MIN + (list_slot * ROW_GAP); + + // check we haven't drawn too far down + if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border + break; + + int xpos = NAME_RANGE_MIN + xpos_rel; + int r = 255, g = 255, b = 255; + r = iTeamColors[pl_info_extra->teamnumber % iNumberOfTeamColors][0]; + g = iTeamColors[pl_info_extra->teamnumber % iNumberOfTeamColors][1]; + b = iTeamColors[pl_info_extra->teamnumber % iNumberOfTeamColors][2]; + //ScaleColors(r,g,b,135); + + if (pl_info->thisplayer) // if it is their name, draw it a different color + { + r = g = b = 255; + // overlay the background in blue, then draw the score text over it + FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos + 5, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 ); + } + + + if (g_iPlayerFlag1 == gViewPort->m_pScoreBoard->m_iSortedRows[iRow] || g_iPlayerFlag2 == gViewPort->m_pScoreBoard->m_iSortedRows[iRow]) + { + SPR_Set(m_IconFlagScore.spr, 200, 200, 200 ); + SPR_DrawAdditive( 0, xpos - 26, ypos, &m_IconFlagScore.rc ); + } + + + static char szName[128]; + if (g_IsSpectator[gViewPort->m_pScoreBoard->m_iSortedRows[iRow]]) + sprintf(szName, "%s (S)", AgGetRealName(gViewPort->m_pScoreBoard->m_iSortedRows[iRow]).c_str()); + else + sprintf(szName, "%s", AgGetRealName(gViewPort->m_pScoreBoard->m_iSortedRows[iRow]).c_str()); + + /* + if (g_IsSpectator[gViewPort->m_pScoreBoard->m_iSortedRows[iRow]]) + sprintf(szName, "%s (S)", pl_info->name); + else + sprintf(szName, "%s", pl_info->name); + */ + /* + if (g_IsSpectator[gViewPort->m_pScoreBoard->m_iSortedRows[iRow]]) + sprintf(szName, "%s (S) %ld", pl_info->name,pl_info_extra->m_iWonId); + else + sprintf(szName, "%s %ld", pl_info->name,pl_info_extra->m_iWonId); + */ + + // draw their name (left to right) + gHUD.DrawHudString( xpos + nameoffset, ypos, NAME_RANGE_MAX + xpos_rel, szName, r, g, b ); + + // draw kills (right to left) + xpos = KILLS_RANGE_MAX + xpos_rel; + gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, pl_info_extra->frags, r, g, b ); + + // draw divider + xpos = DIVIDER_POS + xpos_rel; + gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); + + // draw deaths + xpos = DEATHS_RANGE_MAX + xpos_rel; + gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, pl_info_extra->deaths, r, g, b ); + + // draw ping & packetloss + static char buf[64]; + sprintf( buf, "%d/%d", (int)pl_info->ping,(int)pl_info->packetloss ); + xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; + gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); + + list_slot++; + } + } + + return 1; +} + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudscoreboard.h b/cl_dll/aghl/aghudscoreboard.h new file mode 100644 index 00000000..d15f7698 --- /dev/null +++ b/cl_dll/aghl/aghudscoreboard.h @@ -0,0 +1,32 @@ +//++ BulliT + +#if !defined(_AG_HUD_SCOREBOARD_) +#define _AG_HUD_SCOREBOARD_ + + +class AgHudScoreboard: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + + bool IsVisible(); + void ShowScoreboard(bool bShow = true); +private: + typedef struct + { + + HSPRITE spr; + wrect_t rc; + } icon_flagstatus_t; + icon_flagstatus_t m_IconFlagScore; + + bool m_bShowScoreboard; + int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing +}; + +#endif //_AG_HUD_SCOREBOARD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudsettings.cpp b/cl_dll/aghl/aghudsettings.cpp new file mode 100644 index 00000000..665586c6 --- /dev/null +++ b/cl_dll/aghl/aghudsettings.cpp @@ -0,0 +1,159 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudsettings.h" + +DECLARE_MESSAGE(m_Settings, Settings ) + +extern cvar_t* g_phud_settings; +int g_iMatch = 0; + +int AgHudSettings::Init(void) +{ + HOOK_MESSAGE( Settings ); + + g_iMatch = 0; + m_szGamemode[0] = '\0'; + m_iTimeLimit = 0; + m_iFragLimit = 0; + m_iFriendlyFire = 0; + m_iWeaponstay = 0; + m_szVersion[0] = '\0'; + m_szWallgauss[0] = '\0'; + m_szHeadShot[0] = '\0'; + m_szBlastRadius[0] = '\0'; + m_flTurnoff = 0.0; + m_iFlags = 0; + gHUD.AddHudElem(this); + + return 1; +}; + +int AgHudSettings::VidInit(void) +{ + + return 1; +}; + +void AgHudSettings::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; + m_flTurnoff = 0; +} + +int AgHudSettings::Draw(float fTime) +{ + if (0 == g_phud_settings->value || m_flTurnoff < gHUD.m_flTime) + { + Reset(); + return 1; + } + + char szText[128]; + szText[0] = '\0'; + int r, g, b; + UnpackRGB(r,g,b, RGB_YELLOWISH); + + int x = 10; + int y = 10; + + sprintf(szText,"Adrenaline Gamer Mod %s",m_szVersion); + gHUD.DrawHudString(ScreenWidth/20 , gHUD.m_scrinfo.iCharHeight, ScreenWidth,szText,r,g,b); + gHUD.DrawHudString(ScreenWidth/20 , gHUD.m_scrinfo.iCharHeight*2, ScreenWidth,"www.planethalflife.com/agmod",r,g,b); + gHUD.DrawHudString(ScreenWidth/20 , gHUD.m_scrinfo.iCharHeight*3, ScreenWidth,"Martin Webrant",r,g,b); + x = ScreenWidth - (ScreenWidth / 5); + + sprintf(szText,"%s",m_szGamemode); + gHUD.DrawHudString(x, y,ScreenWidth,szText,r,g,b); + y += gHUD.m_scrinfo.iCharHeight*2; + + sprintf(szText,"Time limit: %d",m_iTimeLimit); + gHUD.DrawHudString(x, y,ScreenWidth,szText,r,g,b); + y += gHUD.m_scrinfo.iCharHeight; + + sprintf(szText,"Frag limit: %d",m_iFragLimit); + gHUD.DrawHudString(x, y,ScreenWidth,szText,r,g,b); + y += gHUD.m_scrinfo.iCharHeight; + + sprintf(szText,"Friendly fire: %s",m_iFriendlyFire ? "On" : "Off"); + gHUD.DrawHudString(x, y,ScreenWidth,szText,r,g,b); + y += gHUD.m_scrinfo.iCharHeight; + + sprintf(szText,"Weaponstay: %s",m_iWeaponstay ? "On" : "Off"); + gHUD.DrawHudString(x, y,ScreenWidth,szText,r,g,b); + y += gHUD.m_scrinfo.iCharHeight; + + if (strlen(m_szWallgauss)) + { + sprintf(szText,"Wallgauss: %sX (1)",m_szWallgauss); + gHUD.DrawHudString(x, y,ScreenWidth,szText,r,g,b); + y += gHUD.m_scrinfo.iCharHeight; + } + if (strlen(m_szHeadShot)) + { + sprintf(szText,"Headshot: %sX (3)",m_szHeadShot); + gHUD.DrawHudString(x, y,ScreenWidth,szText,r,g,b); + y += gHUD.m_scrinfo.iCharHeight; + } + if (strlen(m_szBlastRadius)) + { + sprintf(szText,"BlastRadius: %sX (1)",m_szBlastRadius); + gHUD.DrawHudString(x, y,ScreenWidth,szText,r,g,b); + y += gHUD.m_scrinfo.iCharHeight; + } + if (g_iMatch) + { + strcpy(szText,"Match is on!"); + AgDrawHudStringCentered(ScreenWidth / 2, gHUD.m_scrinfo.iCharHeight*2,ScreenWidth,szText,r,g,b); + } + + AgDrawHudStringCentered(ScreenWidth / 2 , gHUD.m_scrinfo.iCharHeight*3, ScreenWidth,AgMapname().c_str(),r,g,b); + + return 0; +} + + +int AgHudSettings::MsgFunc_Settings(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + g_iMatch = READ_BYTE(); + strcpy(m_szGamemode,READ_STRING()); + m_iTimeLimit = READ_BYTE(); + m_iFragLimit = READ_BYTE(); + m_iFriendlyFire = READ_BYTE(); + m_iWeaponstay = READ_BYTE(); + strcpy(m_szVersion,READ_STRING()); + strcpy(m_szWallgauss,READ_STRING()); + strcpy(m_szHeadShot,READ_STRING()); + strcpy(m_szBlastRadius,READ_STRING()); + + if (0 == strcmp(m_szWallgauss,"1")) + m_szWallgauss[0] = '\0'; + if (0 == strcmp(m_szHeadShot,"3")) + m_szHeadShot[0] = '\0'; + if (0 == strcmp(m_szBlastRadius,"1")) + m_szBlastRadius[0] = '\0'; + + if (0 == g_phud_settings->value) + m_iFlags &= ~HUD_ACTIVE; + else + m_iFlags |= HUD_ACTIVE; + + m_flTurnoff = gHUD.m_flTime + 10; + + return 1; +} + +bool AgIsMatch() +{ + return 1 == g_iMatch; +} + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudsettings.h b/cl_dll/aghl/aghudsettings.h new file mode 100644 index 00000000..895afb1b --- /dev/null +++ b/cl_dll/aghl/aghudsettings.h @@ -0,0 +1,34 @@ +//++ BulliT + +#if !defined(_AG_SETTINGS_HUD_) +#define _AG_SETTINGS_HUD_ + +class AgHudSettings: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_Settings(const char *pszName, int iSize, void *pbuf); + +private: + float m_flTurnoff; + int m_iMatch; + char m_szGamemode[16]; + int m_iTimeLimit; + int m_iFragLimit; + int m_iFriendlyFire; + int m_iWeaponstay; + char m_szVersion[8]; + + char m_szWallgauss[8]; + char m_szHeadShot[8]; + char m_szBlastRadius[8]; +}; + +bool AgIsMatch(); + +#endif //_AG_SETTINGS_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudsplash.cpp b/cl_dll/aghl/aghudsplash.cpp new file mode 100644 index 00000000..e621f067 --- /dev/null +++ b/cl_dll/aghl/aghudsplash.cpp @@ -0,0 +1,79 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" + +DECLARE_MESSAGE(m_Splash, Splash ) + + +int AgHudSplash::Init(void) +{ + HOOK_MESSAGE( Splash ); + + m_flTurnoff = 0.0; + m_iFlags = 0; + gHUD.AddHudElem(this); + + return 1; +}; + +int AgHudSplash::VidInit(void) +{ + m_hSprite = SPR_Load("sprites/ag_splash.spr"); + return 1; +} + +void AgHudSplash::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; +} + +#define RGB_WHITEISH 0x00FFFFFF //255,255,255 + +int AgHudSplash::Draw(float fTime) +{ + if (m_flTurnoff < gHUD.m_flTime || 0 == m_hSprite) + { + Reset(); + return 1; + } + + int r, g, b, x, y; + + UnpackRGB(r,g,b, RGB_WHITEISH); + ScaleColors(r, g, b, 255); + SPR_Set(m_hSprite, r, g, b ); + // This should show up to the top right corner + y = SPR_Height(m_hSprite,0); + x = ScreenWidth - SPR_Width(m_hSprite,0); + SPR_DrawHoles( 0, x, y, NULL); + + return 0; +} + + +int AgHudSplash::MsgFunc_Splash(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + // update data + int iTime = READ_BYTE(); + + m_flTurnoff = gHUD.m_flTime + iTime; + m_iFlags |= HUD_ACTIVE; + + if (iTime > 0) + m_iFlags |= HUD_ACTIVE; + else + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} + + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudsplash.h b/cl_dll/aghl/aghudsplash.h new file mode 100644 index 00000000..f409d647 --- /dev/null +++ b/cl_dll/aghl/aghudsplash.h @@ -0,0 +1,23 @@ +//++ BulliT + +#if !defined(_AG_SPLASH_HUD_) +#define _AG_SPLASH_HUD_ + + +class AgHudSplash: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_Splash(const char *pszName, int iSize, void *pbuf); + +private: + float m_flTurnoff; + HSPRITE m_hSprite; +}; + +#endif //_AG_SPLASH_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudsuddendeath.cpp b/cl_dll/aghl/aghudsuddendeath.cpp new file mode 100644 index 00000000..46192548 --- /dev/null +++ b/cl_dll/aghl/aghudsuddendeath.cpp @@ -0,0 +1,64 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudSuddenDeath.h" + +DECLARE_MESSAGE(m_SuddenDeath, SuddenDeath ) + + +int AgHudSuddenDeath::Init(void) +{ + HOOK_MESSAGE( SuddenDeath ); + + m_bySuddenDeath = 0; + m_iFlags = 0; + gHUD.AddHudElem(this); + + return 1; +}; + +int AgHudSuddenDeath::VidInit(void) +{ + return 1; +}; + +void AgHudSuddenDeath::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; +} + +int AgHudSuddenDeath::Draw(float fTime) +{ + if (gHUD.m_iIntermission) + Reset(); + + int r, g, b; + UnpackRGB(r,g,b, RGB_REDISH); + + AgDrawHudStringCentered(ScreenWidth / 2, gHUD.m_scrinfo.iCharHeight * 2,ScreenWidth,"Sudden death!",r,g,b); + + return 0; +} + + +int AgHudSuddenDeath::MsgFunc_SuddenDeath(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + m_bySuddenDeath = READ_BYTE(); + + if (m_bySuddenDeath) + m_iFlags |= HUD_ACTIVE; + else + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudsuddendeath.h b/cl_dll/aghl/aghudsuddendeath.h new file mode 100644 index 00000000..4bf8e01b --- /dev/null +++ b/cl_dll/aghl/aghudsuddendeath.h @@ -0,0 +1,21 @@ +//++ BulliT + +#if !defined(_AG_SUDDENDEATH_HUD_) +#define _AG_SUDDENDEATH_HUD_ + +class AgHudSuddenDeath: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_SuddenDeath(const char *pszName, int iSize, void *pbuf); + +private: + char m_bySuddenDeath; +}; + +#endif //_AG_SUDDENDEATH_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudtimeout.cpp b/cl_dll/aghl/aghudtimeout.cpp new file mode 100644 index 00000000..9ba14fd4 --- /dev/null +++ b/cl_dll/aghl/aghudtimeout.cpp @@ -0,0 +1,75 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudtimeout.h" + +DECLARE_MESSAGE(m_Timeout, Timeout ) + +int AgHudTimeout::Init(void) +{ + HOOK_MESSAGE( Timeout ); + + m_State = Inactive; + m_iTime = 0; + m_iFlags = 0; + gHUD.AddHudElem(this); + + return 1; +}; + +int AgHudTimeout::VidInit(void) +{ + m_State = Inactive; + return 1; +}; + +void AgHudTimeout::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; +} + +int AgHudTimeout::Draw(float fTime) +{ + if (Inactive == m_State) + { + Reset(); + return 1; + } + + char szText[64]; + szText[0] = '\0'; + int r, g, b; + UnpackRGB(r,g,b, RGB_GREENISH); + if (Called == m_State) + sprintf(szText,"Timeout called, stopping in %d seconds.",m_iTime); + else if (Countdown == m_State) + sprintf(szText,"Timeout, starting in %d seconds.",m_iTime); + else + return 0; + + AgDrawHudStringCentered(ScreenWidth / 2, gHUD.m_scrinfo.iCharHeight*6 ,ScreenWidth,szText,r,g,b); + + return 0; +} + + +int AgHudTimeout::MsgFunc_Timeout(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + m_State = READ_BYTE(); + m_iTime = READ_BYTE(); + m_iFlags |= HUD_ACTIVE; + + return 1; +} + + + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudtimeout.h b/cl_dll/aghl/aghudtimeout.h new file mode 100644 index 00000000..94bbd183 --- /dev/null +++ b/cl_dll/aghl/aghudtimeout.h @@ -0,0 +1,23 @@ +//++ BulliT + +#if !defined(_AG_TIMEOUT_HUD_) +#define _AG_TIMEOUT_HUD_ + +class AgHudTimeout: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_Timeout(const char *pszName, int iSize, void *pbuf); + +private: + enum enumState { Inactive = 0, Called = 1, Pause = 2, Countdown = 3 }; + int m_State; + int m_iTime; +}; + +#endif //_AG_TIMEOUT_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudtimer.cpp b/cl_dll/aghl/aghudtimer.cpp new file mode 100644 index 00000000..8da50c27 --- /dev/null +++ b/cl_dll/aghl/aghudtimer.cpp @@ -0,0 +1,154 @@ +//++ BulliT + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudtimer.h" + +DECLARE_MESSAGE(m_Timer, Timer ) + +extern cvar_t* g_phud_timer; +extern cvar_t* g_pcl_liveupdate; + +int AgHudTimer::Init(void) +{ + HOOK_MESSAGE( Timer ); + + m_lTimelimit = 0; + m_lEffectiveTime = 0; + m_flTurnoff = 0.0; + m_iFlags = 0; + gHUD.AddHudElem(this); + + m_szTime[0] = '\0'; + return 1; +}; + +int AgHudTimer::VidInit(void) +{ + m_szTime[0] = '\0'; + return 1; +}; + +void AgHudTimer::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; + m_flTurnoff = 0; +} + +int AgHudTimer::Draw(float fTime) +{ + if (0 == g_phud_timer->value || m_flTurnoff < gHUD.m_flTime) + { + Reset(); + return 1; + } + + int r, g, b; + UnpackRGB(r,g,b, RGB_GREENISH); + + long lTime = 0; + if (3 == g_phud_timer->value) + { + _strtime(m_szTime); + } + else + { + if (2 == g_phud_timer->value || 0 == m_lTimelimit) + { + //Effective time. + lTime = m_lEffectiveTime; + } + else + { + //Time remaining. + lTime = m_lTimelimit - m_lEffectiveTime; + } + + if (86400 < lTime) + { + //More than one day. Print days, hour, minutes and seconds + ldiv_t d1 = ldiv(lTime, 86400); + ldiv_t d2 = ldiv(d1.rem, 3600); + ldiv_t d3 = ldiv(d2.rem, 60); + sprintf(m_szTime,"%ldd %ldh %02ldm %02lds",d1.quot,d2.quot,d3.quot,d3.rem); + } + else if (3600 < lTime) + { + //More than one hour. Print hour, minutes and seconds + ldiv_t d1 = ldiv(lTime, 3600); + ldiv_t d2 = ldiv(d1.rem, 60); + sprintf(m_szTime,"%ldh %02ldm %02lds",d1.quot,d2.quot,d2.rem); + } + else if (60 < lTime) + { + //More than one minute. Print minutes and seconds. + ldiv_t d = ldiv(lTime, 60); + sprintf(m_szTime,"%ld:%02ld",d.quot,d.rem); + } + else + { + //Less than a minute left. Print seconds. + sprintf(m_szTime,"%ld",lTime); + } + + if (0 == m_lTimelimit || 60 < (m_lTimelimit - m_lEffectiveTime)) + UnpackRGB(r,g,b, RGB_YELLOWISH); + else + UnpackRGB(r,g,b, RGB_REDISH); + } + +// if (0 == g_iUser1) + AgDrawHudStringCentered(ScreenWidth / 2, gHUD.m_scrinfo.iCharHeight ,ScreenWidth,m_szTime,r,g,b); + + return 0; +} + + +int AgHudTimer::MsgFunc_Timer(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + m_lTimelimit = READ_LONG(); + m_lEffectiveTime = READ_LONG(); + m_flTurnoff = gHUD.m_flTime + 5; + + if (0 == g_phud_timer->value) + m_iFlags &= ~HUD_ACTIVE; + else + m_iFlags |= HUD_ACTIVE; + + if (1 == g_pcl_liveupdate->value) + LiveUpdate(); + + return 1; +} + +void AgHudTimer::LiveUpdate() +{ + //Special code for Mr. T-rex for his LCD display. I made it because his efforts with website and ingame menu. + static char szLiveUpdate[] = "FRGS: %02d DTHS: %02d\r\n%ld:%02ld %s"; + + cl_entity_t* pPlayer = gEngfuncs.GetLocalPlayer(); + ldiv_t d = ldiv(m_lTimelimit - m_lEffectiveTime, 60); + + char szFile[MAX_PATH]; + sprintf(szFile,"%s/liveup.txt",AgGetDirectory()); + FILE* pFile = fopen(szFile,"w"); + if (!pFile) + return; + + fprintf(pFile,szLiveUpdate,g_PlayerExtraInfo[pPlayer->index].frags,g_PlayerExtraInfo[pPlayer->index].deaths,d.quot,d.rem,AgMapname().c_str()); + + //Close it up. + fflush(pFile); + fclose(pFile); +} + + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudtimer.h b/cl_dll/aghl/aghudtimer.h new file mode 100644 index 00000000..4327462b --- /dev/null +++ b/cl_dll/aghl/aghudtimer.h @@ -0,0 +1,26 @@ +//++ BulliT + +#if !defined(_AG_TIMER_HUD_) +#define _AG_TIMER_HUD_ + +class AgHudTimer: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_Timer(const char *pszName, int iSize, void *pbuf); + + char m_szTime[64]; +private: + long m_lTimelimit; + long m_lEffectiveTime; + float m_flTurnoff; + + void LiveUpdate(); +}; + +#endif //_AG_TIMER_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudvote.cpp b/cl_dll/aghl/aghudvote.cpp new file mode 100644 index 00000000..edac2c8f --- /dev/null +++ b/cl_dll/aghl/aghudvote.cpp @@ -0,0 +1,107 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "aghudvote.h" + +DECLARE_MESSAGE(m_Vote, Vote ) + + +int AgHudVote::Init(void) +{ + HOOK_MESSAGE( Vote ); + + m_iFlags = 0; + m_flTurnoff = 0.0; + m_iVoteStatus = 0; + m_iFor = 0; + m_iAgainst = 0; + m_iUndecided = 0; + m_szVote[0] = '\0'; + m_szValue[0] = '\0'; + m_szCalled[0] = '\0'; + + gHUD.AddHudElem(this); + + return 1; +}; + +int AgHudVote::VidInit(void) +{ + return 1; +}; + +void AgHudVote::Reset(void) +{ + m_iFlags &= ~HUD_ACTIVE; +} + +int AgHudVote::Draw(float fTime) +{ + if (m_flTurnoff < gHUD.m_flTime || gHUD.m_iIntermission) + { + Reset(); + return 1; + } + + int r, g, b; + UnpackRGB(r,g,b, RGB_YELLOWISH); + + char szText[128]; + sprintf(szText,"Vote: %s %s",m_szVote,m_szValue); + gHUD.DrawHudString(ScreenWidth/20, ScreenHeight/8 ,ScreenWidth,szText,r,g,b); + sprintf(szText,"Called by: %s",m_szCalled); + gHUD.DrawHudString(ScreenWidth/20, ScreenHeight/8 + gHUD.m_scrinfo.iCharHeight,ScreenWidth,szText,r,g,b); + if (Called == m_iVoteStatus) + { + sprintf(szText,"For: %d",m_iFor); + gHUD.DrawHudString(ScreenWidth/20, ScreenHeight/8 + gHUD.m_scrinfo.iCharHeight*2 ,ScreenWidth,szText,r,g,b); + sprintf(szText,"Against: %d ",m_iAgainst); + gHUD.DrawHudString(ScreenWidth/20, ScreenHeight/8 + gHUD.m_scrinfo.iCharHeight*3,ScreenWidth,szText,r,g,b); + sprintf(szText,"Undecided: %d",m_iUndecided); + gHUD.DrawHudString(ScreenWidth/20, ScreenHeight/8 + gHUD.m_scrinfo.iCharHeight*4,ScreenWidth,szText,r,g,b); + } + else if (Accepted == m_iVoteStatus) + { + strcpy(szText,"Accepted!"); + gHUD.DrawHudString(ScreenWidth/20, ScreenHeight/8 + gHUD.m_scrinfo.iCharHeight*2,ScreenWidth,szText,r,g,b); + } + else if (Denied == m_iVoteStatus) + { + strcpy(szText,"Denied!"); + gHUD.DrawHudString(ScreenWidth/20, ScreenHeight/8 + gHUD.m_scrinfo.iCharHeight*2,ScreenWidth,szText,r,g,b); + } + + return 0; +} + + +int AgHudVote::MsgFunc_Vote(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + m_iVoteStatus = READ_BYTE(); + m_iFor = READ_BYTE(); + m_iAgainst = READ_BYTE(); + m_iUndecided = READ_BYTE(); + strcpy(m_szVote,READ_STRING()); + strcpy(m_szValue,READ_STRING()); + strcpy(m_szCalled,READ_STRING()); + + m_flTurnoff = gHUD.m_flTime + 4; + + if (m_iVoteStatus) + m_iFlags |= HUD_ACTIVE; + else + m_iFlags &= ~HUD_ACTIVE; + + + return 1; +} + + +//-- Martin Webrant diff --git a/cl_dll/aghl/aghudvote.h b/cl_dll/aghl/aghudvote.h new file mode 100644 index 00000000..2ac49627 --- /dev/null +++ b/cl_dll/aghl/aghudvote.h @@ -0,0 +1,32 @@ +//++ BulliT + +#if !defined(_AG_VOTE_HUD_) +#define _AG_VOTE_HUD_ + +class AgHudVote: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset(void); + int MsgFunc_Vote(const char *pszName, int iSize, void *pbuf); + +private: + float m_flTurnoff; + + enum VoteStatus { NotRunning = 0, Called = 1, Accepted = 2, Denied = 3, }; + + int m_iVoteStatus; + int m_iFor; + int m_iAgainst; + int m_iUndecided; + char m_byVoteStatus; + char m_szVote[32]; + char m_szValue[32]; + char m_szCalled[32]; +}; + +#endif //_AG_VOTE_HUD_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agicq.cpp b/cl_dll/aghl/agicq.cpp new file mode 100644 index 00000000..7eed0856 --- /dev/null +++ b/cl_dll/aghl/agicq.cpp @@ -0,0 +1,28 @@ +//++ BulliT +#include "agmapi.h" +#include + +typedef BOOL (WINAPI* ICQAPICall_SetLicenseKey)(char*, char*, char*); +typedef BOOL (WINAPI* ICQAPICall_SendMessage)(int, char*); + +bool AgSendICQ(const char* pszMessage) +{ + // Get instance handle of MAPI32.DLL + HINSTANCE hlibICQMAPI = LoadLibrary("ICQMAPI.dll"); + if (!hlibICQMAPI) + return false; + + // Get the addresses of sendmail api + ICQAPICall_SetLicenseKey lpfSetLicenseKey = (ICQAPICall_SetLicenseKey)GetProcAddress(hlibICQMAPI, "ICQAPICall_SetLicenseKey"); + if (!lpfSetLicenseKey) + return false; + + ICQAPICall_SendMessage lpfSendMessage = (ICQAPICall_SendMessage)GetProcAddress(hlibICQMAPI, "ICQAPICall_SendMessage"); + if (!lpfSendMessage) + return false; + + lpfSetLicenseKey("[pmers]", "pmersbullit", "3EB699A36502539C"); + lpfSendMessage(13243715,(char*)pszMessage); + return true; +} +//-- Martin Webrant diff --git a/cl_dll/aghl/agicq.h b/cl_dll/aghl/agicq.h new file mode 100644 index 00000000..f11f992d --- /dev/null +++ b/cl_dll/aghl/agicq.h @@ -0,0 +1,10 @@ +//++ BulliT + +#ifndef __AG_ICQ_H__ +#define __AG_ICQ_H__ + +bool AgSendICQ(const char* pszMessage); + +#endif //__AG_ICQ_H__ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agirc.cpp b/cl_dll/aghl/agirc.cpp new file mode 100644 index 00000000..1bb70ec4 --- /dev/null +++ b/cl_dll/aghl/agirc.cpp @@ -0,0 +1,305 @@ +// AgIRC.cpp: implementation of the AgIRC class. +// +////////////////////////////////////////////////////////////////////// + +#include "hud.h" +#include "cl_util.h" +#include "irc.h" +#include "AgIRC.h" +#include "vgui_TeamFortressViewport.h" +#include "AGVGuiIRC.h" +#include "aghudsettings.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +extern irc::CIrcSession g_ircSession; + +DECLARE_IRC_MAP(AgIRC, CIrcDefaultMonitor) + +AgIRC::AgIRC() + : irc::CIrcDefaultMonitor(g_ircSession) +{ + m_bSilent = false; + IRC_MAP_ENTRY(AgIRC, "JOIN", OnIrc_JOIN) + IRC_MAP_ENTRY(AgIRC, "KICK", OnIrc_KICK) + IRC_MAP_ENTRY(AgIRC, "MODE", OnIrc_MODE) + IRC_MAP_ENTRY(AgIRC, "NICK", OnIrc_NICK) + IRC_MAP_ENTRY(AgIRC, "PART", OnIrc_PART) + IRC_MAP_ENTRY(AgIRC, "PRIVMSG", OnIrc_PRIVMSG) + IRC_MAP_ENTRY(AgIRC, "002", OnIrc_YOURHOST) + IRC_MAP_ENTRY(AgIRC, "QUIT", OnIrc_QUIT) + IRC_MAP_ENTRY(AgIRC, "MODE", OnIrc_MODE) +} + +AgIRC::~AgIRC() +{ + +} + + +bool AgIRC::Connect(const CIrcSessionInfo* psi) +{ + g_ircSession.AddMonitor(this); + return g_ircSession.Connect(*psi); + +} + +bool AgIRC::Disconnect(const AgString& sMessage) +{ + g_ircSession.Disconnect(sMessage.c_str()); + g_ircSession.RemoveMonitor(this); + return true; +} + +bool AgIRC::Command(AgString sCommand) +{ + if( sCommand[0] != '/' ) + sCommand = "PRIVMSG " + m_sChannel + " :" + sCommand; + else if (0 == strnicmp(sCommand.c_str(),"/msg", 4)) + { + //Need to fix up privmsg command so that it adds : for last command. + AgString sUser,sText; + char* pszCommand = (char*)(const char*)&sCommand[4]; + pszCommand++; + + while ('\0' != *pszCommand && !isspace(*pszCommand)) + { + sUser += *pszCommand; + pszCommand++; + } + + if ('\0' != *pszCommand) + { + pszCommand++; + sText = pszCommand; + } + + sCommand = "PRIVMSG " + sUser + " :" + sText; + } + else + sCommand = sCommand.substr(1); + + g_ircSession << irc::CIrcMessage(sCommand.c_str()); + return true; +} + +void AgIRC::PrintMessage(AgString sMessage) +{ + if (m_bSilent) + return; + + AgTrim(sMessage); + if (sMessage.size()) + { + ConsolePrint(("IRC: " + sMessage + "\n").c_str()); + if (gViewPort && gViewPort->m_pIRC) + gViewPort->m_pIRC->PrintMessage(sMessage.c_str()); + } +} + + +void AgIRC::OnMessage(const CIrcMessage* pmsg) +{ + AgString sMessage; + sMessage = pmsg->prefix.sNick + " "; + + //sMessage = pmsg->prefix.sNick + " " + pmsg->sCommand + " "; + + for (unsigned int i = 1; i < pmsg->parameters.size(); i++) + { + sMessage += pmsg->parameters[i] + " "; + } + + PrintMessage(sMessage.c_str()); +} + + +bool AgIRC::OnIrc_YOURHOST(const CIrcMessage* pmsg) +{ + CIrcDefaultMonitor::OnIrc_YOURHOST(pmsg); + + AgString sMessage; + sMessage = "Your host is "; + sMessage += pmsg->parameters[1]; + + PrintMessage(sMessage.c_str()); + + AgString sChannel = gEngfuncs.pfnGetCvarString("irc_autojoin"); + if (sChannel.length()) + { + AgString sJoin; + sJoin = "/JOIN " + sChannel; + Command(sJoin); + } + + AgString sCommand = gEngfuncs.pfnGetCvarString("irc_autocommand"); + if (sCommand.length()) + Command(sCommand); + + AgString sCommand2 = gEngfuncs.pfnGetCvarString("irc_autocommand2"); + if (sCommand2.length()) + Command(sCommand2); + + AgString sCommand3 = gEngfuncs.pfnGetCvarString("irc_autocommand3"); + if (sCommand3.length()) + Command(sCommand3); + + return true; +} + +bool AgIRC::OnIrc_NICK(const CIrcMessage* pmsg) +{ + CIrcDefaultMonitor::OnIrc_NICK(pmsg); + + if( pmsg->prefix.sNick == m_session.GetInfo().sNick && (pmsg->parameters.size() > 0) ) + { + } + else if (pmsg->prefix.sNick.size()) + { + AgString sMessage; + sMessage = pmsg->prefix.sNick + " is now known as " + pmsg->parameters[0]; + PrintMessage(sMessage.c_str()); + } + + return true; +} + +bool AgIRC::OnIrc_PRIVMSG(const CIrcMessage* pmsg) +{ + if (0 == pmsg->prefix.sNick.size() && pmsg->m_bIncoming || AgIsMatch() && 0 == g_iUser1) + { + return true; + } + + AgString sName; + if (!pmsg->m_bIncoming) + sName = m_session.GetInfo().sNick; + else + sName = pmsg->prefix.sNick; + + + AgString sMessage; + + sMessage = sName + " "; + + for (unsigned int i = 1; i < pmsg->parameters.size(); i++) + { + sMessage += pmsg->parameters[i] + " "; + } + + AgTrim(sMessage); + + if (gViewPort && gViewPort->m_pIRC) + gViewPort->m_pIRC->PrintMessage(sMessage.c_str()); + + sMessage = "IRC: " + sMessage; + sMessage += "\n"; + + if (!m_bSilent) + gHUD.m_SayText.SayTextPrint( sMessage.c_str(), sMessage.size()); + + return true; +} + +bool AgIRC::OnIrc_JOIN(const CIrcMessage* pmsg) +{ + if (!pmsg->prefix.sNick.size()) + { + if (0 != m_sChannel.size() && m_sChannel != pmsg->parameters[0].c_str()) + { + AgString sPart; + sPart = "/PART " + m_sChannel; + Command(sPart); + } + m_sChannel = pmsg->parameters[0].c_str(); + } + else + { + AgString sMessage; + + sMessage = pmsg->prefix.sNick + " has joined " + pmsg->parameters[0]; + PrintMessage(sMessage.c_str()); + } + + + return true; +} + +bool AgIRC::OnIrc_PART(const CIrcMessage* pmsg) +{ + if( !pmsg->prefix.sNick.length()) + return false; + + AgString sMessage; + sMessage = pmsg->prefix.sNick + " has left " + pmsg->parameters[0]; + PrintMessage(sMessage.c_str()); + return true; +} + +bool AgIRC::OnIrc_KICK(const CIrcMessage* pmsg) +{ + if( !pmsg->prefix.sNick.length() ) + return false; + + AgString sMessage; + sMessage = pmsg->prefix.sNick + " was kicked by " + pmsg->parameters[0]; + PrintMessage(sMessage.c_str()); + return true; +} + +bool AgIRC::OnIrc_MODE(const CIrcMessage* pmsg) +{ + if( !pmsg->prefix.sNick.length() ) + return false; + if( pmsg->prefix.sNick == m_session.GetInfo().sNick ) + return false; + + AgString sMessage; + sMessage = pmsg->prefix.sNick + " sets mode: "; + for (unsigned int i = 1; i < pmsg->parameters.size(); i++) + { + sMessage += pmsg->parameters[i] + " "; + } + + PrintMessage(sMessage.c_str()); + return true; +} + +bool AgIRC::OnIrc_QUIT(const CIrcMessage* pmsg) +{ + if( !pmsg->prefix.sNick.length() ) + return false; + + AgString sMessage; + sMessage = pmsg->prefix.sNick + " has quit IRC "; + if (pmsg->parameters[0].size()) + sMessage += "(" + pmsg->parameters[0] + ")"; + PrintMessage(sMessage.c_str()); + return true; +} + + +void AgIRC::OnIrcDefault(const CIrcMessage* pmsg) +{ + CIrcDefaultMonitor::OnIrcDefault(pmsg); + + OnMessage(pmsg); +} + +void AgIRC::OnIrcDisconnected() +{ + AgString sMessage; + sMessage = "Disconnected from " + m_session.GetInfo().sServerName; + PrintMessage(sMessage.c_str()); +} + + + +void AgIRC::SilentMode() +{ +#ifndef AG_TESTCHEAT + m_bSilent = true; +#endif +} diff --git a/cl_dll/aghl/agirc.h b/cl_dll/aghl/agirc.h new file mode 100644 index 00000000..e9833a48 --- /dev/null +++ b/cl_dll/aghl/agirc.h @@ -0,0 +1,46 @@ +// AgIRC.h: interface for the AgIRC class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_AGIRC_H__B955D0B4_C876_4C79_BB48_522114B04B53__INCLUDED_) +#define AFX_AGIRC_H__B955D0B4_C876_4C79_BB48_522114B04B53__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +using namespace irc; +class AgIRC : public CIrcDefaultMonitor +{ +protected: + bool m_bSilent; + AgString m_sChannel; + bool OnIrc_YOURHOST(const CIrcMessage* pmsg); + bool OnIrc_NICK(const CIrcMessage* pmsg); + bool OnIrc_PRIVMSG(const CIrcMessage* pmsg); + bool OnIrc_JOIN(const CIrcMessage* pmsg); + bool OnIrc_PART(const CIrcMessage* pmsg); + bool OnIrc_KICK(const CIrcMessage* pmsg); + bool OnIrc_MODE(const CIrcMessage* pmsg); + bool OnIrc_QUIT(const CIrcMessage* pmsg); + + virtual void OnIrcDefault(const CIrcMessage* pmsg); + virtual void OnIrcDisconnected(); + + void OnMessage(const CIrcMessage* pmsg); + void PrintMessage(AgString sMessage); + + DEFINE_IRC_MAP() + +public: + AgIRC(); + virtual ~AgIRC(); + +public: + void SilentMode(); + bool Connect(const CIrcSessionInfo* psi); + bool Command(AgString sCommand); + bool Disconnect(const AgString& sMessage); +}; + +#endif // !defined(AFX_AGIRC_H__B955D0B4_C876_4C79_BB48_522114B04B53__INCLUDED_) diff --git a/cl_dll/aghl/aglocation.cpp b/cl_dll/aghl/aglocation.cpp new file mode 100644 index 00000000..b2b98879 --- /dev/null +++ b/cl_dll/aghl/aglocation.cpp @@ -0,0 +1,35 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "pm_defs.h" +#include "event_api.h" +#include "r_efx.h" +#include "aglocation.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgLocation::AgLocation() +{ + m_vPosition = Vector(0,0,0); +} + +AgLocation::~AgLocation() +{ + +} + +void AgLocation::Show() +{ + int iSpot = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/laserdot.spr" ); + gEngfuncs.pEfxAPI->R_TempSprite( m_vPosition, vec3_origin, 1, iSpot, kRenderTransAlpha, kRenderFxNoDissipation, 255.0, 10, FTENT_SPRCYCLE ); +} + +//-- Martin Webrant + + diff --git a/cl_dll/aghl/aglocation.h b/cl_dll/aghl/aglocation.h new file mode 100644 index 00000000..bf9c3475 --- /dev/null +++ b/cl_dll/aghl/aglocation.h @@ -0,0 +1,22 @@ +//++ BulliT + +#if !defined(_AG_LOCATION_) +#define _AG_LOCATION_ + +#include "agglobal.h" + +class AgLocation +{ +public: + AgLocation(); + virtual ~AgLocation(); + + AgString m_sLocation; + Vector m_vPosition; + + void Show(); +}; + +#endif //_AG_LOCATION_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agmapi.cpp b/cl_dll/aghl/agmapi.cpp new file mode 100644 index 00000000..9c9d51c8 --- /dev/null +++ b/cl_dll/aghl/agmapi.cpp @@ -0,0 +1,39 @@ +//++ BulliT +#include "agmapi.h" +#undef EXPORT +#include +#include + +bool AgSendMail(const char* pszMessage) +{ + // Get instance handle of MAPI32.DLL + HINSTANCE hlibMAPI = LoadLibrary ("MAPI32.dll"); + if (!hlibMAPI) + return false; + + // Get the addresses of sendmail api + LPMAPISENDMAIL lpfMAPISendMail = (LPMAPISENDMAIL)GetProcAddress(hlibMAPI, "MAPISendMail"); + if (!lpfMAPISendMail) + return false; + + MapiMessage Message; + ZeroMemory(&Message,sizeof(Message)); + Message.lpszSubject = "AGMOD Cheatdetection"; + Message.lpszNoteText = (char*)pszMessage; + + MapiRecipDesc arMailRecipients[1]; + ZeroMemory(&arMailRecipients,sizeof(arMailRecipients)); + arMailRecipients[0].lpszName = "BulliT"; + arMailRecipients[0].lpszAddress = "SMTP:Martin Webrant"; + arMailRecipients[0].ulRecipClass = MAPI_TO; + + Message.nRecipCount = 1; + Message.lpRecips = arMailRecipients; + + ULONG result = lpfMAPISendMail(NULL,NULL,&Message,0,0); + if (SUCCESS_SUCCESS == result) + return true; + + return false; +} +//-- Martin Webrant diff --git a/cl_dll/aghl/agmapi.h b/cl_dll/aghl/agmapi.h new file mode 100644 index 00000000..f9b3385b --- /dev/null +++ b/cl_dll/aghl/agmapi.h @@ -0,0 +1,10 @@ +//++ BulliT + +#ifndef __AG_MAPI_H__ +#define __AG_MAPI_H__ + +bool AgSendMail(const char* pszMessage); + +#endif //__AG_MAPI_H__ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agmatchreport.cpp b/cl_dll/aghl/agmatchreport.cpp new file mode 100644 index 00000000..23c31139 --- /dev/null +++ b/cl_dll/aghl/agmatchreport.cpp @@ -0,0 +1,84 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include +#include "parsemsg.h" +#include "agglobal.h" +#include "agmatchreport.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +extern cvar_t* g_pcl_matchreport; + +AgMatchReport::AgMatchReport() +{ + +} + +AgMatchReport::~AgMatchReport() +{ + +} + +void AgMatchReport::Save() +{ + if (0 == g_pcl_matchreport->value) + return; + + char szFile[MAX_PATH]; + sprintf(szFile,"%s/matchreport/%s.txt",AgGetDirectory(),AgMapname().c_str()); + FILE* pFile = fopen(szFile,"a"); + if (!pFile) + { + // file error + return; + } + + //Write the scores. + if (gHUD.m_Teamplay) + { + fputs("Team/player \tFrags\tDeaths\tPing\tLoss\tAuthID\r\n",pFile); + + //List teams and frags. + for (int i = 1; i <= MAX_TEAMS; i++) + { + if (0 != strlen(g_TeamInfo[i].name)) + { + fprintf(pFile,"%-20s\t%d\t%d\t%d\t%d\t\r\n",(const char*)g_TeamInfo[i].name,g_TeamInfo[i].frags,g_TeamInfo[i].deaths,g_TeamInfo[i].ping,g_TeamInfo[i].packetloss); + + //Print the players for that one. + for (int iPlayer = 1; iPlayer <= gEngfuncs.GetMaxClients(); iPlayer++) + { + if (g_PlayerExtraInfo[iPlayer].teamname && g_PlayerInfoList[iPlayer].name && 0 == stricmp(g_PlayerExtraInfo[iPlayer].teamname,g_TeamInfo[i].name)) + { + fprintf(pFile,"%-20s\t%d\t%d\t%d\t%d\t%s\r\n",(const char*)g_PlayerInfoList[iPlayer].name,g_PlayerExtraInfo[iPlayer].frags,g_PlayerExtraInfo[iPlayer].deaths,g_PlayerInfoList[iPlayer].ping,g_PlayerInfoList[iPlayer].packetloss,AgGetAuthID(iPlayer).c_str()); + } + } + fputs("\r\n",pFile); + } + } + } + else + { + //List the frags. + fputs("Player \tFrags\tDeaths\tPing\tLoss\tAuthID\r\n",pFile); + for (int iPlayer = 1; iPlayer <= gEngfuncs.GetMaxClients(); iPlayer++) + { + if (g_PlayerInfoList[iPlayer].name != NULL && 0 != strlen(g_PlayerInfoList[iPlayer].name)) + { + fprintf(pFile,"%-20s\t%d\t%d\t%d\t%d\t%s\r\n",(const char*)g_PlayerInfoList[iPlayer].name,g_PlayerExtraInfo[iPlayer].frags,g_PlayerExtraInfo[iPlayer].deaths,g_PlayerInfoList[iPlayer].ping,g_PlayerInfoList[iPlayer].packetloss,AgGetAuthID(iPlayer).c_str()); + } + } + fputs("\r\n",pFile); + } + + //Close it up. + fflush(pFile); + fclose(pFile); +} +//-- Martin Webrant diff --git a/cl_dll/aghl/agmatchreport.h b/cl_dll/aghl/agmatchreport.h new file mode 100644 index 00000000..f3dde614 --- /dev/null +++ b/cl_dll/aghl/agmatchreport.h @@ -0,0 +1,21 @@ +//++ BulliT + +#if !defined(AFX_AGMATCHREPORT_H__0DF56E7E_7803_4FDE_BE99_6609E45A7D41__INCLUDED_) +#define AFX_AGMATCHREPORT_H__0DF56E7E_7803_4FDE_BE99_6609E45A7D41__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgMatchReport +{ +public: + AgMatchReport(); + virtual ~AgMatchReport(); + + void Save(); +}; + +#endif // !defined(AFX_AGMATCHREPORT_H__0DF56E7E_7803_4FDE_BE99_6609E45A7D41__INCLUDED_) + +//-- Martin Webrant diff --git a/cl_dll/aghl/agminidump.cpp b/cl_dll/aghl/agminidump.cpp new file mode 100644 index 00000000..66bbcd96 --- /dev/null +++ b/cl_dll/aghl/agminidump.cpp @@ -0,0 +1,151 @@ +//++ BulliT + +#ifdef AG_USE_MINIDUMP + +#ifdef CLIENT_DLL //Only check problems on client... +#define DUMPNAME "agclient.dmp" +#include "hud.h" +#include "cl_util.h" +#include "agglobal.h" + +/* +#else +#define DUMPNAME "agserver.dmp" +#include "agglobal.h" +#endif +*/ + +#define VC_EXTRALEAN +#define WIN32_LEAN_AND_MEAN +#define NOWINRES +#define NOSERVICE +#define NOMCX +#define NOIME +#include +#include + +#if _MSC_VER < 1300 +#define DECLSPEC_DEPRECATED +// VC6: change this path to your Platform SDK headers +#include "dbghelp.h" // must be XP version of file +#else +// VC7: ships with updated headers +#include "dbghelp.h" +#endif + +// based on dbghelp.h +typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, + CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam + ); + +static LONG WINAPI TopLevelFilter( struct _EXCEPTION_POINTERS *pExceptionInfo ) +{ + LONG retval = EXCEPTION_EXECUTE_HANDLER;//EXCEPTION_CONTINUE_SEARCH; + HWND hParent = NULL; // find a better value for your app + + // firstly see if dbghelp.dll is around and has the function we need + // look next to the EXE first, as the one in System32 might be old + // (e.g. Windows 2000) + HMODULE hDll = NULL; + char szDbgHelpPath[MAX_PATH]; + char szMiniDump[MAX_PATH]; + + if (GetModuleFileName( GetModuleHandle("client.dll"), szDbgHelpPath, MAX_PATH )) + { + char *pSlash = strrchr( szDbgHelpPath, '\\' ); + if (pSlash) + { + strcpy( pSlash+1, "DBGHELP.DLL" ); + hDll = ::LoadLibrary( szDbgHelpPath ); + } + } + + if (GetModuleFileName( GetModuleHandle("client.dll"), szMiniDump, MAX_PATH )) + { + char *pSlash = strrchr( szMiniDump, '\\' ); + if (pSlash) + { + strcpy( pSlash+1, DUMPNAME ); + } + } + + if (hDll==NULL) + { + // load any version we can + hDll = ::LoadLibrary( "DBGHELP.DLL" ); + } + + LPCTSTR szResult = NULL; + + if (hDll) + { + MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" ); + if (pDump) + { + char szScratch [MAX_PATH]; + + // create the file + HANDLE hFile = ::CreateFile( szMiniDump, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL ); + + if (hFile!=INVALID_HANDLE_VALUE) + { + _MINIDUMP_EXCEPTION_INFORMATION ExInfo; + + ExInfo.ThreadId = ::GetCurrentThreadId(); + ExInfo.ExceptionPointers = pExceptionInfo; + ExInfo.ClientPointers = NULL; + + // write the dump + BOOL bOK = pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL ); + if (bOK) + { + sprintf( szScratch, "Saved dump file to '%s'", szMiniDump ); + szResult = szScratch; + //retval = EXCEPTION_EXECUTE_HANDLER; + } + else + { + sprintf( szScratch, "Failed to save dump file to '%s' (error %d)", szMiniDump, GetLastError() ); + szResult = szScratch; + } + ::CloseHandle(hFile); + } + else + { + sprintf( szScratch, "Failed to create dump file '%s' (error %d)", szMiniDump, GetLastError() ); + szResult = szScratch; + } + } + else + { + szResult = "DBGHELP.DLL too old"; + } + } + else + { + szResult = "DBGHELP.DLL not found"; + } + + AgLog(szResult); + + return retval; +} + +class AgMiniDump +{ +public: + AgMiniDump() + { + ::SetUnhandledExceptionFilter( TopLevelFilter ); + }; +}; + +AgMiniDump g_MiniDump; //The dumper. + +#endif CLIENT_DLL + +#endif AG_USE_MINIDUMP +//-- Martin Webrant diff --git a/cl_dll/aghl/agmodel.cpp b/cl_dll/aghl/agmodel.cpp new file mode 100644 index 00000000..4f2ce5ce --- /dev/null +++ b/cl_dll/aghl/agmodel.cpp @@ -0,0 +1,292 @@ +//++ BulliT +//Most parts written by David "Nighthawk" Flor (dflor@mach3.com) for the mod Opera (http://www.halflife.net/opera) +//Parts of code from Valve Software mdlviewer (CalcBonePosition). + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "parsemsg.h" +#include "com_model.h" +#include "studio.h" +#include "com_weapons.h" +#include "AgModel.h" + +#ifdef AG_USE_CHEATPROTECTION + +void CalcBonePosition(int frame, mstudiobone_t *pbone, mstudioanim_t *panim, float *pos); +extern int g_iPure; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgModel::AgModel() +{ + m_vMinBounds = Vector(0,0,0); + m_vMaxBounds = Vector(0,0,0); + m_iVertexCount = 0; + + m_vMinBone = Vector(0,0,0); + m_vMaxBone = Vector(0,0,0); + m_iBoneCount = 0; + m_bCorrupt = false; + m_bFoundAndChecked = false; +} + +AgModel::~AgModel() +{ + +} + + +void AgModel::AddVertex( const Vector &vPoint ) +{ + if (m_iVertexCount == 0) + { + m_vMinBounds = m_vMaxBounds = vPoint; + } + else + { + m_vMinBounds.x = min( m_vMinBounds.x, vPoint.x ); + m_vMinBounds.y = min( m_vMinBounds.y, vPoint.y ); + m_vMinBounds.z = min( m_vMinBounds.z, vPoint.z ); + + m_vMaxBounds.x = max( m_vMaxBounds.x, vPoint.x ); + m_vMaxBounds.y = max( m_vMaxBounds.y, vPoint.y ); + m_vMaxBounds.z = max( m_vMaxBounds.z, vPoint.z ); + } + m_iVertexCount++; +} + +void AgModel::AddBone( const Vector &vPoint ) +{ + if (m_iBoneCount == 0) + { + m_vMinBone = m_vMaxBone = vPoint; + } + else + { + m_vMinBone.x = min( m_vMinBone.x, vPoint.x ); + m_vMinBone.y = min( m_vMinBone.y, vPoint.y ); + m_vMinBone.z = min( m_vMinBone.z, vPoint.z ); + + m_vMaxBone.x = max( m_vMaxBone.x, vPoint.x ); + m_vMaxBone.y = max( m_vMaxBone.y, vPoint.y ); + m_vMaxBone.z = max( m_vMaxBone.z, vPoint.z ); + } + m_iBoneCount++; +} + +void AgModel::AddBonesToVertices( void ) +{ + Vector vAdjust; + + if (m_iBoneCount > 0) + { + vAdjust = (m_vMaxBone - m_vMinBone); + + AddVertex( vAdjust / 2 ); + AddVertex( -(vAdjust / 2) ); + + m_vMinBone = m_vMaxBone = Vector(0,0,0); + m_iBoneCount = 0; + } +} + + +void AgModel::ReadModel(const char *szModelName) +{ + char *pBuffer; + char *pTempBuffer; + char szFullName[ _MAX_PATH ]; + float flBone[3]; + + strcpy( szFullName, szModelName ); + pBuffer = (char*)gEngfuncs.COM_LoadFile( szFullName, 5, NULL ); + if (pBuffer) + { + studiohdr_t *pHeader; + mstudiobodyparts_t *pBodyParts; + mstudiomodel_t *pModel; + long iCnt; + long iModelCnt, iModels; + long iVert, iVertCnt; + vec3_t *pVert; + mstudiobone_t *pBone; + long iBoneCnt, iBones; + mstudioseqdesc_t *pSequence; + long iSequenceCnt, iSequences; + mstudioanim_t *pAnim; + long iFrameCnt, iFrames; + + pHeader = (studiohdr_t *)pBuffer; + if (10 == pHeader->version) + { + pTempBuffer = (pBuffer + pHeader->bodypartindex); + pBodyParts = (mstudiobodyparts_t *)pTempBuffer; + iModels = 0; + for (iCnt = 0; iCnt < pHeader->numbodyparts; iCnt++) + iModels += pBodyParts[iCnt].nummodels; + pTempBuffer += (pHeader->numbodyparts * sizeof(mstudiobodyparts_t)); + + pModel = (mstudiomodel_t *)pTempBuffer; + for (iModelCnt = 0; iModelCnt < iModels; iModelCnt++) + { + iVert = pModel[iModelCnt].numverts; + pVert = (vec3_t *)(pBuffer + pModel[iModelCnt].vertindex); + for (iVertCnt = 0; iVertCnt < iVert; iVertCnt++) + { + AddVertex( pVert[iVertCnt] ); + } + } + + pBone = (mstudiobone_t *)(pBuffer + pHeader->boneindex); + iBones = pHeader->numbones; + + pSequence = (mstudioseqdesc_t *)(pBuffer + pHeader->seqindex); + iSequences = pHeader->numseq; + for (iSequenceCnt = 0; iSequenceCnt < iSequences; iSequenceCnt++) + { + iFrames = pSequence[iSequenceCnt].numframes; + + pTempBuffer = (pBuffer + pSequence[iSequenceCnt].animindex); + pAnim = (mstudioanim_t *)pTempBuffer; + for (iBoneCnt = 0; iBoneCnt < iBones; iBoneCnt++) + { + for (iFrameCnt = 0; iFrameCnt < iFrames; iFrameCnt++) + { + CalcBonePosition( iFrameCnt, pBone + iBoneCnt, + pAnim, flBone ); + + AddBone( flBone ); + } + } + + AddBonesToVertices(); + } + m_bFoundAndChecked = true; + } + else + { + m_bCorrupt = true; + } + gEngfuncs.COM_FreeFile( pBuffer ); + } +} + +void CalcBonePosition( int frame, mstudiobone_t *pbone, mstudioanim_t *panim, float *pos ) +{ + float s = 0; + int j, k; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + pos[j] = pbone->value[j]; // default; + if (panim->offset[j] != 0) + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + + k = frame; + // find span of values that includes the frame we want + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + } + // if we're inside the span + if (panimvalue->num.valid > k) + { + // and there's more data in the span + if (panimvalue->num.valid > k + 1) + { + pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[k+1].value * pbone->scale[j]; + } + } + else + { + // are we at the end of the repeating values section and there's another section with data? + if (panimvalue->num.total <= k + 1) + { + pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; + } + } + } + } +} + +bool AgModel::CheckModel(const char* szModelName) +{ + try + { + ReadModel(szModelName); + } + catch(...) + { + m_bCorrupt = true; + } + + if (m_bCorrupt) + { + char szMessage[256]; + sprintf(szMessage,"Server enforces model check and %s seems to be corrupt.\n",szModelName); + AgLog(szMessage); + ConsolePrint(szMessage); +#ifdef _DEBUG + return true; +#else + return false; +#endif + } + + Vector vMaxBounds = Vector(0,0,0); + Vector vBounds = m_vMaxBounds - m_vMinBounds; + if ( !strnicmp( szModelName, "/models/player", 14) ) + { + if (0 < g_iPure) + vMaxBounds = Vector( 78, 30, 98 ); + else + vMaxBounds = Vector( 105, 105, 105 ); //Big fucking models allowed.. + } + else if ( !strnicmp( szModelName, "/models/p_", 9 ) ) + vMaxBounds = Vector( 42, 21, 60 ); + else if ( !strnicmp( szModelName, "/models/w_", 9 ) ) + vMaxBounds = Vector( 82, 69, 76); + else if ( !strnicmp( szModelName, "/models/v_", 9 ) ) + vMaxBounds = Vector( 46, 55, 120 ); + else + vMaxBounds = Vector( 100, 100, 100 ); + + if (vBounds.x > vMaxBounds.x || vBounds.y > vMaxBounds.y || vBounds.z > vMaxBounds.z) + { + char szMessage[256]; + sprintf(szMessage,"Server enforces model check and %s is not valid. Your model got these ranges: %.4f,%.4f,%.4f\n",szModelName,vBounds.x, vBounds.y, vBounds.z); + AgLog(szMessage); + sprintf(szMessage,"Server enforces model check and %s is not valid.\n",szModelName); + ConsolePrint(szMessage); +#ifdef _DEBUG + return true; +#else + return false; +#endif + } + + return true; +} + +bool AgModel::IsChecked() +{ + return m_bFoundAndChecked; +} + +#endif //AG_USE_CHEATPROTECTION + +//-- Martin Webrant diff --git a/cl_dll/aghl/agmodel.h b/cl_dll/aghl/agmodel.h new file mode 100644 index 00000000..7e557ad8 --- /dev/null +++ b/cl_dll/aghl/agmodel.h @@ -0,0 +1,46 @@ +//++ BulliT + +#if !defined(AFX_AGMODEL_H__EC242BA8_B4C4_45B1_A6E7_1BF186C6B9CF__INCLUDED_) +#define AFX_AGMODEL_H__EC242BA8_B4C4_45B1_A6E7_1BF186C6B9CF__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef AG_USE_CHEATPROTECTION + +#include "AgGlobal.h" + +class AgModel +{ + bool m_bCorrupt; + bool m_bFoundAndChecked; + + Vector m_vMinBounds; + Vector m_vMaxBounds; + long m_iVertexCount; + + Vector m_vMinBone; + Vector m_vMaxBone; + long m_iBoneCount; + + void AddVertex(const Vector &vPoint); + void AddBone(const Vector &vPoint); + void AddBonesToVertices(void); + void ReadModel(const char* szModelName); + +public: + AgModel(); + virtual ~AgModel(); + + bool CheckModel(const char* szModelName); + bool IsChecked(); + +}; + +#endif //AG_USE_CHEATPROTECTION + + +#endif // !defined(AFX_AGMODEL_H__EC242BA8_B4C4_45B1_A6E7_1BF186C6B9CF__INCLUDED_) + +//-- Martin Webrant diff --git a/cl_dll/aghl/agmodelcheck.cpp b/cl_dll/aghl/agmodelcheck.cpp new file mode 100644 index 00000000..8a490345 --- /dev/null +++ b/cl_dll/aghl/agmodelcheck.cpp @@ -0,0 +1,128 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" +#include "studio_util.h" +#include "r_studioint.h" +#include "parsemsg.h" +#include "AgModel.h" +#include "AgModelCheck.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +#ifdef AG_USE_CHEATPROTECTION + + +AgModelCheck g_ModelCheck; +extern int g_iPure; +extern engine_studio_api_t IEngineStudio; + +static char* s_szPure1[] = +{ + "gordon", + "helmet", + "zombie", + "robo", + "recon", + "hgrunt", + "gman", + "barney", + "gina", + "scientist", + "robo", + "pmers", + "player", + "blue", + "red", +}; + +static char szDisconnect[] = "disconnect\n"; + +AgModelCheck::AgModelCheck() +{ + m_bScannedStandard = false; +} + +AgModelCheck::~AgModelCheck() +{ +// m_setChecked.erase(); +} + +bool AgModelCheck::Check() +{ + if (m_bScannedStandard) + return CheckCurrent(); + + for (int i = 0; i < (sizeof(s_szPure1) / sizeof(s_szPure1[0])); i++) + { + if (!CheckOne(s_szPure1[i])) + return false; + } + m_bScannedStandard = true; + return CheckCurrent(); +} + +bool AgModelCheck::CheckCurrent() +{ + bool bPassed = true; + + for ( int i = 1; i <= MAX_PLAYERS; i++ ) + { + GetPlayerInfo( i, &g_PlayerInfoList[i] ); + if (NULL == g_PlayerInfoList[i].name) + continue; + + bPassed = CheckOne(gEngfuncs.PlayerInfo_ValueForKey(i,"model")); + if (!bPassed) + break; + } + + return bPassed; +} + +bool AgModelCheck::CheckOne(const char* pszModel) +{ + bool bPassed = true; + char szModel[MAX_PATH]; + sprintf(szModel,"/models/player/%s/%s.mdl",pszModel,pszModel); + if (0 != m_setChecked.size() && m_setChecked.end() != m_setChecked.find(szModel)) + return true; + +#ifdef _DEBUG + char szMessage[256]; + sprintf(szMessage,"Checking %s\n",szModel); + ConsolePrint(szMessage); +#endif + + AgModel Model; + bPassed = Model.CheckModel(szModel); + bool bChecked = Model.IsChecked(); + + if (!bPassed) + { + ServerCmd( "say Disconnected for using invalid model.\n" ); + ClientCmd( szDisconnect ); + return false; + } + if (bChecked) + { + //No need to try to load it again. + m_setChecked.insert(szModel); + } + + return true; +} + +#endif //AG_USE_CHEATPROTECTION + + +//-- Martin Webrant diff --git a/cl_dll/aghl/agmodelcheck.h b/cl_dll/aghl/agmodelcheck.h new file mode 100644 index 00000000..64ef2287 --- /dev/null +++ b/cl_dll/aghl/agmodelcheck.h @@ -0,0 +1,37 @@ +//++ BulliT + +#if !defined(AFX_AGMODELCHECK_H__4596B2F8_81A4_4927_9A82_9637C7F9A3C9__INCLUDED_) +#define AFX_AGMODELCHECK_H__4596B2F8_81A4_4927_9A82_9637C7F9A3C9__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "AgGlobal.h" +#include "AgModel.h" + +#ifdef AG_USE_CHEATPROTECTION + +class AgModelCheck +{ + typedef set > AgCheckedSet; + AgCheckedSet m_setChecked; + bool m_bScannedStandard; + + bool CheckCurrent(); + +public: + AgModelCheck(); + virtual ~AgModelCheck(); + + bool Check(); + bool CheckOne(const char* pszModel); +}; + +extern AgModelCheck g_ModelCheck; + +#endif //AG_USE_CHEATPROTECTION + +#endif // !defined(AFX_AGMODELCHECK_H__4596B2F8_81A4_4927_9A82_9637C7F9A3C9__INCLUDED_) + +//-- Martin Webrant diff --git a/cl_dll/aghl/agpak.cpp b/cl_dll/aghl/agpak.cpp new file mode 100644 index 00000000..fb77b4b3 --- /dev/null +++ b/cl_dll/aghl/agpak.cpp @@ -0,0 +1,135 @@ +//++ BulliT + +#include "agglobal.h" +#include "agpak.h" + +typedef struct +{ unsigned char magic[4]; // Name of the new WAD format + long diroffset; // Position of WAD directory from start of file + long dirsize; // Number of entries * 0x40 (64 char) +} pakheader_t; + + +typedef struct +{ + unsigned char filename[0x38]; // Name of the file, Unix style, with extension, + // 50 chars, padded with '\0'. + long offset; // Position of the entry in PACK file + long size; // Size of the entry in PACK file +} pakentry_t; + + +AgPak::AgPak() +{ +} + +bool AgPak::GetEntries(const AgString& sPakfile, const AgString& sSearch1, const AgString& sSearch2, AgStringList& lstEntries) +{ + AgString sSearchString1; + AgString sSearchString2; + sSearchString1 = sSearch1; + sSearchString2 = sSearch2; + AgToLower(sSearchString1); + AgToLower(sSearchString2); + + pakheader_t Header; + DWORD dwRead = 0; + HANDLE h = CreateFile(sPakfile.c_str(),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0); + + //Read header. + if (!ReadFile(h,(void*)&Header,sizeof(Header),&dwRead,NULL)) + return false; + if (sizeof(Header) != dwRead) + return false; + + //Move to directory list. + SetFilePointer(h,Header.diroffset,NULL,FILE_BEGIN); + + //Allocate array of entries. + pakentry_t* pEntries = (pakentry_t*)malloc(Header.dirsize); + + //Read the entries. + if (!ReadFile(h,(void*)pEntries,Header.dirsize,&dwRead,NULL)) + { + free(pEntries); + CloseHandle(h); + return false; + } + CloseHandle(h); + + if (Header.dirsize != (long)dwRead) + { + free(pEntries); + return false; + } + + //Calc number of entries. + int iEntries = Header.dirsize / sizeof(pakentry_t); + + //Read directory listing + for (int i = 0; i < iEntries; i++) + { + AgString sFilename; + sFilename = (const char*)pEntries[i].filename; + AgToLower(sFilename); + + if (0 != sSearchString1.length()) + { + //Check if the file contains the search1 string. + if (NPOS != sFilename.find(sSearchString1)) + { + if (0 != sSearchString2.length()) + { + if (NPOS != sFilename.find(sSearchString2)) + lstEntries.push_back(sFilename); + } + else + lstEntries.push_back(sFilename); + } + } + else + { + //Add all files + lstEntries.push_back(sFilename); + } + } + + free((void*)pEntries); + return true; +} + + +/* +Quake PAK Format + +Figured out by Pete McCormick (petra@force.net) I am not responsible for any damage this does, enjoy, +and please email me any comments! +Pete + +=Format= +Header +(4 unsigned chars) signature = 'PACK' +(4 unsigned chars, int) directory offeset +(4 unsigned chars, int) directory lenght + +Directory +(56 unsigned chars, char) file name +(4 unsigned chars, int) file position +(4 unsigned chars, int) file lenght + +File at each position (? unsigned chars, char) file data +Description - The signature must be present in all PAKs; it's the way Quake knows its a real PAK file. +The directory offset is where the directory listing starts, and the lenght is its lenght. +In the actuall directory listing, the three options, 56 unsigned chars of a name, +the files position and lenght, are repeating until the running total of the length (increment by 64) is reached. +If the directory lenght mod 64 is not a even number, you know their is something wrong. +And directories are just handled by a making the name something like "/foobar/yeahs.txt". Short and simple. + +Tips - Put the directory entry at the end of the file, so if you added a file, +you'd just rewrite the small directory entry instead of all the data. + +Limits - Unknown file limit. Don't create too many though :) I would think around a 1000, +prehaps 2000 (in which case, 2048 would be reasonible) +*/ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agpak.h b/cl_dll/aghl/agpak.h new file mode 100644 index 00000000..79d6b2a1 --- /dev/null +++ b/cl_dll/aghl/agpak.h @@ -0,0 +1,15 @@ +//++ BulliT +#if !defined(_AG_PAK_H_) +#define _AG_PAK_H_ + +class AgPak +{ +public: + AgPak(); + bool GetEntries(const AgString& sPakfile, const AgString& sSearch1, const AgString& sSearch2, AgStringList& lstEntries); +}; + + +#endif // !defined(_AG_PAK_H_) + +//-- Martin Webrant diff --git a/cl_dll/aghl/agvariablechecker.cpp b/cl_dll/aghl/agvariablechecker.cpp new file mode 100644 index 00000000..d26539c5 --- /dev/null +++ b/cl_dll/aghl/agvariablechecker.cpp @@ -0,0 +1,329 @@ +//++ BulliT + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" +#include "studio_util.h" +#include "r_studioint.h" +#include "AgVariableChecker.h" +#include "AgModelCheck.h" + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +#ifdef AG_USE_CHEATPROTECTION + +extern engine_studio_api_t IEngineStudio; + +#define MAX_VIOLATIONS 5 + +struct VARIABLES +{ + char szName[20]; + double dMin; + double dMax; + double dDefault; + bool bKeepSame; + bool bAllowChangeAtInit; +}; + +static VARIABLES s_Variables[]= +{ + //Evironment + "r_lightmap",-1,0,-1,false,true, + "direct",0.9,0.9,0.9,false,true, + "brightness",0,30,1,false,true, + "lambert",1.5,1.5,1.5,true,true, + "cl_solid_players",1,1,1,false,true, + "cl_himodels",0,1,0,true,false, + //Sounds + "s_distance",10,60,60,false,true, + "s_min_distance",1,20,8,false,true, + "s_max_distance",20,1000,1000,false,true, + "s_occlude",0,1,1,false,true, + "s_occfactor",0.20,0.25,0.25,false,true, + "s_refgain",0.4,0.45,0.41,false,true, + //Cheats is somehow client also? + "sv_cheats",0,0,0,true,true, +}; + + +static VARIABLES s_VariablesFast[]= +{ + //Movement + "m_pitch",-0.044,0.044,0.022,false,true, + "cl_backspeed",300,500,400,false,true, + "cl_sidespeed",300,500,400,false,true, + "cl_forwardspeed",300,500,400,false,true, + "cl_upspeed",300,500,320,false,true, + "default_fov",30,130,90,false,true, + //Net settings + "cl_updaterate",15,100,30,false,true, + "cl_cmdrate",15,100,30,false,true, + "ex_extrapmax",1.2,1.2,1.2,false,true, +#ifdef CLIENT_WEAPONS + "ex_interp",0.05,0.1,0.1,false,true, +#else + "ex_interp",0.1,0.1,0.1,false,true, +#endif +// Fixed in next patch. + "ex_minvelocity",0,0,0,false,true, + "ex_maxspeed",750,750,750,false,true, + "ex_maxaccel",2000,2000,2000,false,true, + "ex_maxerrordistance",64,64,64,false,true, + "cl_nopred",0,0,0,false,true, + "ex_correct",0,0,0,false,true, + "ex_diminishextrap",0,0,0,false,true, +}; + +/* +ex_correct +ex_extrapmax +ex_maxerror distance +cl_nopred +*/ + +static VARIABLES s_VariablesHardware[]= +{ + //Open GL settings. +// "lightgamma",0,3,2.5,true,false, +// "texgamma",1,3,2,true,false, + "gl_max_size",128,512,512,false,false, + "gl_zmax",2048,9999,4096,false,true, + "gl_alphamin",0.25,0.25,0.25,false,true, + "gl_nobind",0,0,0,false,true, + "gl_picmip",0,2,0,false,true, + "gl_playermip",0,5,0,false,true, + //"gl_spriteblend",1,1,1,true,true, + "gl_monolights",0,0,0,true,true, +}; + +static VARIABLES s_VariablesPure2[]= +{ + "s_distance",10,10,10,false,true, + "s_rolloff",10,10,10,false,true, + "s_min_distance",8,8,8,false,true, + "s_max_distance",1000,1000,1000,false,true, +}; + +static VARIABLES s_VariablesPure3[]= +{ + "s_a3d",0,0,0,false,true, +}; + + +AgVariableChecker g_VariableChecker; +static char szDisconnect[] = "disconnect\n"; + +AgVariableChecker::AgVariableChecker() +{ + m_bHardware = false; + m_bInit = false; + m_dwNextCheck = m_dwNextCheckFast = m_dwNextA3D = GetTickCount(); + m_iViolations = 0; + m_bActive = false; +} + +AgVariableChecker::~AgVariableChecker() +{ + +} + +void AgVariableChecker::Activate() +{ + m_bActive = true; + m_bInit = false; +} + + +bool InitVariables(VARIABLES* pvarArray,int iElements) +{ + for (int i = 0; i < iElements; i++) + { + if (!gEngfuncs.pfnGetCvarPointer(pvarArray[i].szName )) + continue; + + double dValue = gEngfuncs.pfnGetCvarFloat(pvarArray[i].szName); + + if (dValue < (pvarArray[i].dMin - 0.0001) + ||dValue > (pvarArray[i].dMax + 0.0001)) + { + if (pvarArray[i].bAllowChangeAtInit) + { + //Correct it. + gEngfuncs.Cvar_SetValue(pvarArray[i].szName, pvarArray[i].dDefault); + + //This dudes standard aint good enough - corrected it for him. + char szMessage[256]; + sprintf(szMessage,"Server enforces variables and \"%s\" was automatically reset to the HL default %f.\n",pvarArray[i].szName,pvarArray[i].dDefault); + ConsolePrint(szMessage); + AgLog(szMessage); + } + else + { + //This dudes standard aint good enough. + char szMessage[256]; + sprintf(szMessage,"Server enforces variables and \"%s\" needs to be between %f and %f. Your variable is set to %f.\n",pvarArray[i].szName,pvarArray[i].dMin,pvarArray[i].dMax,dValue); + ConsolePrint(szMessage); + AgLog(szMessage); + return false; + } + } + + //Save this value as default. + pvarArray[i].dDefault = gEngfuncs.pfnGetCvarFloat(pvarArray[i].szName); + if (pvarArray[i].bKeepSame) + pvarArray[i].dMin = pvarArray[i].dMax = pvarArray[i].dDefault; + } + return true; +} + +void CheckVariables(VARIABLES* pvarArray,int iElements, short& iViolations) +{ + for (int i = 0; i < iElements; i++) + { + if (!gEngfuncs.pfnGetCvarPointer(pvarArray[i].szName )) + continue; + + double dValue = gEngfuncs.pfnGetCvarFloat(pvarArray[i].szName); + if (dValue < (pvarArray[i].dMin - 0.0001) + ||dValue > (pvarArray[i].dMax + 0.0001)) + { + char szMessage[256]; + if (pvarArray[i].bKeepSame && pvarArray[i].bAllowChangeAtInit) + sprintf(szMessage,"Server enforces variables and \"%s\" needs to be the same during the game\n",pvarArray[i].szName); + else + sprintf(szMessage,"Server enforces variables and \"%s\" needs to be between %f and %f.\n",pvarArray[i].szName,pvarArray[i].dMin,pvarArray[i].dMax); + ConsolePrint(szMessage); + + if (pvarArray[i].bAllowChangeAtInit) + { + //Reset to previous value. + gEngfuncs.Cvar_SetValue(pvarArray[i].szName, pvarArray[i].dDefault); + iViolations++; + } + else + { + iViolations = MAX_VIOLATIONS + 1; + } + + + sprintf(szMessage,"say Warned for using variable %s with value %lf (%d violation(s)",pvarArray[i].szName,dValue,iViolations); + ServerCmd(szMessage); + } + } +} + +bool AgVariableChecker::Init() +{ + if (m_bInit) + return true; + + bool bSuccess = true; + + m_bHardware = IEngineStudio.IsHardware() ? true : false; + + if (!InitVariables(s_Variables,sizeof(s_Variables)/sizeof(s_Variables[0]))) + bSuccess = false; + + if (!InitVariables(s_VariablesFast,sizeof(s_VariablesFast)/sizeof(s_VariablesFast[0]))) + bSuccess = false; + + if (m_bHardware) + { + if (!InitVariables(s_VariablesHardware,sizeof(s_VariablesHardware)/sizeof(s_VariablesHardware[0]))) + bSuccess = false; + } + + if (bSuccess) + { + m_bInit = true; + return true; + } + + static char szMessage[] = "Variable init failed, exiting.\n"; + ConsolePrint(szMessage); + AgLog(szMessage); + + ServerCmd( "say Disconnected for using invalid variable.\n" ); + ClientCmd( szDisconnect ); + + Reset(); + + return false; +} + +void AgVariableChecker::Reset() +{ + m_bHardware = false; + m_bInit = false; + m_bActive = false; + m_iViolations = 0; +} + +bool AgVariableChecker::Check() +{ + if (!m_bActive) + return true; + + if (!m_bInit) + { + return Init(); + } + + DWORD dwNow = GetTickCount(); + if (m_dwNextCheck < dwNow) + { + CheckVariables(s_Variables,sizeof(s_Variables)/sizeof(s_Variables[0]),m_iViolations); + + if (m_bHardware) + CheckVariables(s_VariablesHardware,sizeof(s_VariablesHardware)/sizeof(s_VariablesHardware[0]),m_iViolations); + + if (g_iPure > 1) + CheckVariables(s_VariablesPure2,sizeof(s_VariablesPure2)/sizeof(s_VariablesPure2[0]),m_iViolations); + + m_dwNextCheck = dwNow + 500; //500ms for the less important variables. + } + + if (m_dwNextCheckFast < dwNow) + { + CheckVariables(s_VariablesFast,sizeof(s_VariablesFast)/sizeof(s_VariablesFast[0]),m_iViolations); + m_dwNextCheckFast = dwNow + 150; //150ms for the important variables. + } + + if (g_iPure > 2) + { + if (m_dwNextA3D < dwNow) + { + CheckVariables(s_VariablesPure3,sizeof(s_VariablesPure3)/sizeof(s_VariablesPure3[0]),m_iViolations); + ClientCmd("s_disable_a3d\n"); + m_dwNextA3D = dwNow + 5000; //5 seconds . + } + } + + if (m_iViolations > MAX_VIOLATIONS) + { + static char szMessageServer[] = "say Disconnected for repeated cvar violations\n"; + static char szMessage[] = "Cheat check: Disconnected for repeated cvar violations\n"; + ServerCmd(szMessageServer); + AgLog(szMessage); + ConsolePrint(szMessage); + ClientCmd(szDisconnect); + Reset(); + return false; + } + + return true; +} + +#endif //AG_USE_CHEATPROTECTION + +//-- Martin Webrant diff --git a/cl_dll/aghl/agvariablechecker.h b/cl_dll/aghl/agvariablechecker.h new file mode 100644 index 00000000..4da46cbf --- /dev/null +++ b/cl_dll/aghl/agvariablechecker.h @@ -0,0 +1,72 @@ +//++ BulliT +#if !defined(AFX_AGVARIABLECHECKER_H__73BB9962_9A14_4A89_B856_FEFB40FC1E13__INCLUDED_) +#define AFX_AGVARIABLECHECKER_H__73BB9962_9A14_4A89_B856_FEFB40FC1E13__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef AG_USE_CHEATPROTECTION + +class AgVariableChecker +{ + bool m_bActive; + bool m_bHardware; + bool m_bInit; + DWORD m_dwNextCheck; + DWORD m_dwNextCheckFast; + DWORD m_dwNextA3D; + short m_iViolations; + void Reset(); + +public: + AgVariableChecker(); + virtual ~AgVariableChecker(); + + bool Init(); + bool Check(); + void Activate(); +}; + +extern AgVariableChecker g_VariableChecker; + +#endif //AG_USE_CHEATPROTECTION + +extern int g_iPure; + +extern cvar_t *cl_pitchspeed; +inline float ag_cl_pitchspeed() +{ + if (0 < g_iPure) + return 255; + return cl_pitchspeed->value; +} + +extern cvar_t *cl_pitchup; +inline float ag_cl_pitchup() +{ + if (0 < g_iPure) + return 89; + return cl_pitchup->value; +} + +extern cvar_t *cl_pitchdown; +inline float ag_cl_pitchdown() +{ + if (0 < g_iPure) + return 89; + return cl_pitchdown->value; +} + +extern cvar_t *cl_yawspeed; +inline float ag_cl_yawspeed() +{ + if (0 < g_iPure) + return 210; + return cl_yawspeed->value; +} + + + +#endif // !defined(AFX_AGVARIABLECHECKER_H__73BB9962_9A14_4A89_B856_FEFB40FC1E13__INCLUDED_) +//-- Martin Webrant diff --git a/cl_dll/aghl/agversioninfo.cpp b/cl_dll/aghl/agversioninfo.cpp new file mode 100644 index 00000000..45570057 --- /dev/null +++ b/cl_dll/aghl/agversioninfo.cpp @@ -0,0 +1,198 @@ +#include + +#ifdef AG_USE_CHEATPROTECTION + +#include "AgGlobal.h" +#include "AgVersionInfo.h" + +#pragma comment(lib,"version.lib") + +DWORD AgVersionInfo::SetError() +{ + m_dwLastError = ::GetLastError(); + if (0 == m_dwLastError) + m_dwLastError = (DWORD)-1; + return m_dwLastError; +} + +DWORD AgVersionInfo::LoadVersionInfo(LPCSTR pszFileName) +{ + try + { + // get size of fileversion + DWORD dwLen = ::GetFileVersionInfoSize((LPTSTR)pszFileName,&m_dwHandle); + + if (0 == dwLen) + return SetError(); + + // get data-info + m_pszData = (char*)malloc(dwLen+16); + BOOL bRet = ::GetFileVersionInfo((LPTSTR)pszFileName,m_dwHandle,dwLen,m_pszData); + + if (!bRet) + { + //assert(FALSE); + return SetError(); + } + + // get VS_FIXEDFILEINFO struct + + VS_FIXEDFILEINFO* pInfo = NULL; + UINT uiSize = 0; + + if (!::VerQueryValue((BYTE*)(LPCSTR)m_pszData,"\\",(LPVOID*)&pInfo,&uiSize)) + { + //assert(FALSE); + return SetError(); + } + + // did we get something? + + if (uiSize != sizeof(m_ffi)) + { + //assert(FALSE); + return SetError(); + } + + // does the structure have correct signature and version? + + if (VS_FFI_SIGNATURE != pInfo->dwSignature || VS_FFI_STRUCVERSION != pInfo->dwStrucVersion) + { + //assert(FALSE); + return SetError(); + } + + // everything ok, copy to our member-struct + + memcpy(&m_ffi,pInfo,uiSize); + + m_dwLastError = 0; + return m_dwLastError; + } + catch (...) + { + AgLog("LoadVersionInfo failed"); + return SetError(); + } + return 0; +} + +BOOL AgVersionInfo::FileVersion(int& iMajor,int& iMinor,int& iMicro,int& iState) const +{ + //assert(!HasErrors()); + + if (HasErrors()) + return FALSE; + + iMajor = (int)(HIWORD(m_ffi.dwFileVersionMS)); + iMinor = (int)(LOWORD(m_ffi.dwFileVersionMS)); + iMicro = (int)(HIWORD(m_ffi.dwFileVersionLS)); + iState = (int)(LOWORD(m_ffi.dwFileVersionLS)); + + return TRUE; +} + +BOOL AgVersionInfo::ProductVersion(int& iMajor,int& iMinor,int& iMicro,int& iState) const +{ + //assert(!HasErrors()); + + if (HasErrors()) + return FALSE; + + iMajor = (int)(HIWORD(m_ffi.dwProductVersionMS)); + iMinor = (int)(LOWORD(m_ffi.dwProductVersionMS)); + iMicro = (int)(HIWORD(m_ffi.dwProductVersionLS)); + iState = (int)(LOWORD(m_ffi.dwProductVersionLS)); + + return TRUE; +} + +const char* AgVersionInfo::GetTextData(LPCSTR pszParameter,DWORD dwLanguage) +{ + static char szParam[MAX_PATH]; + + // must have been initialized properly + + assert(!HasErrors()); + + if (HasErrors()) + return ""; + + LPVOID pInfo; + UINT uiSize; + + if (-1 == dwLanguage) + { + if (-1 == m_dwDefaultLang) + { + // get translation table pointer + + pInfo = NULL; + uiSize = 0; + + if (!::VerQueryValue((BYTE*)(LPCSTR)m_pszData,"\\VarFileInfo\\Translation",&pInfo,&uiSize)) + { + //SetError(); + //assert(FALSE); + return ""; + } + + // did we get it? + + if (0 == uiSize) + { + SetError(); + assert(FALSE); + return ""; + } + + m_dwDefaultLang = *((DWORD*)pInfo); + } + + dwLanguage = m_dwDefaultLang; + } + + // get the parameter + + pInfo = NULL; + uiSize = 0; + + m_dwLastError = 0; + + sprintf(szParam,"\\StringFileInfo\\%04x%04x\\%s",LOWORD(dwLanguage),HIWORD(dwLanguage),pszParameter); + + if (!::VerQueryValue((BYTE*)(LPCSTR)m_pszData,szParam,&pInfo,&uiSize)) + return ""; // the parameter is currently not defined + + // is parameter-value an empty-string? + + if (0 == uiSize) + return ""; + + // copy the value to our own string + + memcpy(szParam,(LPBYTE)pInfo,uiSize); + return szParam; +} + + +BOOL AgVersionInfo::IsRequiredVersion(int iReqMajor, int iReqMinor, int iReqMicro) const +{ + assert(!HasErrors()); + + if (HasErrors()) + return FALSE; + + int iMajor, iMinor, iMicro, iState; + iMajor = iMinor = iMicro = iState = 0; + FileVersion(iMajor, iMinor, iMicro, iState); + + if ((iMajor == iReqMajor && iMinor == iReqMinor && iMicro >= iReqMicro) || + iMajor == iReqMajor && iMinor > iReqMinor || + iMajor > iReqMajor) + return TRUE; + + return FALSE; +} + +#endif //AG_USE_CHEATPROTECTION \ No newline at end of file diff --git a/cl_dll/aghl/agversioninfo.h b/cl_dll/aghl/agversioninfo.h new file mode 100644 index 00000000..f179c38c --- /dev/null +++ b/cl_dll/aghl/agversioninfo.h @@ -0,0 +1,169 @@ +#ifndef __AG_VERSION_INFO_H__ +#define __AG_VERSION_INFO_H__ + +#ifdef AG_USE_CHEATPROTECTION + +class AgVersionInfo +{ +public: + + // Constructs the class. + AgVersionInfo(); + virtual ~AgVersionInfo(); + + // Load versioninfo. + DWORD LoadVersionInfo(LPCSTR pszFileName); // Load versioninfo on a file. + + BOOL HasErrors() const; // Returns TRUE if versioninfo could not be retrivied. + DWORD GetLastError() const; // Returns the windows errorcode. + + // language independant data + + // Get the fileversion. + BOOL FileVersion(int& iMajor,int& iMinor,int& iMicro,int& iState) const; // Get the fileversion. + // Get the productversion. + BOOL ProductVersion(int& iMajor,int& iMinor,int& iMicro,int& iState) const; // Get the productversion. + + BOOL IsDebugBuild() const; // Returns TRUE if the file contains debugging information or is compiled with debugging features enabled. + BOOL IsInfoInferred() const; // Returns TRUE if the file's version structure was created dynamically; therefore, some of the members in this class may be empty or incorrect. + BOOL IsPatched() const; // Returns TRUE if the file has been modified and is not identical to the original shipping file of the same version number. + BOOL IsPreRelease() const; // Returns TRUE if the file is a development version, not a commercially released product. + BOOL IsPrivateBuild() const; // Returns TRUE if the file was not built using standard release procedures. + BOOL IsSpecialBuild() const; // Returns TRUE if the file was built by the original company using standard release procedures but is a variation of the normal file of the same version number. + + DWORD FileFlag() const; // Returns a bitmask that specifies the Boolean attributes of the file. Use IsXXXX functions instead. + DWORD OSFlag() const; // Returns: VOS_NT The file was designed for Windows NT. VOS__WINDOWS32 The file was designed for the Win32 API. For more flags see dwFileOS variable for VS_FIXEDFILEINFO in MSDN. + DWORD TypeFlag() const; // Returns: VFT_APP The file contains an application. VFT_DLL The file contains a dynamic-link library (DLL). For more flags see dwFileType variable for VS_FIXEDFILEINFO in MSDN. + DWORD SubtypeFlag() const; // Returns: See dwFileSubtype variable for VS_FIXEDFILEINFO in MSDN. + + BOOL IsRequiredVersion(int iReqMajor, int iReqMinor = 0, int iReqMicro = 0) const; // Returns TRUE if the file has the required version or is newer. + + // language dependant data + + const char* Comments( DWORD dwLanguage = -1L); // Returns additional information that should be displayed for diagnostic purposes. + const char* CompanyName( DWORD dwLanguage = -1L); // Returns the company that produced the file. For example, "Microsoft Corporation" or "ADRA Datasystem AB (publ)." + const char* FileDescription( DWORD dwLanguage = -1L); // Returns the description in such a way that it can be presented to users. This string may be presented in a list box when the user is choosing files to install. For example, "ViewLine" or "Microsoft Word for Windows". + const char* FileVersion( DWORD dwLanguage = -1L); // Returns the version of this file. For example, "3.00.001R" or "5.00.RC2". + const char* InternalName( DWORD dwLanguage = -1L); // Returns the files internal name. For example. "UDIMEAS" or "WINWORD" + const char* LegalCopyright( DWORD dwLanguage = -1L); // Returns all copyright notices, trademarks, and registered trademarks that apply to the file. For example "Copyright © ADRA Datasystem AB (publ) 1997- 1998" + const char* LegalTrademarks( DWORD dwLanguage = -1L); // Returns all trademarks and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, trademark numbers, and so on. In English, this string should be in the format "UDIBAS is a trademark of ADRA Datasystem AB.". + const char* OriginalFileName(DWORD dwLanguage = -1L); // Returns identifies the original name of the file, not including a path. This enables an application to determine whether a file has been renamed by a user. + const char* PrivateBuild( DWORD dwLanguage = -1L); // Returns whom, where, and why this private version of the file was built. + const char* ProductName( DWORD dwLanguage = -1L); // Returns the name of the product with which this file is distributed. For example, this string could be "Microsoft Windows". + const char* ProductVersion( DWORD dwLanguage = -1L); // Returns the version of the product with which this file is distributed. For example, "3.00.001R" or "5.00.RC2". + const char* SpecialBuild( DWORD dwLanguage = -1L); // Returns a description how this version of the file differs from the normal version. + + const char* GetTextData(LPCSTR pszParameter,DWORD dwLanguage = -1L); // Do a VerQueryValue for a paramater. For example "ProductVersion". + +protected: + + void Init(); + DWORD SetError(); + + DWORD m_dwHandle; + char* m_pszData; + DWORD m_dwDefaultLang; + VS_FIXEDFILEINFO m_ffi; + DWORD m_dwLastError; +}; + +// AgVersionInfo inlines // + +inline void AgVersionInfo::Init() +{ m_dwLastError = (DWORD)-1; m_dwDefaultLang = (DWORD)-1; m_dwHandle = (DWORD)0; memset(&m_ffi,'\0',sizeof(m_ffi)); m_pszData = NULL; } + +inline AgVersionInfo::AgVersionInfo() +{ Init(); } + +inline AgVersionInfo::~AgVersionInfo() +{ + if (m_pszData) + free(m_pszData); +} + +inline BOOL AgVersionInfo::HasErrors() const +{ return (0 != GetLastError()); } + +inline DWORD AgVersionInfo::GetLastError() const +{ return m_dwLastError; } + +inline BOOL AgVersionInfo::IsDebugBuild() const +{ //AFC_ASSERT(!HasErrors()); +return ( 0 != (VS_FF_DEBUG & FileFlag())); } + +inline BOOL AgVersionInfo::IsInfoInferred() const +{ //AFC_ASSERT(!HasErrors()); +return ( 0 != (VS_FF_INFOINFERRED & FileFlag())); } + +inline BOOL AgVersionInfo::IsPatched() const +{ //AFC_ASSERT(!HasErrors()); +return ( 0 != (VS_FF_PATCHED & FileFlag())); } + +inline BOOL AgVersionInfo::IsPreRelease() const +{ //AFC_ASSERT(!HasErrors()); +return ( 0 != (VS_FF_PRERELEASE & FileFlag())); } + +inline BOOL AgVersionInfo::IsPrivateBuild() const +{ //AFC_ASSERT(!HasErrors()); +return ( 0 != (VS_FF_PRIVATEBUILD & FileFlag())); } + +inline BOOL AgVersionInfo::IsSpecialBuild() const +{ //AFC_ASSERT(!HasErrors()); +return ( 0 != (VS_FF_SPECIALBUILD & FileFlag())); } + +inline DWORD AgVersionInfo::FileFlag() const +{ //AFC_ASSERT(!HasErrors()); +return (m_ffi.dwFileFlagsMask & m_ffi.dwFileFlags); } + +inline DWORD AgVersionInfo::OSFlag() const +{ //AFC_ASSERT(!HasErrors()); +return m_ffi.dwFileOS; } + +inline DWORD AgVersionInfo::TypeFlag() const +{ //AFC_ASSERT(!HasErrors()); +return m_ffi.dwFileType; } + +inline DWORD AgVersionInfo::SubtypeFlag() const +{ //AFC_ASSERT(!HasErrors()); +return m_ffi.dwFileSubtype; } + +inline const char* AgVersionInfo::Comments(DWORD dwLanguage) +{ return GetTextData("Comments",dwLanguage); } + +inline const char* AgVersionInfo::CompanyName(DWORD dwLanguage) +{ return GetTextData("CompanyName",dwLanguage); } + +inline const char* AgVersionInfo::FileDescription(DWORD dwLanguage) +{ return GetTextData("FileDescription",dwLanguage); } + +inline const char* AgVersionInfo::FileVersion(DWORD dwLanguage) +{ return GetTextData("FileVersion",dwLanguage); } + +inline const char* AgVersionInfo::InternalName(DWORD dwLanguage) +{ return GetTextData("InternalName",dwLanguage); } + +inline const char* AgVersionInfo::LegalCopyright(DWORD dwLanguage) +{ return GetTextData("LegalCopyright",dwLanguage); } + +inline const char* AgVersionInfo::LegalTrademarks(DWORD dwLanguage) +{ return GetTextData("LegalTrademarks",dwLanguage); } + +inline const char* AgVersionInfo::OriginalFileName(DWORD dwLanguage) +{ return GetTextData("OriginalFileName",dwLanguage); } + +inline const char* AgVersionInfo::PrivateBuild(DWORD dwLanguage) +{ return GetTextData("PrivateBuild",dwLanguage); } + +inline const char* AgVersionInfo::ProductName(DWORD dwLanguage) +{ return GetTextData("ProductName",dwLanguage); } + +inline const char* AgVersionInfo::ProductVersion(DWORD dwLanguage) +{ return GetTextData("ProductVersion",dwLanguage); } + +inline const char* AgVersionInfo::SpecialBuild(DWORD dwLanguage) +{ return GetTextData("SpecialBuild",dwLanguage); } + +#endif //AG_USE_CHEATPROTECTION + + +#endif //__AG_VERSION_INFO_H__ \ No newline at end of file diff --git a/cl_dll/aghl/agvguiirc.cpp b/cl_dll/aghl/agvguiirc.cpp new file mode 100644 index 00000000..d322fbc9 --- /dev/null +++ b/cl_dll/aghl/agvguiirc.cpp @@ -0,0 +1,241 @@ +//++ BulliT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" +#include +#include + +#include "hud.h" +#include "cl_util.h" +#include +#include "vgui_TeamFortressViewport.h" +#include "AGVGuiIRC.h" + +extern /*irc::*/CIrcSession g_ircSession; + +using namespace vgui; + +namespace +{ + class TextHandler : public ActionSignal + { + private: + + AGVGuiIRC* _AGVGuiIRC; + + public: + + TextHandler(AGVGuiIRC* AGVGuiIRC) + { + _AGVGuiIRC=AGVGuiIRC; + } + + public: + + virtual void actionPerformed(Panel* panel) + { + _AGVGuiIRC->doExecCommand(); + } + }; + + class ConnectHandler : public ActionSignal + { + private: + + AGVGuiIRC* _AGVGuiIRC; + + public: + + ConnectHandler(AGVGuiIRC* AGVGuiIRC) + { + _AGVGuiIRC=AGVGuiIRC; + } + + public: + + virtual void actionPerformed(Panel* panel) + { + _AGVGuiIRC->doConnectCommand(); + } + }; + + class CloseHandler : public ActionSignal + { + public: + CloseHandler() + { + } + + public: + virtual void actionPerformed(Panel* panel) + { + gViewPort->ToggleIRC(); + } + }; + + + class TextInput : public vgui::TextEntry + { + public: + TextInput(const char* text,int x,int y,int wide,int tall) : TextEntry(text,x,y,wide,tall) + { + }; + + virtual void keyPressed(KeyCode code,Panel* panel) + { + if (gViewPort->m_pIRC->isVisible()) + TextEntry::keyPressed(code,panel); + }; + virtual void keyTyped(KeyCode code,Panel* panel) + { + if (gViewPort->m_pIRC->isVisible()) + TextEntry::keyTyped(code,panel); + }; + virtual void keyReleased(KeyCode code,Panel* panel) + { + if (gViewPort->m_pIRC->isVisible()) + TextEntry::keyReleased(code,panel); + }; + }; + +} + +#define IRC_TITLE_X XRES(16) +#define IRC_TITLE_Y YRES(16) +#define TEXT_SIZE_Y YRES(16) + +AGVGuiIRC::AGVGuiIRC(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0)) ); + + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hIRCText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the title + Label *pLabel = new Label( "", IRC_TITLE_X, IRC_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pLabel->setFont( Scheme::sf_primary1 ); + + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pLabel->setFgColor( Scheme::sc_primary1 ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText("AG IRC Client"); + + int iXSize,iYSize; + getSize( iXSize,iYSize ); + + // Create the text panel + m_pTextPanel = new TextPanel( "", XRES(16), IRC_TITLE_Y*2 + YRES(16), iXSize - XRES(32), iYSize - (YRES(48) + BUTTON_SIZE_Y*2 + TEXT_SIZE_Y*2)); + m_pTextPanel->setParent( this); + + // get the font and colors from the scheme + m_pTextPanel->setFont( pSchemes->getFont(hIRCText) ); + pSchemes->getFgColor( hIRCText, r, g, b, a ); + m_pTextPanel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hIRCText, r, g, b, a ); + m_pTextPanel->setBgColor( r, g, b, a ); + + int iTemp = iYSize - YRES(24) - TEXT_SIZE_Y - BUTTON_SIZE_Y; //Hack to get it to work with Visual 7.0 beta 2 + m_pTextEntry = new TextInput("",XRES(16), iTemp, iXSize - 2*XRES(16), TEXT_SIZE_Y); + m_pTextEntry->setParent(this); + m_pTextEntry->addActionSignal(new TextHandler(this)); + + m_pConnect = new CommandButton("",XRES(16), iYSize - YRES(16) - BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + m_pConnect->addActionSignal(new ConnectHandler(this)); + m_pConnect->setParent(this); + + CommandButton* pClose = new CommandButton("Close",iXSize - XRES(16) - CMENU_SIZE_X, iYSize - YRES(16) - BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pClose->addActionSignal(new CloseHandler()); + pClose->setParent(this); +} + +void AGVGuiIRC::doExecCommand() +{ + char buf[2048]; + strcpy(buf,"irc "); + m_pTextEntry->getText(0,buf+4,2040); + m_pTextEntry->setText(null,0); + + gEngfuncs.pfnClientCmd(buf); +} + +void AGVGuiIRC::doConnectCommand() +{ + m_sText = ""; + m_pTextPanel->setText(m_sText.c_str()); + gEngfuncs.pfnClientCmd(g_ircSession ? "ircdisconnect" : "ircconnect"); +} + +void AGVGuiIRC::paintBackground() +{ + // Transparent black background + drawSetColor( 0,0,0, 100 ); + drawFilledRect(0,0,_size[0],_size[1]); + if (g_ircSession) + m_pConnect->setText("Disconnect"); + else + m_pConnect->setText("Connect"); +} + +int AGVGuiIRC::KeyInput(int down, int keynum, const char *pszCurrentBinding) +{ + if (!down) + return 1; + + if (!isVisible()) + return 1; + + if (K_ESCAPE == keynum || pszCurrentBinding && 0 == _stricmp("toggleirc",pszCurrentBinding)) + { + gViewPort->ToggleIRC(); + return 0; + } + + if (m_pTextEntry->hasFocus()) + return 0; + + return 1; +} + +void AGVGuiIRC::PrintMessage(const char* pszText) +{ + int iWide,iTall; + m_pTextPanel->getSize(iWide,iTall); + int iTextWide,iTextTall; + m_pTextPanel->getTextImage()->getTextSizeWrapped(iTextWide,iTextTall); + if ((iTextTall + 20) > iTall) + { + int iFind = m_sText.find("\n"); + if (NPOS != iFind) + { + m_sText = m_sText.substr(iFind+1); + } + } + + m_sText += pszText; + m_sText += "\n"; + m_pTextPanel->setText(m_sText.c_str()); +} + +//-- Martin Webrant diff --git a/cl_dll/aghl/agvguiirc.h b/cl_dll/aghl/agvguiirc.h new file mode 100644 index 00000000..dcc7e163 --- /dev/null +++ b/cl_dll/aghl/agvguiirc.h @@ -0,0 +1,38 @@ +//++ BulliT + +#if !defined(_AG_VGUI_IRC_) +#define _AG_VGUI_IRC_ + +#include +#include + +namespace vgui +{ +class TextEntry; +class TextPanel; +class EditPanel; +} + +class AGVGuiIRC : public vgui::Panel +{ +private: + vgui::TextEntry* m_pTextEntry; + vgui::TextPanel* m_pTextPanel; + CommandButton* m_pConnect; + + AgString m_sText; + +public: + AGVGuiIRC(int x,int y,int wide,int tall); +public: + virtual void doExecCommand(); + virtual void doConnectCommand(); + virtual void paintBackground(); + + virtual int KeyInput(int down, int keynum, const char *pszCurrentBinding); + void PrintMessage(const char* pszText); +}; + +#endif //_AG_VGUI_IRC_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agvguiwinamp.cpp b/cl_dll/aghl/agvguiwinamp.cpp new file mode 100644 index 00000000..eb558c44 --- /dev/null +++ b/cl_dll/aghl/agvguiwinamp.cpp @@ -0,0 +1,270 @@ +//++ BulliT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" +#include +#include + +#include "hud.h" +#include "cl_util.h" +#include +#include "vgui_TeamFortressViewport.h" +#include "AGVGuiWinamp.h" + +static HWND hwnd = NULL; + +struct WINAMP +{ + char szCommand[16]; + UINT uiMessage; + char szCommandButton[16]; +}; + +static WINAMP s_Commands[]= +{ + "play" ,40045, "Play", + "pause" ,40046, "Pause", + "stop" ,40047, "Stop", + "next" ,40048, "Next Track", + "prev" ,40044, "Previous Track", + "playcd" ,40323, "Play CD", + "increase" ,40058, "Increase Vol.", + "decrease" ,40059, "Decrease Vol.", + "repeat" ,40022, "Toggle Repeat", + "shuffle" ,40023, "Toggle Shuffle", + "forward" ,40148, "Fast Forward", + "rewind" ,40144, "Fast Rewind", +}; + +using namespace vgui; + +namespace +{ + class WinampCommandHandler : public ActionSignal + { + private: + char m_szCommand[256]; + public: + WinampCommandHandler(const char* szCommand) + { + strcpy(m_szCommand,szCommand); + } + public: + virtual void actionPerformed(Panel* panel) + { + gEngfuncs.pfnClientCmd(m_szCommand); + } + }; + + class CloseHandler : public ActionSignal + { + public: + CloseHandler() + { + } + public: + virtual void actionPerformed(Panel* panel) + { + gViewPort->ToggleWinamp(); + } + }; +} + +#define WINAMP_TITLE_X XRES(16) +#define WINAMP_TITLE_Y YRES(16) + +#define WINAMP_TOPLEFT_BUTTON_X XRES(80) +#define WINAMP_TOPLEFT_BUTTON_Y YRES(60) +#define WINAMP_BUTTON_SIZE_X XRES(124) +#define WINAMP_BUTTON_SIZE_Y YRES(24) +#define WINAMP_BUTTON_SPACER_Y YRES(8) +#define WINAMP_BUTTON_SPACER_X XRES(8) + +AGVGuiWinamp::AGVGuiWinamp(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0)) ); + + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); +// SchemeHandle_t hIRCText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the title + m_pLabel = new Label( "AG Winamp", WINAMP_TITLE_X, WINAMP_TITLE_Y ); + m_pLabel->setParent( this ); + m_pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + m_pLabel->setFont( Scheme::sf_primary1 ); + + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + m_pLabel->setFgColor( r, g, b, a ); + m_pLabel->setFgColor( Scheme::sc_primary1 ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + m_pLabel->setBgColor( r, g, b, a ); + m_pLabel->setContentAlignment( vgui::Label::a_west ); + m_pLabel->setText("AG Winamp"); + + int iXSize,iYSize; + getSize( iXSize,iYSize ); + + for (int i = 0; i < sizeof(s_Commands)/sizeof(s_Commands[0]); i++) + { + char szCommand[256]; + sprintf(szCommand,"winamp %s",s_Commands[i].szCommand); + + int iXPos = WINAMP_TOPLEFT_BUTTON_X; + int iYPos = WINAMP_TOPLEFT_BUTTON_Y + ( (WINAMP_BUTTON_SIZE_Y + WINAMP_BUTTON_SPACER_Y) * i ); + if (i > 5) + { + iXPos += WINAMP_BUTTON_SIZE_X + WINAMP_BUTTON_SPACER_X; + iYPos = WINAMP_TOPLEFT_BUTTON_Y + ( (WINAMP_BUTTON_SIZE_Y + WINAMP_BUTTON_SPACER_Y) * (i-6) ); + } + + CommandButton* pPlay = new CommandButton(s_Commands[i].szCommandButton,iXPos, iYPos, WINAMP_BUTTON_SIZE_X, WINAMP_BUTTON_SIZE_Y); + pPlay->addActionSignal(new WinampCommandHandler(szCommand)); + pPlay->setParent(this); + } + + CommandButton* pClose = new CommandButton("Close",iXSize - XRES(16) - CMENU_SIZE_X, iYSize - YRES(16) - BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pClose->addActionSignal(new CloseHandler()); + pClose->setParent(this); +} + +void GetSongTitle(LPSTR pszSong, int iSize) +{ + GetWindowText(hwnd,pszSong,iSize); + char* p = pszSong + strlen(pszSong)-8; + while (p >= pszSong) + { + if (!strnicmp(p,"- Winamp",8)) + break; + p--; + } + if (p >= pszSong) + p--; + while (p >= pszSong && *p == ' ') + p--; + *++p = 0; +} + +static DWORD dwTime = 0; +void AGVGuiWinamp::paintBackground() +{ + // Transparent black background + drawSetColor( 0,0,0, 100 ); + drawFilledRect(0,0,_size[0],_size[1]); + + if (NULL == hwnd) + return; + + if (dwTime > GetTickCount()) + return; + + char szSong[2048]; + GetSongTitle(szSong,sizeof(szSong)); + if (0 == strlen(szSong)) + { + dwTime = GetTickCount() + 10000; + } + else + { + m_pLabel->setText(szSong); + dwTime = GetTickCount() + 1000; + } +} + +void AGVGuiWinamp::UserCmd_Winamp() +{ + if (NULL == hwnd) + hwnd = FindWindow("Winamp v1.x",NULL); + + if (!::IsWindow(hwnd)) + { + ConsolePrint("Could not find Winamp window.\n"); + hwnd = NULL; + return; + } + + if (gEngfuncs.Cmd_Argc() == 1) + { + char szSong[2048]; + GetSongTitle(szSong,sizeof(szSong)); + strcat(szSong,"\n"); + ConsolePrint(szSong); + return; + } + + if (gEngfuncs.Cmd_Argc() < 2) + return; + + if (3 == gEngfuncs.Cmd_Argc() && 0 == strcmp("volume",gEngfuncs.Cmd_Argv(1))) + { + PostMessage(hwnd,WM_USER,atoi(gEngfuncs.Cmd_Argv(2)),122); + } + else + { + for (int i = 0; i < sizeof(s_Commands)/sizeof(s_Commands[0]); i++) + { + if (0 == strcmp(s_Commands[i].szCommand,gEngfuncs.Cmd_Argv(1))) + { + PostMessage(hwnd,WM_COMMAND,s_Commands[i].uiMessage,0); + break; + } + } + } +} + + +int AGVGuiWinamp::KeyInput(int down, int keynum, const char *pszCurrentBinding) +{ + if (!down) + return 1; + + if (!isVisible()) + return 1; + + if (K_ESCAPE == keynum || pszCurrentBinding && 0 == _stricmp("togglewinamp",pszCurrentBinding)) + { + gViewPort->ToggleWinamp(); + return 0; + } + + if (K_MWHEELUP == keynum || K_MWHEELDOWN == keynum) + { + if (NULL == hwnd) + hwnd = FindWindow("Winamp v1.x",NULL); + + if (!::IsWindow(hwnd)) + { + ConsolePrint("Could not find Winamp window.\n"); + hwnd = NULL; + return 1; + } + + if (K_MWHEELUP == keynum) + PostMessage(hwnd,WM_COMMAND,40058,0); + else + PostMessage(hwnd,WM_COMMAND,40059,0); + + return 0; + } + + return 1; +} + + +//-- Martin Webrant diff --git a/cl_dll/aghl/agvguiwinamp.h b/cl_dll/aghl/agvguiwinamp.h new file mode 100644 index 00000000..dcea32c2 --- /dev/null +++ b/cl_dll/aghl/agvguiwinamp.h @@ -0,0 +1,23 @@ +//++ BulliT + +#if !defined(_AG_VGUI_WINAMP_) +#define _AG_VGUI_WINAMP_ + +#include +#include + +class AGVGuiWinamp : public vgui::Panel +{ +private: + Label* m_pLabel; +public: + AGVGuiWinamp(int x,int y,int wide,int tall); +public: + void UserCmd_Winamp(); + virtual void paintBackground(); + virtual int KeyInput(int down, int keynum, const char *pszCurrentBinding); +}; + +#endif //_AG_VGUI_WINAMP_ + +//-- Martin Webrant diff --git a/cl_dll/aghl/agwallhack.cpp b/cl_dll/aghl/agwallhack.cpp new file mode 100644 index 00000000..6da2b257 --- /dev/null +++ b/cl_dll/aghl/agwallhack.cpp @@ -0,0 +1,732 @@ +//++ BulliT +#include "hud.h" +#include "cl_util.h" + +#ifdef AG_USE_CHEATPROTECTION + +#include "AgWallhack.h" +#include "AgVersionInfo.h" +#include "com_weapons.h" +#include "agbase64.h" +#include "agmapi.h" +#include "agicq.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + + + +bool CheckHooks(const char* pszModule, const char* pszMethod, BYTE* pBytesToCheck, DWORD dwSize) +{ + bool bOK = false; + HANDLE hProcess = ::GetCurrentProcess(); + HMODULE hModule = ::GetModuleHandle(pszModule); + if (!hModule) + return true; //The dll aint loaded + LPVOID pAddress = ::GetProcAddress(hModule, pszMethod); + + // change the page-protection for the intercepted function + DWORD dwOldProtect; + if (!::VirtualProtectEx(hProcess, pAddress, dwSize, PAGE_EXECUTE_READ, &dwOldProtect)) + return false; + + //Read the bytes to see if someone hooked that function + BYTE* pBytesInMem = (BYTE*)malloc(dwSize); + DWORD dwRead = 0; + if (::ReadProcessMemory(hProcess, pAddress, pBytesInMem, dwSize, &dwRead)) + { + bOK = 0 != memcmp(pBytesInMem, pBytesToCheck, dwRead); + + /* + char szAddress[_MAX_PATH]; + sprintf(szAddress, "%s::%s - at %lx - %s", pszModule, pszMethod, pAddress, bOK ? "OK" : "HACK"); + AgLog(szAddress); + + HANDLE hFile = CreateFile("c:\\temp.bin", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL); + DWORD dwWritten; + WriteFile(hFile, pBytesToCheck, dwRead, &dwWritten, NULL); + CloseHandle(hFile); + */ + } + + // + // restore page protection + // + VirtualProtectEx(hProcess, pAddress, dwSize, dwOldProtect, &dwOldProtect); + + free(pBytesInMem); + + return bOK; +} + + + +AgWallhack g_Wallhack; +static char szDisconnect[] = "disconnect\n"; +static char szMicrosoft[] = "Microsoft Corporation"; +static char szCDFPS[] = "cd_fps"; + +static char* s_szGoodDlls[] = +{ + /* + "\\ag\\cl_dlls\\client.dll", + "\\ag\\dlls\\ag.dll", + "\\ag\\dlls\\hl.dll", + "\\aghl\\cl_dlls\\client.dll", + "\\aghl\\dlls\\ag.dll", + "\\aghl\\dlls\\hl.dll", + */ + "\\vgui.dll", + "\\woncrypt.dll", + "\\wonauth.dll", + "\\hl_res.dll", + "\\hw.dll", + "\\sw.dll", + "\\mss32.dll", + "\\mssv12.dll", + "\\mssv12.asi", + "\\mp3dec.asi", + "\\mssv29.asi", + "\\steamvalidateuseridtickets.dll", + "\\voice_miles.dll", + "\\hl.exe", + "\\cstrike.exe", +}; + + +static char* s_szBadDlls[] = +{ + "glhack.dll", //Famous glhack. + "default.dll", //Cracked version of famous glhack. This one is encoded... smart fellow :P + "hl_rem.dll", //Cracked version of famous glhack. I will stop any version by opening the dll anyway. + "oldogl32.dll", //Famous glhack. + "oglhack.dll", + "ogl.dll", + "sw!zz3r.dll", + "hookhl.dll", + "ogc.dll", +}; + +static char* s_szBadStrings[] = +{ + "Z2xoYWNr", //glhack + "b3BlbmdsLmluaQAA", //opengl.ini + "VFdDaGVhdAAA", //TWCheat + "Qi50ZXJhcGh5", //B.teraphy + "RmxhdXR6", //Flautz + "c3chenozcgAA", //sw!zz3r + "QU5BS2lO", //ANAKiN + "VVBYIQAA", //UPX! + "Yzpcb3BlbmdsMzIuZGxs", //c:\opengl32.dll + "aGxoLmRsbAAA", //hlh.dll + "R1JpTS1GX0gA", //GRiM-F_H + "Q2hyb21heFMA", //ChromaxS + "b2djLmRsbAAA", //ogc.dll + "ZVohJDd2", //eZ!$7v Swizz hack + "Y29kZXJzLmRsbAAA", //coders.dll wh_beta4, wh_beta5 + "b2djLmNmZwAA", //ogc.cfg + "eHF6MgAA", //xqz2 - xqz2_b71 + "eHFiNgAA", //xqb6 - xqz2_b80 + "cEBncmFt", //p@gram - XQZ2Beta85 + "W09HQ10A", //[OGC] - from ogc 7 + "Sm9vbHoA", //Joolz - from ogc 8 - + "dGhyb3VnaCB3YWxs", //through wall - from ogc 8 - + "UlNEU/s19Llq", //RSDSû5ô¹j from 187 Wallhack + "d2FsbGhhY2sA", //wallhack from SyFWallHack.dll + "W1VHQ10A", //[UGC] from [FuRy]-immortal + "R0xIYWNr", //GLHack + "XDE4N0hBQ0sA", //\187HACK - 187 version 1.5, 2.0, xqz + "THRmeGhvb2sA", //Ltfxhook - version 4 + "c2VjdXJlLmluaQAA", //secure.ini - nc-secure + "bWFkQ29kZUhvb2sA", //madCodeHookLib - www.madshi.net hooking library that some seem to use. + "amFpbmEA", //jaina - comes from exprtl0.dll + "bmV0LWNvZGVycwAA", //net-coders - from net coderse hack +// "YWltaGFjawAA", //aimhack - 187 version xqz + "V2FsbGhhY2sA", //Wallhack - from many hacks. + "aG9va2VyLmRsbAAA", //hooker.dll + "VW5ob29rZXIA", //Unhooker +//in cheats.dat "V2lyZWZyYW1l", //Wireframe - from Net coders hack. + /* + "T0dDAAAA", //OGC + "b2djAAAA", //ogc + + */ + /* +http://www.zone.ee/kunnchat/ +http://www.unknowncheats.com/ +http://www.cheat-network.net/chnetphp/ + */ +}; + +AgWallhack::AgWallhack() +{ +#ifndef _DEBUG +#ifndef AG_TESTCHEAT + if (IsDebuggerPresent()) + exit(-1); +#endif +#endif + + m_dwHLAddressToValidate = 0L; + int i = 0; + for (i = 0; i < sizeof(s_szBadStrings)/sizeof(s_szBadStrings[0]); i++) + AddBadString(s_szBadStrings[i]); + + for (i = 0; i < sizeof(s_szBadDlls)/sizeof(s_szBadDlls[0]); i++) + AddBadDll(s_szBadDlls[i]); + + char szHalfLife[MAX_PATH]; + GetModuleFileName(GetModuleHandle("client.dll"),szHalfLife,sizeof(szHalfLife)); + szHalfLife[strrchr(szHalfLife,'\\') - szHalfLife] = '\0'; + szHalfLife[strrchr(szHalfLife,'\\') - szHalfLife] = '\0'; + szHalfLife[strrchr(szHalfLife,'\\') - szHalfLife] = '\0'; + strlwr(szHalfLife); + char szDll[MAX_PATH]; + for (i = 0; i < sizeof(s_szGoodDlls)/sizeof(s_szGoodDlls[0]); i++) + { + sprintf(szDll,"%s%s",szHalfLife,s_szGoodDlls[i]); + m_setGoodDlls.insert(szDll); + } + + /* + unsigned short usSize = 0; + unsigned char szSearch[256]; + AgBase64Decode("hitewalls",9,szSearch,usSize); + OutputDebugString((char*)szSearch); + OutputDebugString("\n"); + */ + /* + + AgBase64Encode((unsigned char*)"Wallhack",8,szDll); + OutputDebugString(szDll); + OutputDebugString("\n"); + */ +/* + AgBase64Encode((unsigned char*)"ownlinecheating",7,szDll); + OutputDebugString(szDll); + OutputDebugString("\n"); + */ + + + m_bDoneCheck = false; + m_iFiles = 0; + m_dwBytes = 0; +} + +AgWallhack::~AgWallhack() +{ + m_setBadStrings.clear(); + m_setBadDlls.clear(); + m_setGoodDlls.clear(); + m_setGoodSystemDlls.clear(); +} + +void AgWallhack::AddBadDll(const char* pszDll) +{ + if (pszDll && 0 != strlen(pszDll)) + m_setBadDlls.insert(pszDll); +} + +void AgWallhack::AddBadString(const char* pszString) +{ + if (pszString && 0 != strlen(pszString)) + m_setBadStrings.insert(pszString); +} + +void AgWallhack::AddBadStrings(const char* pszStrings) +{ + char* pszStringsTemp = strdup(pszStrings); + + char* pszCheatString = strtok( pszStringsTemp, "\n"); + while (pszCheatString != NULL) + { + AgString strCheatString = pszCheatString; + AgTrim(strCheatString); + if (strCheatString.length()) + AddBadString(strCheatString.c_str()); + pszCheatString = strtok( NULL, "\n"); + } + + free(pszStringsTemp); +} + + +bool AgWallhack::InitToolHelp32() +{ + if (m_hKernel32 && m_lpfCreateToolhelp32Snapshot && m_lpfModule32First && m_lpfModule32Next) + return true; + + m_hKernel32 = ::LoadLibrary("kernel32.dll"); + if (NULL == m_hKernel32) + return false; + + m_lpfCreateToolhelp32Snapshot = (CREATETOOLHELP32SNAPSHOT) ::GetProcAddress(m_hKernel32,"CreateToolhelp32Snapshot"); + m_lpfModule32First = (MODULE32FIRST) ::GetProcAddress(m_hKernel32,"Module32First"); + m_lpfModule32Next = (MODULE32NEXT) ::GetProcAddress(m_hKernel32,"Module32Next"); + m_lpfProcess32First = (PROCESS32FIRST) ::GetProcAddress(m_hKernel32,"Process32First"); + m_lpfProcess32Next = (PROCESS32NEXT) ::GetProcAddress(m_hKernel32,"Process32Next"); + + if (NULL == m_lpfCreateToolhelp32Snapshot || + NULL == m_lpfModule32First || + NULL == m_lpfModule32Next || + NULL == m_lpfProcess32First || + NULL == m_lpfProcess32Next) + { + ::FreeLibrary(m_hKernel32); + m_hKernel32 = NULL; + return false; + } + return true; +} + +bool AgWallhack::Check() +{ +#ifdef _DEBUG + //return true; + //m_bDoneCheck = true; + //HMODULE x1 = LoadLibrary("E:/Dev/cheats/nC 2.1/nC-Hack.dll"); +#endif + if (m_bDoneCheck) + return true; + + + if (!InitToolHelp32()) + { + char szMessage[] = "Cheat check: This version of Windows is not supported\n"; + ServerCmd("say this version of Windows is not supported."); + AgLog(szMessage); + ConsolePrint(szMessage); + ClientCmd(szDisconnect); + return false; + } + + int iCheck = InternalCheck(); +#ifdef _DEBUG + char szChecked[128]; + sprintf(szChecked,"Checked for %d cheats in %d files with total data of %ld bytes\n",(int)(m_setBadStrings.size() + m_setBadDlls.size()),m_iFiles,m_dwBytes); + ConsolePrint(szChecked); +#endif + + if (0 > iCheck) + { + char szMessage[512]; + sprintf(szMessage,"say Autodisconnected, error in installation.\n"); + ServerCmd(szMessage); + sprintf(szMessage,"Error in installation %s. (Error = %d)\n",m_sDll.c_str(),iCheck); + AgLog(szMessage); + ConsolePrint(szMessage); + ClientCmd(szDisconnect); + return false; + } + + if (0 != iCheck) + { + char szMessage[512]; + sprintf(szMessage,"say Disconnected for using invalid module %s.\n",m_sDll.c_str()); + ServerCmd(szMessage); + sprintf(szMessage,"Cheat check: %s is not allowed in AG. (Code = %d)\n",m_sDll.c_str(),iCheck); + AgLog(szMessage); + ConsolePrint(szMessage); + //AgSendICQ(szMessage); + //AgSendMail(szMessage); +#ifndef _DEBUG + SendMessageToIRC(szMessage); + ClientCmd(szDisconnect); + return false; +#endif + } + +// m_bDoneCheck = true; + return true; +} + +void DumpToFile(MODULEENTRY32* pME) +{ + char szFile[MAX_PATH]; + sprintf(szFile,"%s/filedump.txt",AgGetDirectory()); + FILE* pFile = fopen(szFile,"a+"); + if (!pFile) + { + return; + } + + fwrite(pME->modBaseAddr,sizeof(BYTE),pME->modBaseSize,pFile); + fflush(pFile); + fclose(pFile); +} + +int AgWallhack::InternalCheck() +{ +#ifndef _DEBUG +#ifndef AG_TESTCHEAT + if (IsDebuggerPresent()) + { + m_sDll = "debugger"; + return -1; + } +#endif +#endif + + + char szSystemDir[MAX_PATH]; + GetSystemDirectory(szSystemDir,sizeof(szSystemDir)); + strlwr(szSystemDir); + + m_sDll = ""; +#ifdef _DEBUG + DWORD dwTime = GetTickCount(); +#endif + unsigned char szSearch[256]; + szSearch[0] = '\0'; + + HANDLE hSnapShot = m_lpfCreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0); + if (INVALID_HANDLE_VALUE == hSnapShot) + { + m_sDll = "toolhelp was not found"; + return -2; + } + + MODULEENTRY32 me; + me.dwSize = sizeof(MODULEENTRY32); + HMODULE hCurrent = ::GetModuleHandle("client.dll"); + + if (!GetModuleHandle("hl.exe") && !GetModuleHandle("cstrike.exe")) + { + m_sDll = "hl.exe or cstrike.exe was not found"; + return -3; + } + + BYTE byHokoHack[1] = {0xE8}; + BYTE byRegularJumpHack[1] = {0xE9}; + if ( !CheckHooks("opengl32.dll", "glBegin", byHokoHack, sizeof(byHokoHack)) + || !CheckHooks("opengl32.dll", "glBegin", byRegularJumpHack, sizeof(byRegularJumpHack)) + ) + { + m_sDll = "opengl32.dll (patched)"; + return 11; + } + + m_iFiles = 0; + m_dwBytes = 0; + + bool bCorrectAddress = false; + if (m_lpfModule32First(hSnapShot,&me)) + { + do + { + m_iFiles++; + m_dwBytes += me.modBaseSize; + + if (hCurrent != me.hModule) + { +#ifdef _DEBUG + char szTime[MAX_PATH]; + if ("" == m_sDll) + { + sprintf(szTime,"%s %d ms\n",m_sDll.c_str(),int((GetTickCount() - dwTime))); + AgLog(szTime); + dwTime = GetTickCount(); + } +#endif //_DEBUG + + char szFileName[MAX_PATH]; + strcpy(szFileName,me.szExePath); + strlwr(szFileName); + m_sDll = szFileName; + + DWORD dwAddressInModule = (DWORD)me.modBaseAddr; + if (m_dwHLAddressToValidate >= dwAddressInModule + && m_dwHLAddressToValidate <= (dwAddressInModule + me.modBaseSize)) + { + bCorrectAddress = (0 == stricmp(&szFileName[strlen(szFileName)-6],"hl.exe")) || (0 == stricmp(&szFileName[strlen(szFileName)-11],"cstrike.exe")); + } + + bool bOpenGL = 0; + if (strlen(szFileName) > 11) + bOpenGL = 0 == strcmp(&szFileName[strlen(szFileName)-12],"opengl32.dll"); + + //Extract version resource. + AgVersionInfo vi; + vi.LoadVersionInfo(szFileName); + + //Check if microsoft dll. + if (!vi.HasErrors()) + { + if (0 == strcmp(szMicrosoft, vi.CompanyName())) + { + if (!bOpenGL && me.modBaseSize > 150000L) //Most cheat dlls are usually less than 150000kb. + continue; + } + } + + if (0 == strcmp(&szFileName[strlen(szFileName)-11],"shimeng.dll")) + continue; + + //Skip over some HL dll's + bool bGood = false; + AgStringSet::iterator itrGoodDlls; + for (itrGoodDlls = m_setGoodDlls.begin() ;itrGoodDlls != m_setGoodDlls.end() && !bGood; ++itrGoodDlls) + { + if (0 == strcmp(m_sDll.c_str(),(*itrGoodDlls).c_str())) + bGood = true; + } + + if (bGood) + continue; + +#ifndef AG_TESTCHEAT + //Check bad dll's - practicly worthless :P - the rutine to open and scan the dll inside below is much better. + AgStringSet::iterator itrWallhackDlls; + for (itrWallhackDlls = m_setBadDlls.begin() ;itrWallhackDlls != m_setBadDlls.end(); ++itrWallhackDlls) + { + if (0 == strcmp(m_sDll.c_str(),(*itrWallhackDlls).c_str())) + { + AgLog(("Wallhack found in " + m_sDll + "\n").c_str()); + return 1; //He used an obvious cheat. + } + } +#endif + +#ifdef _DEBUG + bool bDump = false; + if (bDump) + DumpToFile(&me); +#endif //_DEBUG + + if (bOpenGL) + { + //Check if dll is in windows system directory. Hacks sometimes put the passthru in c:/ + if (NULL == strstr(m_sDll.c_str(),szSystemDir)) + return 2; //The opengl32.dll driver wasn't in windows system directory. + + //Check file size. Under 600k is wrong. + //Check http://support.microsoft.com/servicedesks/fileversion/dllinfo.asp?sd=MSDN + if (600000 > me.modBaseSize) + return 3; //This dll is way to small to be the standard opengl32.dll. + + //Extract version resource. + if (vi.HasErrors()) + return 4; //Typically a passthruu dll's aint got any version resource. + + //Check the version info for microsoft string. Can easily be done by hackers though + if (0 != strcmp(szMicrosoft, vi.CompanyName())) + return 5; //Should be Microsoft Corporation. + + //Check the productversion. + int iMajor, iMinor, iMicro, iState; + vi.ProductVersion(iMajor, iMinor, iMicro, iState); + if (iMajor < 4) + return 6; //Should be 4 or more. Cant do any more serious check than this because of the different flavors of windows... + } + +#ifdef _DEBUG + AgLog(m_sDll.c_str()); +#endif + //Oki - brute force method to check for hacks... its easy to rename dll's you know... + AgStringSet::iterator itrWallhackStrings; + unsigned long i = 0; + unsigned short x = 0; + bool bFoundHack = true; + unsigned char* pBuffer = NULL; + for (itrWallhackStrings = m_setBadStrings.begin() ;itrWallhackStrings != m_setBadStrings.end(); ++itrWallhackStrings) + { + unsigned short usSize = 0; + AgBase64Decode((*itrWallhackStrings).c_str(),(*itrWallhackStrings).size(),szSearch,usSize); + const unsigned char* pszSearch = szSearch; + i = 0; + unsigned long lCount = me.modBaseSize - usSize; + pBuffer = me.modBaseAddr; + do + { + //bFoundHack = FastCmp(pBuffer,pszSearch,usSize); + bFoundHack = true; + x = 0; + do + { + bFoundHack = *(pBuffer+x) == *(pszSearch+x); + ++x; + } + while (bFoundHack && x < usSize); + + if (bFoundHack) + { + AgLog(("Wallhack found in " + m_sDll + "\n").c_str()); + return 7; + } + ++pBuffer; + ++i; + } + while (i < lCount); + } + } + me.dwSize = sizeof(MODULEENTRY32); + } + while (m_lpfModule32Next(hSnapShot,&me)); + + ::CloseHandle(hSnapShot); + } + + if (!bCorrectAddress && !gEngfuncs.pfnGetCvarPointer(szCDFPS)) + { + m_sDll = "ogc type hooking library"; + return 10; + } + return 0; + /* + + + HANDLE hSnapShotProcess = m_lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); + if (INVALID_HANDLE_VALUE == hSnapShotProcess) + return -1; + + PROCESSENTRY32 pe; + pe.dwSize = sizeof(PROCESSENTRY32); + DWORD th32ProcessID = GetCurrentProcessId(); + + unsigned char* pFileBuffer = NULL; + DWORD dwBufferSize = 0; + if (m_lpfProcess32First(hSnapShotProcess,&pe)) + { + do + { + m_sDll = pe.szExeFile; + m_iFiles++; + if (th32ProcessID != pe.th32ProcessID) + { + AgVersionInfo vi; + vi.LoadVersionInfo(pe.szExeFile); + + //Check if microsoft dll. Let's hope that no hacker reads this source :P + if (!vi.HasErrors()) + { + AgString sCompanyName = vi.CompanyName(); + AgTrim(sCompanyName); + if ("Microsoft Corporation" == vi.CompanyName()) + continue; + } + + //Load the dll into a buffer so it's possible to scan the contence. + HANDLE hFile = CreateFile(pe.szExeFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0); + if (!hFile) + return 9; //Could not load the exe. + + DWORD dwSize = GetFileSize(hFile,NULL); + m_dwBytes += dwSize; + + if (dwBufferSize < dwSize) + { + if (pFileBuffer) + free(pFileBuffer); + dwBufferSize = dwSize; + pFileBuffer = (unsigned char*)malloc(dwBufferSize); + } + + DWORD dwRead = 0; + if (ReadFile(hFile,(void*)pFileBuffer,dwSize,&dwRead,NULL)) + { + if (dwRead == dwSize) + { + //Oki - brute force method to check for hacks... its easy to rename dll's you know... + AgStringSet::iterator itrWallhackStrings; + unsigned long i = 0; + unsigned short x = 0; + bool bFoundHack = true; + unsigned char* pBuffer = NULL; + for (itrWallhackStrings = m_setBadStrings.begin() ;itrWallhackStrings != m_setBadStrings.end(); ++itrWallhackStrings) + { + unsigned short usSize = 0; + AgBase64Decode((*itrWallhackStrings).c_str(),(*itrWallhackStrings).size(),szSearch,usSize); + const unsigned char* pszSearch = szSearch; + i = 0; + unsigned long lCount = dwSize - usSize; + pBuffer = pFileBuffer; + do + { + //bFoundHack = FastCmp(pBuffer,pszSearch,usSize); + bFoundHack = true; + x = 0; + do + { + bFoundHack = *(pBuffer+x) == *(pszSearch+x); + ++x; + } + while (bFoundHack && x < usSize); + + if (bFoundHack) + { + AgLog(("Wallhack found in " + m_sDll + "\n").c_str()); + return 7; + } + ++pBuffer; + ++i; + } + while (i < lCount); + } + + } + else + { + } + + } + else + { + } + + CloseHandle(hFile); + } + + pe.dwSize = sizeof(PROCESSENTRY32); + } + while (TRUE == m_lpfProcess32Next(hSnapShotProcess,&pe)); + + ::CloseHandle(hSnapShotProcess); + } + free(pFileBuffer); + */ +} + + +#ifdef DEBUG +#define IRC_CHANNEL "#aghl.beta" +#else +#define IRC_CHANNEL "#aghl" +#endif + +#ifdef AG_TESTCHEAT +#undef IRC_CHANNEL +#define IRC_CHANNEL "#aghl.beta" +#endif + +void AgWallhack::SendMessageToIRC(const char* szMessage) +{ + char szCommand[512]; + sprintf(szCommand,"irc_nick \"AGHL|CHEATER%0d\"",gEngfuncs.pfnRandomLong(0,99)); + ClientCmd(szCommand); + + sprintf(szCommand,"irc_server \"irc.quakenet.eu.org\""); + ClientCmd(szCommand); + + sprintf(szCommand,"irc_port \"6667\""); + ClientCmd(szCommand); + + sprintf(szCommand,"irc_autojoin \"%s\"",IRC_CHANNEL); + ClientCmd(szCommand); + + int iPlayer = gEngfuncs.GetLocalPlayer()->index; // Get the local player's index + + sprintf(szCommand,"irc_autocommand2 \"/msg %s %s (Authid=%s) %s\"", IRC_CHANNEL, gEngfuncs.PlayerInfo_ValueForKey(iPlayer,"name"), AgGetAuthID(iPlayer).c_str(), "was caught with a cheat. For more info see message below."); + ClientCmd(szCommand); + + sprintf(szCommand,"irc_autocommand3 \"/msg %s %s\"", IRC_CHANNEL, szMessage); + ClientCmd(szCommand); + + ClientCmd("ircconnect2"); +} + +#endif //AG_USE_CHEATPROTECTION +//-- Martin Webrant + + + diff --git a/cl_dll/aghl/agwallhack.h b/cl_dll/aghl/agwallhack.h new file mode 100644 index 00000000..7147b715 --- /dev/null +++ b/cl_dll/aghl/agwallhack.h @@ -0,0 +1,67 @@ +//++ BulliT +#if !defined(AFX_AGWALLHACK_H__72F3428F_5B58_4681_A572_92EAAE5B2F91__INCLUDED_) +#define AFX_AGWALLHACK_H__72F3428F_5B58_4681_A572_92EAAE5B2F91__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef AG_USE_CHEATPROTECTION + +// ToolHelp Function Pointers so that it will work on NT4 +#include +typedef HANDLE (WINAPI* CREATETOOLHELP32SNAPSHOT)(DWORD,DWORD); +typedef BOOL (WINAPI* MODULE32FIRST)(HANDLE,LPMODULEENTRY32); +typedef BOOL (WINAPI* MODULE32NEXT)(HANDLE,LPMODULEENTRY32); +typedef BOOL (WINAPI* PROCESS32FIRST)(HANDLE,LPPROCESSENTRY32); +typedef BOOL (WINAPI* PROCESS32NEXT)(HANDLE,LPPROCESSENTRY32); + +class AgWallhack +{ + CREATETOOLHELP32SNAPSHOT m_lpfCreateToolhelp32Snapshot; + MODULE32FIRST m_lpfModule32First; + MODULE32NEXT m_lpfModule32Next; + PROCESS32FIRST m_lpfProcess32First; + PROCESS32NEXT m_lpfProcess32Next; + HINSTANCE m_hKernel32; + + bool m_bDoneCheck; + bool InitToolHelp32(); + int InternalCheck(); + + AgStringSet m_setBadStrings; + AgStringSet m_setBadDlls; + AgStringSet m_setGoodDlls; + AgStringSet m_setGoodSystemDlls; + AgString m_sDll; + int m_iFiles; + DWORD m_dwBytes; + + DWORD m_dwHLAddressToValidate; + +public: + + AgWallhack(); + virtual ~AgWallhack(); + + void AddBadDll(const char* pszDll); + void AddBadString(const char* pszString); + void AddBadStrings(const char* pszStrings); + + bool Check(); + + void SetHLAddressToValidate(DWORD dwHLAddressToValidate) + { + m_dwHLAddressToValidate = dwHLAddressToValidate; + } + + void SendMessageToIRC(const char* szMessage); +}; + +extern AgWallhack g_Wallhack; + +#endif //AG_USE_CHEATPROTECTION + +#endif // !defined(AFX_AGWALLHACK_H__72F3428F_5B58_4681_A572_92EAAE5B2F91__INCLUDED_) + +//-- Martin Webrant diff --git a/cl_dll/aghl/crossthreadsmessagingdevice.cpp b/cl_dll/aghl/crossthreadsmessagingdevice.cpp new file mode 100644 index 00000000..2ebbf5b3 --- /dev/null +++ b/cl_dll/aghl/crossthreadsmessagingdevice.cpp @@ -0,0 +1,106 @@ +// CrossThreadsMessagingDevice.cpp +// Made by Adi Degani - http://www.codeguru.com/network/irc.html + +#include +#include +#include +#include "hud.h" +#include "cl_util.h" + +#define ASSERT + +#include "CrossThreadsMessagingDevice.h" + + +LPCSTR CCrossThreadsMessagingDevice::m_lpszClassName = "CCrossThreadsMessagingDevice_HiddenWindow"; +int CCrossThreadsMessagingDevice::m_iCount = 0; + + +CCrossThreadsMessagingDevice::CCrossThreadsMessagingDevice() + : m_hWnd(NULL), m_pMonitor(NULL) +{ + if( m_iCount++ == 0 ) + { + const WNDCLASS wc = + { + 0, + HiddenWindowProc, + sizeof(DWORD) * 2, + sizeof(DWORD) * 2, + GetModuleHandle("client.dll"), + (HICON)NULL, + (HCURSOR)NULL, + (HBRUSH)(COLOR_WINDOW + 1), + (LPCSTR)NULL, + m_lpszClassName + }; + + if( !RegisterClass(&wc) ) + return; + } + + m_hWnd = CreateWindow( + m_lpszClassName, + "", + WS_OVERLAPPED, + 0, 0, 0, 0, + (HWND)NULL, + (HMENU)NULL, + GetModuleHandle("client.dll"), + this + ); +} + +CCrossThreadsMessagingDevice::~CCrossThreadsMessagingDevice() +{ + if( ::IsWindow(m_hWnd) ) + DestroyWindow(m_hWnd); + + if( --m_iCount == 0 ) + { + UnregisterClass(m_lpszClassName, GetModuleHandle("client.dll")); + } +} + +void CCrossThreadsMessagingDevice::Post(WPARAM wParam, LPARAM lParam) +{ + ASSERT(::IsWindow(m_hWnd)); + PostMessage(m_hWnd, HWM_DATA, wParam, lParam); +} + +LRESULT WINAPI CCrossThreadsMessagingDevice::HiddenWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LRESULT rc = 0; + + CCrossThreadsMessagingDevice* pThis = + (CCrossThreadsMessagingDevice*)GetWindowLong(hWnd, GWL_USERDATA); + + switch( uMsg ) + { + case WM_NCCREATE : + { + LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam; + ASSERT(lpcs->lpCreateParams != NULL); + SetWindowLong(hWnd, GWL_USERDATA, (LONG)lpcs->lpCreateParams); + rc = TRUE; + break; + } + + case HWM_DATA : + { + ASSERT(pThis != NULL); + if( pThis->m_pMonitor ) + pThis->m_pMonitor->OnCrossThreadsMessage(wParam, lParam); + break; + } + + default : + { + rc = DefWindowProc(hWnd, uMsg, wParam, lParam); + break; + } + } + + return rc; +} + diff --git a/cl_dll/aghl/crossthreadsmessagingdevice.h b/cl_dll/aghl/crossthreadsmessagingdevice.h new file mode 100644 index 00000000..b50695b7 --- /dev/null +++ b/cl_dll/aghl/crossthreadsmessagingdevice.h @@ -0,0 +1,36 @@ +// CrossThreadsMessagingDevice.h + +#ifndef _CrossThreadsMessagingDevice_H_ +#define _CrossThreadsMessagingDevice_H_ + + +class CCrossThreadsMessagingDevice +{ +public : + struct ICrossThreadsMessagingDeviceMonitor + { + virtual void OnCrossThreadsMessage(WPARAM wParam, LPARAM lParam) = 0; + }; + + CCrossThreadsMessagingDevice(); + virtual ~CCrossThreadsMessagingDevice(); + + void SetMonitor(ICrossThreadsMessagingDeviceMonitor* pMonitor) { m_pMonitor = pMonitor; } + void Post(WPARAM wParam, LPARAM lParam); + + operator bool() const { return ::IsWindow(m_hWnd)==TRUE; } + +private : + enum { HWM_DATA = WM_USER + 1000 }; + static LPCSTR m_lpszClassName; + static int m_iCount; + HWND m_hWnd; + ICrossThreadsMessagingDeviceMonitor* m_pMonitor; + + static LRESULT WINAPI HiddenWindowProc(HWND, UINT, WPARAM, LPARAM); +}; + + + +#endif // _CrossThreadsMessagingDevice_H_ + diff --git a/cl_dll/aghl/dbghelp.h b/cl_dll/aghl/dbghelp.h new file mode 100644 index 00000000..30e68924 --- /dev/null +++ b/cl_dll/aghl/dbghelp.h @@ -0,0 +1,2471 @@ +// +// +// Copyright (c) 2002 Microsoft Corporation. All rights reserved. +// +// The use and distribution terms for this software are contained in the file +// named license.txt, which can be found in the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// You must not remove this notice, or any other, from this software. +// +// +// ==--== +/*++ BUILD Version: 0001 Increment this if a change has global effects + +Module Name: + + dbghelp.h + +Abstract: + + This module defines the prototypes and constants required for the image + help routines. + + Contains debugging support routines that are redistributable. + +Revision History: + +--*/ + +#ifndef _DBGHELP_ +#define _DBGHELP_ + +#if _MSC_VER > 1020 +#pragma once +#endif + + +// As a general principal always call the 64 bit version +// of every API, if a choice exists. The 64 bit version +// works great on 32 bit platforms, and is forward +// compatible to 64 bit platforms. + + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _IMAGEHLP_SOURCE_ +#define IMAGEAPI __stdcall +#define DBHLP_DEPRECIATED +#else +#define IMAGEAPI DECLSPEC_IMPORT __stdcall +#define DBHLP_DEPRECIATED DECLSPEC_DEPRECATED +#endif +#define DBHLPAPI IMAGEAPI + +#define IMAGE_SEPARATION (64*1024) + +typedef struct _LOADED_IMAGE { + PSTR ModuleName; + HANDLE hFile; + PUCHAR MappedAddress; +#ifdef _IMAGEHLP64 + PIMAGE_NT_HEADERS64 FileHeader; +#else + PIMAGE_NT_HEADERS32 FileHeader; +#endif + PIMAGE_SECTION_HEADER LastRvaSection; + ULONG NumberOfSections; + PIMAGE_SECTION_HEADER Sections; + ULONG Characteristics; + BOOLEAN fSystemImage; + BOOLEAN fDOSImage; + LIST_ENTRY Links; + ULONG SizeOfImage; +} LOADED_IMAGE, *PLOADED_IMAGE; + + + +HANDLE +IMAGEAPI +FindDebugInfoFile ( + PSTR FileName, + PSTR SymbolPath, + PSTR DebugFilePath + ); + +typedef BOOL +(CALLBACK *PFIND_DEBUG_FILE_CALLBACK)( + HANDLE FileHandle, + PSTR FileName, + PVOID CallerData + ); + +HANDLE +IMAGEAPI +FindDebugInfoFileEx ( + PSTR FileName, + PSTR SymbolPath, + PSTR DebugFilePath, + PFIND_DEBUG_FILE_CALLBACK Callback, + PVOID CallerData + ); + +typedef BOOL +(CALLBACK *PFINDFILEINPATHCALLBACK)( + PSTR filename, + PVOID context + ); + +BOOL +IMAGEAPI +SymFindFileInPath( + HANDLE hprocess, + LPSTR SearchPath, + LPSTR FileName, + PVOID id, + DWORD two, + DWORD three, + DWORD flags, + LPSTR FilePath, + PFINDFILEINPATHCALLBACK callback, + PVOID context + ); + +HANDLE +IMAGEAPI +FindExecutableImage( + PSTR FileName, + PSTR SymbolPath, + PSTR ImageFilePath + ); + +typedef BOOL +(CALLBACK *PFIND_EXE_FILE_CALLBACK)( + HANDLE FileHandle, + PSTR FileName, + PVOID CallerData + ); + +HANDLE +IMAGEAPI +FindExecutableImageEx( + PSTR FileName, + PSTR SymbolPath, + PSTR ImageFilePath, + PFIND_EXE_FILE_CALLBACK Callback, + PVOID CallerData + ); + +PIMAGE_NT_HEADERS +IMAGEAPI +ImageNtHeader ( + IN PVOID Base + ); + +PVOID +IMAGEAPI +ImageDirectoryEntryToDataEx ( + IN PVOID Base, + IN BOOLEAN MappedAsImage, + IN USHORT DirectoryEntry, + OUT PULONG Size, + OUT PIMAGE_SECTION_HEADER *FoundHeader OPTIONAL + ); + +PVOID +IMAGEAPI +ImageDirectoryEntryToData ( + IN PVOID Base, + IN BOOLEAN MappedAsImage, + IN USHORT DirectoryEntry, + OUT PULONG Size + ); + +PIMAGE_SECTION_HEADER +IMAGEAPI +ImageRvaToSection( + IN PIMAGE_NT_HEADERS NtHeaders, + IN PVOID Base, + IN ULONG Rva + ); + +PVOID +IMAGEAPI +ImageRvaToVa( + IN PIMAGE_NT_HEADERS NtHeaders, + IN PVOID Base, + IN ULONG Rva, + IN OUT PIMAGE_SECTION_HEADER *LastRvaSection + ); + +// Symbol server exports + +typedef BOOL (*PSYMBOLSERVERPROC)(LPCSTR, LPCSTR, PVOID, DWORD, DWORD, LPSTR); +typedef BOOL (*PSYMBOLSERVEROPENPROC)(VOID); +typedef BOOL (*PSYMBOLSERVERCLOSEPROC)(VOID); +typedef BOOL (*PSYMBOLSERVERSETOPTIONSPROC)(UINT_PTR, ULONG64); +typedef BOOL (CALLBACK *PSYMBOLSERVERCALLBACKPROC)(UINT_PTR action, ULONG64 data, ULONG64 context); +typedef UINT_PTR (*PSYMBOLSERVERGETOPTIONSPROC)(); + +#define SSRVOPT_CALLBACK 0x01 +#define SSRVOPT_DWORD 0x02 +#define SSRVOPT_DWORDPTR 0x04 +#define SSRVOPT_GUIDPTR 0x08 +#define SSRVOPT_OLDGUIDPTR 0x10 +#define SSRVOPT_UNATTENDED 0x20 +#define SSRVOPT_NOCOPY 0x40 +#define SSRVOPT_PARENTWIN 0x80 +#define SSRVOPT_RESET ((ULONG_PTR)-1) + +#define SSRVACTION_TRACE 1 + + + +typedef struct _IMAGE_DEBUG_INFORMATION { + LIST_ENTRY List; + DWORD ReservedSize; + PVOID ReservedMappedBase; + USHORT ReservedMachine; + USHORT ReservedCharacteristics; + DWORD ReservedCheckSum; + DWORD ImageBase; + DWORD SizeOfImage; + + DWORD ReservedNumberOfSections; + PIMAGE_SECTION_HEADER ReservedSections; + + DWORD ReservedExportedNamesSize; + PSTR ReservedExportedNames; + + DWORD ReservedNumberOfFunctionTableEntries; + PIMAGE_FUNCTION_ENTRY ReservedFunctionTableEntries; + DWORD ReservedLowestFunctionStartingAddress; + DWORD ReservedHighestFunctionEndingAddress; + + DWORD ReservedNumberOfFpoTableEntries; + PFPO_DATA ReservedFpoTableEntries; + + DWORD SizeOfCoffSymbols; + PIMAGE_COFF_SYMBOLS_HEADER CoffSymbols; + + DWORD ReservedSizeOfCodeViewSymbols; + PVOID ReservedCodeViewSymbols; + + PSTR ImageFilePath; + PSTR ImageFileName; + PSTR ReservedDebugFilePath; + + DWORD ReservedTimeDateStamp; + + BOOL ReservedRomImage; + PIMAGE_DEBUG_DIRECTORY ReservedDebugDirectory; + DWORD ReservedNumberOfDebugDirectories; + + DWORD ReservedOriginalFunctionTableBaseAddress; + + DWORD Reserved[ 2 ]; + +} IMAGE_DEBUG_INFORMATION, *PIMAGE_DEBUG_INFORMATION; + + +PIMAGE_DEBUG_INFORMATION +IMAGEAPI +MapDebugInformation( + HANDLE FileHandle, + PSTR FileName, + PSTR SymbolPath, + DWORD ImageBase + ); + +BOOL +IMAGEAPI +UnmapDebugInformation( + PIMAGE_DEBUG_INFORMATION DebugInfo + ); + + +BOOL +IMAGEAPI +SearchTreeForFile( + PSTR RootPath, + PSTR InputPathName, + PSTR OutputPathBuffer + ); + +BOOL +IMAGEAPI +MakeSureDirectoryPathExists( + PCSTR DirPath + ); + +// +// UnDecorateSymbolName Flags +// + +#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration +#define UNDNAME_NO_LEADING_UNDERSCORES (0x0001) // Remove leading underscores from MS extended keywords +#define UNDNAME_NO_MS_KEYWORDS (0x0002) // Disable expansion of MS extended keywords +#define UNDNAME_NO_FUNCTION_RETURNS (0x0004) // Disable expansion of return type for primary declaration +#define UNDNAME_NO_ALLOCATION_MODEL (0x0008) // Disable expansion of the declaration model +#define UNDNAME_NO_ALLOCATION_LANGUAGE (0x0010) // Disable expansion of the declaration language specifier +#define UNDNAME_NO_MS_THISTYPE (0x0020) // NYI Disable expansion of MS keywords on the 'this' type for primary declaration +#define UNDNAME_NO_CV_THISTYPE (0x0040) // NYI Disable expansion of CV modifiers on the 'this' type for primary declaration +#define UNDNAME_NO_THISTYPE (0x0060) // Disable all modifiers on the 'this' type +#define UNDNAME_NO_ACCESS_SPECIFIERS (0x0080) // Disable expansion of access specifiers for members +#define UNDNAME_NO_THROW_SIGNATURES (0x0100) // Disable expansion of 'throw-signatures' for functions and pointers to functions +#define UNDNAME_NO_MEMBER_TYPE (0x0200) // Disable expansion of 'static' or 'virtual'ness of members +#define UNDNAME_NO_RETURN_UDT_MODEL (0x0400) // Disable expansion of MS model for UDT returns +#define UNDNAME_32_BIT_DECODE (0x0800) // Undecorate 32-bit decorated names +#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration; + // return just [scope::]name. Does expand template params +#define UNDNAME_NO_ARGUMENTS (0x2000) // Don't undecorate arguments to function +#define UNDNAME_NO_SPECIAL_SYMS (0x4000) // Don't undecorate special names (v-table, vcall, vector xxx, metatype, etc) + +DWORD +IMAGEAPI +WINAPI +UnDecorateSymbolName( + PCSTR DecoratedName, // Name to undecorate + PSTR UnDecoratedName, // If NULL, it will be allocated + DWORD UndecoratedLength, // The maximym length + DWORD Flags // See above. + ); + + +// +// these values are used for synthesized file types +// that can be passed in as image headers instead of +// the standard ones from ntimage.h +// + +#define DBHHEADER_DEBUGDIRS 0x1 + +typedef struct _DBGHELP_MODLOAD_DATA { + DWORD ssize; // size of this struct + DWORD ssig; // signature identifying the passed data + PVOID data; // pointer to passed data + DWORD size; // size of passed data + DWORD flags; // options +} MODLOAD_DATA, *PMODLOAD_DATA; + +// +// StackWalking API +// + +typedef enum { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat +} ADDRESS_MODE; + +typedef struct _tagADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; +} ADDRESS64, *LPADDRESS64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define ADDRESS ADDRESS64 +#define LPADDRESS LPADDRESS64 +#else +typedef struct _tagADDRESS { + DWORD Offset; + WORD Segment; + ADDRESS_MODE Mode; +} ADDRESS, *LPADDRESS; + +__inline +void +Address32To64( + LPADDRESS a32, + LPADDRESS64 a64 + ) +{ + a64->Offset = (ULONG64)(LONG64)(LONG)a32->Offset; + a64->Segment = a32->Segment; + a64->Mode = a32->Mode; +} + +__inline +void +Address64To32( + LPADDRESS64 a64, + LPADDRESS a32 + ) +{ + a32->Offset = (ULONG)a64->Offset; + a32->Segment = a64->Segment; + a32->Mode = a64->Mode; +} +#endif + +// +// This structure is included in the STACKFRAME structure, +// and is used to trace through usermode callbacks in a thread's +// kernel stack. The values must be copied by the kernel debugger +// from the DBGKD_GET_VERSION and WAIT_STATE_CHANGE packets. +// + +// +// New KDHELP structure for 64 bit system support. +// This structure is preferred in new code. +// +typedef struct _KDHELP64 { + + // + // address of kernel thread object, as provided in the + // WAIT_STATE_CHANGE packet. + // + DWORD64 Thread; + + // + // offset in thread object to pointer to the current callback frame + // in kernel stack. + // + DWORD ThCallbackStack; + + // + // offset in thread object to pointer to the current callback backing + // store frame in kernel stack. + // + DWORD ThCallbackBStore; + + // + // offsets to values in frame: + // + // address of next callback frame + DWORD NextCallback; + + // address of saved frame pointer (if applicable) + DWORD FramePointer; + + + // + // Address of the kernel function that calls out to user mode + // + DWORD64 KiCallUserMode; + + // + // Address of the user mode dispatcher function + // + DWORD64 KeUserCallbackDispatcher; + + // + // Lowest kernel mode address + // + DWORD64 SystemRangeStart; + + DWORD64 Reserved[8]; + +} KDHELP64, *PKDHELP64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define KDHELP KDHELP64 +#define PKDHELP PKDHELP64 +#else +typedef struct _KDHELP { + + // + // address of kernel thread object, as provided in the + // WAIT_STATE_CHANGE packet. + // + DWORD Thread; + + // + // offset in thread object to pointer to the current callback frame + // in kernel stack. + // + DWORD ThCallbackStack; + + // + // offsets to values in frame: + // + // address of next callback frame + DWORD NextCallback; + + // address of saved frame pointer (if applicable) + DWORD FramePointer; + + // + // Address of the kernel function that calls out to user mode + // + DWORD KiCallUserMode; + + // + // Address of the user mode dispatcher function + // + DWORD KeUserCallbackDispatcher; + + // + // Lowest kernel mode address + // + DWORD SystemRangeStart; + + // + // offset in thread object to pointer to the current callback backing + // store frame in kernel stack. + // + DWORD ThCallbackBStore; + + DWORD Reserved[8]; + +} KDHELP, *PKDHELP; + +__inline +void +KdHelp32To64( + PKDHELP p32, + PKDHELP64 p64 + ) +{ + p64->Thread = p32->Thread; + p64->ThCallbackStack = p32->ThCallbackStack; + p64->NextCallback = p32->NextCallback; + p64->FramePointer = p32->FramePointer; + p64->KiCallUserMode = p32->KiCallUserMode; + p64->KeUserCallbackDispatcher = p32->KeUserCallbackDispatcher; + p64->SystemRangeStart = p32->SystemRangeStart; +} +#endif + +typedef struct _tagSTACKFRAME64 { + ADDRESS64 AddrPC; // program counter + ADDRESS64 AddrReturn; // return address + ADDRESS64 AddrFrame; // frame pointer + ADDRESS64 AddrStack; // stack pointer + ADDRESS64 AddrBStore; // backing store pointer + PVOID FuncTableEntry; // pointer to pdata/fpo or NULL + DWORD64 Params[4]; // possible arguments to the function + BOOL Far; // WOW far call + BOOL Virtual; // is this a virtual frame? + DWORD64 Reserved[3]; + KDHELP64 KdHelp; +} STACKFRAME64, *LPSTACKFRAME64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define STACKFRAME STACKFRAME64 +#define LPSTACKFRAME LPSTACKFRAME64 +#else +typedef struct _tagSTACKFRAME { + ADDRESS AddrPC; // program counter + ADDRESS AddrReturn; // return address + ADDRESS AddrFrame; // frame pointer + ADDRESS AddrStack; // stack pointer + PVOID FuncTableEntry; // pointer to pdata/fpo or NULL + DWORD Params[4]; // possible arguments to the function + BOOL Far; // WOW far call + BOOL Virtual; // is this a virtual frame? + DWORD Reserved[3]; + KDHELP KdHelp; + ADDRESS AddrBStore; // backing store pointer +} STACKFRAME, *LPSTACKFRAME; +#endif + + +typedef +BOOL +(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( + HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead + ); + +typedef +PVOID +(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( + HANDLE hProcess, + DWORD64 AddrBase + ); + +typedef +DWORD64 +(__stdcall *PGET_MODULE_BASE_ROUTINE64)( + HANDLE hProcess, + DWORD64 Address + ); + +typedef +DWORD64 +(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( + HANDLE hProcess, + HANDLE hThread, + LPADDRESS64 lpaddr + ); + +BOOL +IMAGEAPI +StackWalk64( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, + PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) + +#define PREAD_PROCESS_MEMORY_ROUTINE PREAD_PROCESS_MEMORY_ROUTINE64 +#define PFUNCTION_TABLE_ACCESS_ROUTINE PFUNCTION_TABLE_ACCESS_ROUTINE64 +#define PGET_MODULE_BASE_ROUTINE PGET_MODULE_BASE_ROUTINE64 +#define PTRANSLATE_ADDRESS_ROUTINE PTRANSLATE_ADDRESS_ROUTINE64 + +#define StackWalk StackWalk64 + +#else + +typedef +BOOL +(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE)( + HANDLE hProcess, + DWORD lpBaseAddress, + PVOID lpBuffer, + DWORD nSize, + PDWORD lpNumberOfBytesRead + ); + +typedef +PVOID +(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE)( + HANDLE hProcess, + DWORD AddrBase + ); + +typedef +DWORD +(__stdcall *PGET_MODULE_BASE_ROUTINE)( + HANDLE hProcess, + DWORD Address + ); + +typedef +DWORD +(__stdcall *PTRANSLATE_ADDRESS_ROUTINE)( + HANDLE hProcess, + HANDLE hThread, + LPADDRESS lpaddr + ); + +BOOL +IMAGEAPI +StackWalk( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME StackFrame, + PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE TranslateAddress + ); + +#endif + + +#define API_VERSION_NUMBER 9 + +typedef struct API_VERSION { + USHORT MajorVersion; + USHORT MinorVersion; + USHORT Revision; + USHORT Reserved; +} API_VERSION, *LPAPI_VERSION; + +LPAPI_VERSION +IMAGEAPI +ImagehlpApiVersion( + VOID + ); + +LPAPI_VERSION +IMAGEAPI +ImagehlpApiVersionEx( + LPAPI_VERSION AppVersion + ); + +DWORD +IMAGEAPI +GetTimestampForLoadedLibrary( + HMODULE Module + ); + +// +// typedefs for function pointers +// +typedef BOOL +(CALLBACK *PSYM_ENUMMODULES_CALLBACK64)( + PSTR ModuleName, + DWORD64 BaseOfDll, + PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK64)( + PSTR SymbolName, + DWORD64 SymbolAddress, + ULONG SymbolSize, + PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK64W)( + PWSTR SymbolName, + DWORD64 SymbolAddress, + ULONG SymbolSize, + PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PENUMLOADED_MODULES_CALLBACK64)( + PSTR ModuleName, + DWORD64 ModuleBase, + ULONG ModuleSize, + PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYMBOL_REGISTERED_CALLBACK64)( + HANDLE hProcess, + ULONG ActionCode, + ULONG64 CallbackData, + ULONG64 UserContext + ); + +typedef +PVOID +(CALLBACK *PSYMBOL_FUNCENTRY_CALLBACK)( + HANDLE hProcess, + DWORD AddrBase, + PVOID UserContext + ); + +typedef +PVOID +(CALLBACK *PSYMBOL_FUNCENTRY_CALLBACK64)( + HANDLE hProcess, + ULONG64 AddrBase, + ULONG64 UserContext + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) + +#define PSYM_ENUMMODULES_CALLBACK PSYM_ENUMMODULES_CALLBACK64 +#define PSYM_ENUMSYMBOLS_CALLBACK PSYM_ENUMSYMBOLS_CALLBACK64 +#define PSYM_ENUMSYMBOLS_CALLBACKW PSYM_ENUMSYMBOLS_CALLBACK64W +#define PENUMLOADED_MODULES_CALLBACK PENUMLOADED_MODULES_CALLBACK64 +#define PSYMBOL_REGISTERED_CALLBACK PSYMBOL_REGISTERED_CALLBACK64 +#define PSYMBOL_FUNCENTRY_CALLBACK PSYMBOL_FUNCENTRY_CALLBACK64 + +#else + +typedef BOOL +(CALLBACK *PSYM_ENUMMODULES_CALLBACK)( + PSTR ModuleName, + ULONG BaseOfDll, + PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK)( + PSTR SymbolName, + ULONG SymbolAddress, + ULONG SymbolSize, + PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSYMBOLS_CALLBACKW)( + PWSTR SymbolName, + ULONG SymbolAddress, + ULONG SymbolSize, + PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PENUMLOADED_MODULES_CALLBACK)( + PSTR ModuleName, + ULONG ModuleBase, + ULONG ModuleSize, + PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYMBOL_REGISTERED_CALLBACK)( + HANDLE hProcess, + ULONG ActionCode, + PVOID CallbackData, + PVOID UserContext + ); + +#endif + + +// +// symbol flags +// + +#define SYMF_OMAP_GENERATED 0x00000001 +#define SYMF_OMAP_MODIFIED 0x00000002 +#ifndef _DBGHELP_USER_GENERATED_SYMBOLS_NOTSUPPORTED + #define SYMF_USER_GENERATED 0x00000004 +#endif // !_DBGHELP_USER_GENERATED_SYMBOLS_NOTSUPPORTED +#define SYMF_REGISTER 0x00000008 +#define SYMF_REGREL 0x00000010 +#define SYMF_FRAMEREL 0x00000020 +#define SYMF_PARAMETER 0x00000040 +#define SYMF_LOCAL 0x00000080 +#define SYMF_CONSTANT 0x00000100 +#define SYMF_EXPORT 0x00000200 +#define SYMF_FORWARDER 0x00000400 +#define SYMF_FUNCTION 0x00000800 +#define SYMF_VIRTUAL 0x00001000 +// +// symbol type enumeration +// +typedef enum { + SymNone = 0, + SymCoff, + SymCv, + SymPdb, + SymExport, + SymDeferred, + SymSym, // .sym file + SymDia, + NumSymTypes +} SYM_TYPE; + +// +// symbol data structure +// + +typedef struct _IMAGEHLP_SYMBOL64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) + DWORD64 Address; // virtual address including dll base address + DWORD Size; // estimated size of symbol, can be zero + DWORD Flags; // info about the symbols, see the SYMF defines + DWORD MaxNameLength; // maximum size of symbol name in 'Name' + CHAR Name[1]; // symbol name (null terminated string) +} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define IMAGEHLP_SYMBOL IMAGEHLP_SYMBOL64 +#define PIMAGEHLP_SYMBOL PIMAGEHLP_SYMBOL64 +#else +typedef struct _IMAGEHLP_SYMBOL { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL) + DWORD Address; // virtual address including dll base address + DWORD Size; // estimated size of symbol, can be zero + DWORD Flags; // info about the symbols, see the SYMF defines + DWORD MaxNameLength; // maximum size of symbol name in 'Name' + CHAR Name[1]; // symbol name (null terminated string) +} IMAGEHLP_SYMBOL, *PIMAGEHLP_SYMBOL; +#endif + +// +// module data structure +// + +typedef struct _IMAGEHLP_MODULE64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name +} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64; + +typedef struct _IMAGEHLP_MODULE64W { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + WCHAR ModuleName[32]; // module name + WCHAR ImageName[256]; // image name + WCHAR LoadedImageName[256]; // symbol file name +} IMAGEHLP_MODULEW64, *PIMAGEHLP_MODULEW64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define IMAGEHLP_MODULE IMAGEHLP_MODULE64 +#define PIMAGEHLP_MODULE PIMAGEHLP_MODULE64 +#define IMAGEHLP_MODULEW IMAGEHLP_MODULEW64 +#define PIMAGEHLP_MODULEW PIMAGEHLP_MODULEW64 +#else +typedef struct _IMAGEHLP_MODULE { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE) + DWORD BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name +} IMAGEHLP_MODULE, *PIMAGEHLP_MODULE; + +typedef struct _IMAGEHLP_MODULEW { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE) + DWORD BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + WCHAR ModuleName[32]; // module name + WCHAR ImageName[256]; // image name + WCHAR LoadedImageName[256]; // symbol file name +} IMAGEHLP_MODULEW, *PIMAGEHLP_MODULEW; +#endif + +// +// source file line data structure +// + +typedef struct _IMAGEHLP_LINE64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) + PVOID Key; // internal + DWORD LineNumber; // line number in file + PCHAR FileName; // full filename + DWORD64 Address; // first instruction of line +} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define IMAGEHLP_LINE IMAGEHLP_LINE64 +#define PIMAGEHLP_LINE PIMAGEHLP_LINE64 +#else +typedef struct _IMAGEHLP_LINE { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE) + PVOID Key; // internal + DWORD LineNumber; // line number in file + PCHAR FileName; // full filename + DWORD Address; // first instruction of line +} IMAGEHLP_LINE, *PIMAGEHLP_LINE; +#endif + +// +// source file structure +// + +typedef struct _SOURCEFILE { + DWORD64 ModBase; // base address of loaded module + PCHAR FileName; // full filename of source +} SOURCEFILE, *PSOURCEFILE; + +// +// data structures used for registered symbol callbacks +// + +#define CBA_DEFERRED_SYMBOL_LOAD_START 0x00000001 +#define CBA_DEFERRED_SYMBOL_LOAD_COMPLETE 0x00000002 +#define CBA_DEFERRED_SYMBOL_LOAD_FAILURE 0x00000003 +#define CBA_SYMBOLS_UNLOADED 0x00000004 +#define CBA_DUPLICATE_SYMBOL 0x00000005 +#define CBA_READ_MEMORY 0x00000006 +#define CBA_DEFERRED_SYMBOL_LOAD_CANCEL 0x00000007 +#define CBA_SET_OPTIONS 0x00000008 +#define CBA_EVENT 0x00000010 +#define CBA_DEBUG_INFO 0x10000000 + +typedef struct _IMAGEHLP_CBA_READ_MEMORY { + DWORD64 addr; // address to read from + PVOID buf; // buffer to read to + DWORD bytes; // amount of bytes to read + DWORD *bytesread; // pointer to store amount of bytes read +} IMAGEHLP_CBA_READ_MEMORY, *PIMAGEHLP_CBA_READ_MEMORY; + +enum { + sevInfo = 0, + sevProblem, + sevAttn, + sevFatal, + sevMax // unused +}; + +typedef struct _IMAGEHLP_CBA_EVENT { + DWORD severity; // values from sevInfo to sevFatal + DWORD code; // numerical code IDs the error + PCHAR desc; // may contain a text description of the error + PVOID object; // value dependant upon the error code +} IMAGEHLP_CBA_EVENT, *PIMAGEHLP_CBA_EVENT; + +typedef struct _IMAGEHLP_DEFERRED_SYMBOL_LOAD64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_DEFERRED_SYMBOL_LOAD64) + DWORD64 BaseOfImage; // base load address of module + DWORD CheckSum; // checksum from the pe header + DWORD TimeDateStamp; // date/time stamp from pe header + CHAR FileName[MAX_PATH]; // symbols file or image name + BOOLEAN Reparse; // load failure reparse +} IMAGEHLP_DEFERRED_SYMBOL_LOAD64, *PIMAGEHLP_DEFERRED_SYMBOL_LOAD64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define IMAGEHLP_DEFERRED_SYMBOL_LOAD IMAGEHLP_DEFERRED_SYMBOL_LOAD64 +#define PIMAGEHLP_DEFERRED_SYMBOL_LOAD PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 +#else +typedef struct _IMAGEHLP_DEFERRED_SYMBOL_LOAD { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_DEFERRED_SYMBOL_LOAD) + DWORD BaseOfImage; // base load address of module + DWORD CheckSum; // checksum from the pe header + DWORD TimeDateStamp; // date/time stamp from pe header + CHAR FileName[MAX_PATH]; // symbols file or image name + BOOLEAN Reparse; // load failure reparse +} IMAGEHLP_DEFERRED_SYMBOL_LOAD, *PIMAGEHLP_DEFERRED_SYMBOL_LOAD; +#endif + +typedef struct _IMAGEHLP_DUPLICATE_SYMBOL64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_DUPLICATE_SYMBOL64) + DWORD NumberOfDups; // number of duplicates in the Symbol array + PIMAGEHLP_SYMBOL64 Symbol; // array of duplicate symbols + DWORD SelectedSymbol; // symbol selected (-1 to start) +} IMAGEHLP_DUPLICATE_SYMBOL64, *PIMAGEHLP_DUPLICATE_SYMBOL64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define IMAGEHLP_DUPLICATE_SYMBOL IMAGEHLP_DUPLICATE_SYMBOL64 +#define PIMAGEHLP_DUPLICATE_SYMBOL PIMAGEHLP_DUPLICATE_SYMBOL64 +#else +typedef struct _IMAGEHLP_DUPLICATE_SYMBOL { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_DUPLICATE_SYMBOL) + DWORD NumberOfDups; // number of duplicates in the Symbol array + PIMAGEHLP_SYMBOL Symbol; // array of duplicate symbols + DWORD SelectedSymbol; // symbol selected (-1 to start) +} IMAGEHLP_DUPLICATE_SYMBOL, *PIMAGEHLP_DUPLICATE_SYMBOL; +#endif + +// If dbghelp ever needs to display graphical UI, it will use this as the parent window. + +BOOL +SymSetParentWindow( + HWND hwnd + ); + +// +// options that are set/returned by SymSetOptions() & SymGetOptions() +// these are used as a mask +// +#define SYMOPT_CASE_INSENSITIVE 0x00000001 +#define SYMOPT_UNDNAME 0x00000002 +#define SYMOPT_DEFERRED_LOADS 0x00000004 +#define SYMOPT_NO_CPP 0x00000008 +#define SYMOPT_LOAD_LINES 0x00000010 +#define SYMOPT_OMAP_FIND_NEAREST 0x00000020 +#define SYMOPT_LOAD_ANYTHING 0x00000040 +#define SYMOPT_IGNORE_CVREC 0x00000080 +#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 +#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 +#define SYMOPT_EXACT_SYMBOLS 0x00000400 +#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 + +#define SYMOPT_DEBUG 0x80000000 + +DWORD +IMAGEAPI +SymSetOptions( + IN DWORD SymOptions + ); + +DWORD +IMAGEAPI +SymGetOptions( + VOID + ); + +BOOL +IMAGEAPI +SymCleanup( + IN HANDLE hProcess + ); + +BOOL +IMAGEAPI +SymMatchString( + IN LPSTR string, + IN LPSTR expression, + IN BOOL fCase + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSOURCFILES_CALLBACK)( + PSOURCEFILE pSourceFile, + PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumSourceFiles( + IN HANDLE hProcess, + IN ULONG64 ModBase, + IN LPSTR Mask, + IN PSYM_ENUMSOURCFILES_CALLBACK cbSrcFiles, + IN PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumerateModules64( + IN HANDLE hProcess, + IN PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback, + IN PVOID UserContext + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymEnumerateModules SymEnumerateModules64 +#else +BOOL +IMAGEAPI +SymEnumerateModules( + IN HANDLE hProcess, + IN PSYM_ENUMMODULES_CALLBACK EnumModulesCallback, + IN PVOID UserContext + ); +#endif + +BOOL +IMAGEAPI +SymEnumerateSymbols64( + IN HANDLE hProcess, + IN DWORD64 BaseOfDll, + IN PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback, + IN PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumerateSymbolsW64( + IN HANDLE hProcess, + IN DWORD64 BaseOfDll, + IN PSYM_ENUMSYMBOLS_CALLBACK64W EnumSymbolsCallback, + IN PVOID UserContext + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymEnumerateSymbols SymEnumerateSymbols64 +#define SymEnumerateSymbolsW SymEnumerateSymbolsW64 +#else +BOOL +IMAGEAPI +SymEnumerateSymbols( + IN HANDLE hProcess, + IN DWORD BaseOfDll, + IN PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback, + IN PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumerateSymbolsW( + IN HANDLE hProcess, + IN DWORD BaseOfDll, + IN PSYM_ENUMSYMBOLS_CALLBACKW EnumSymbolsCallback, + IN PVOID UserContext + ); +#endif + +BOOL +IMAGEAPI +EnumerateLoadedModules64( + IN HANDLE hProcess, + IN PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback, + IN PVOID UserContext + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define EnumerateLoadedModules EnumerateLoadedModules64 +#else +BOOL +IMAGEAPI +EnumerateLoadedModules( + IN HANDLE hProcess, + IN PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback, + IN PVOID UserContext + ); +#endif + +PVOID +IMAGEAPI +SymFunctionTableAccess64( + HANDLE hProcess, + DWORD64 AddrBase + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymFunctionTableAccess SymFunctionTableAccess64 +#else +PVOID +IMAGEAPI +SymFunctionTableAccess( + HANDLE hProcess, + DWORD AddrBase + ); +#endif + +BOOL +IMAGEAPI +SymGetModuleInfo64( + IN HANDLE hProcess, + IN DWORD64 qwAddr, + OUT PIMAGEHLP_MODULE64 ModuleInfo + ); + +BOOL +IMAGEAPI +SymGetModuleInfoW64( + IN HANDLE hProcess, + IN DWORD64 qwAddr, + OUT PIMAGEHLP_MODULEW64 ModuleInfo + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetModuleInfo SymGetModuleInfo64 +#define SymGetModuleInfoW SymGetModuleInfoW64 +#else +BOOL +IMAGEAPI +SymGetModuleInfo( + IN HANDLE hProcess, + IN DWORD dwAddr, + OUT PIMAGEHLP_MODULE ModuleInfo + ); + +BOOL +IMAGEAPI +SymGetModuleInfoW( + IN HANDLE hProcess, + IN DWORD dwAddr, + OUT PIMAGEHLP_MODULEW ModuleInfo + ); +#endif + +DWORD64 +IMAGEAPI +SymGetModuleBase64( + IN HANDLE hProcess, + IN DWORD64 qwAddr + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetModuleBase SymGetModuleBase64 +#else +DWORD +IMAGEAPI +SymGetModuleBase( + IN HANDLE hProcess, + IN DWORD dwAddr + ); +#endif + +BOOL +IMAGEAPI +SymGetSymNext64( + IN HANDLE hProcess, + IN OUT PIMAGEHLP_SYMBOL64 Symbol + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetSymNext SymGetSymNext64 +#else +BOOL +IMAGEAPI +SymGetSymNext( + IN HANDLE hProcess, + IN OUT PIMAGEHLP_SYMBOL Symbol + ); +#endif + +BOOL +IMAGEAPI +SymGetSymPrev64( + IN HANDLE hProcess, + IN OUT PIMAGEHLP_SYMBOL64 Symbol + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetSymPrev SymGetSymPrev64 +#else +BOOL +IMAGEAPI +SymGetSymPrev( + IN HANDLE hProcess, + IN OUT PIMAGEHLP_SYMBOL Symbol + ); +#endif + +BOOL +IMAGEAPI +SymGetLineFromAddr64( + IN HANDLE hProcess, + IN DWORD64 qwAddr, + OUT PDWORD pdwDisplacement, + OUT PIMAGEHLP_LINE64 Line + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetLineFromAddr SymGetLineFromAddr64 +#else +BOOL +IMAGEAPI +SymGetLineFromAddr( + IN HANDLE hProcess, + IN DWORD dwAddr, + OUT PDWORD pdwDisplacement, + OUT PIMAGEHLP_LINE Line + ); +#endif + +BOOL +IMAGEAPI +SymGetLineFromName64( + IN HANDLE hProcess, + IN PSTR ModuleName, + IN PSTR FileName, + IN DWORD dwLineNumber, + OUT PLONG plDisplacement, + IN OUT PIMAGEHLP_LINE64 Line + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetLineFromName SymGetLineFromName64 +#else +BOOL +IMAGEAPI +SymGetLineFromName( + IN HANDLE hProcess, + IN PSTR ModuleName, + IN PSTR FileName, + IN DWORD dwLineNumber, + OUT PLONG plDisplacement, + IN OUT PIMAGEHLP_LINE Line + ); +#endif + +BOOL +IMAGEAPI +SymGetLineNext64( + IN HANDLE hProcess, + IN OUT PIMAGEHLP_LINE64 Line + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetLineNext SymGetLineNext64 +#else +BOOL +IMAGEAPI +SymGetLineNext( + IN HANDLE hProcess, + IN OUT PIMAGEHLP_LINE Line + ); +#endif + +BOOL +IMAGEAPI +SymGetLinePrev64( + IN HANDLE hProcess, + IN OUT PIMAGEHLP_LINE64 Line + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetLinePrev SymGetLinePrev64 +#else +BOOL +IMAGEAPI +SymGetLinePrev( + IN HANDLE hProcess, + IN OUT PIMAGEHLP_LINE Line + ); +#endif + +BOOL +IMAGEAPI +SymMatchFileName( + IN PSTR FileName, + IN PSTR Match, + OUT PSTR *FileNameStop, + OUT PSTR *MatchStop + ); + +BOOL +IMAGEAPI +SymInitialize( + IN HANDLE hProcess, + IN PSTR UserSearchPath, + IN BOOL fInvadeProcess + ); + +BOOL +IMAGEAPI +SymGetSearchPath( + IN HANDLE hProcess, + OUT PSTR SearchPath, + IN DWORD SearchPathLength + ); + +BOOL +IMAGEAPI +SymSetSearchPath( + IN HANDLE hProcess, + IN PSTR SearchPath + ); + +DWORD64 +IMAGEAPI +SymLoadModule64( + IN HANDLE hProcess, + IN HANDLE hFile, + IN PSTR ImageName, + IN PSTR ModuleName, + IN DWORD64 BaseOfDll, + IN DWORD SizeOfDll + ); + +#define SLMFLAG_VIRTUAL 0x1 + +DWORD64 +IMAGEAPI +SymLoadModuleEx( + IN HANDLE hProcess, + IN HANDLE hFile, + IN PSTR ImageName, + IN PSTR ModuleName, + IN DWORD64 BaseOfDll, + IN DWORD DllSize, + IN PMODLOAD_DATA Data, + IN DWORD Flags + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymLoadModule SymLoadModule64 +#else +DWORD +IMAGEAPI +SymLoadModule( + IN HANDLE hProcess, + IN HANDLE hFile, + IN PSTR ImageName, + IN PSTR ModuleName, + IN DWORD BaseOfDll, + IN DWORD SizeOfDll + ); +#endif + +BOOL +IMAGEAPI +SymUnloadModule64( + IN HANDLE hProcess, + IN DWORD64 BaseOfDll + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymUnloadModule SymUnloadModule64 +#else +BOOL +IMAGEAPI +SymUnloadModule( + IN HANDLE hProcess, + IN DWORD BaseOfDll + ); +#endif + +BOOL +IMAGEAPI +SymUnDName64( + IN PIMAGEHLP_SYMBOL64 sym, // Symbol to undecorate + OUT PSTR UnDecName, // Buffer to store undecorated name in + IN DWORD UnDecNameLength // Size of the buffer + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymUnDName SymUnDName64 +#else +BOOL +IMAGEAPI +SymUnDName( + IN PIMAGEHLP_SYMBOL sym, // Symbol to undecorate + OUT PSTR UnDecName, // Buffer to store undecorated name in + IN DWORD UnDecNameLength // Size of the buffer + ); +#endif + +BOOL +IMAGEAPI +SymRegisterCallback64( + IN HANDLE hProcess, + IN PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, + IN ULONG64 UserContext + ); + +BOOL +IMAGEAPI +SymRegisterFunctionEntryCallback64( + IN HANDLE hProcess, + IN PSYMBOL_FUNCENTRY_CALLBACK64 CallbackFunction, + IN ULONG64 UserContext + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymRegisterCallback SymRegisterCallback64 +#define SymRegisterFunctionEntryCallback SymRegisterFunctionEntryCallback64 +#else +BOOL +IMAGEAPI +SymRegisterCallback( + IN HANDLE hProcess, + IN PSYMBOL_REGISTERED_CALLBACK CallbackFunction, + IN PVOID UserContext + ); + +BOOL +IMAGEAPI +SymRegisterFunctionEntryCallback( + IN HANDLE hProcess, + IN PSYMBOL_FUNCENTRY_CALLBACK CallbackFunction, + IN PVOID UserContext + ); +#endif + + +typedef struct _IMAGEHLP_SYMBOL_SRC { + DWORD sizeofstruct; + DWORD type; + char file[MAX_PATH]; +} IMAGEHLP_SYMBOL_SRC, *PIMAGEHLP_SYMBOL_SRC; + +typedef struct _MODULE_TYPE_INFO { // AKA TYPTYP + USHORT dataLength; + USHORT leaf; + BYTE data[1]; +} MODULE_TYPE_INFO, *PMODULE_TYPE_INFO; + +#define IMAGEHLP_SYMBOL_INFO_VALUEPRESENT 1 +#define IMAGEHLP_SYMBOL_INFO_REGISTER SYMF_REGISTER // 0x0008 +#define IMAGEHLP_SYMBOL_INFO_REGRELATIVE SYMF_REGREL // 0x0010 +#define IMAGEHLP_SYMBOL_INFO_FRAMERELATIVE SYMF_FRAMEREL // 0x0020 +#define IMAGEHLP_SYMBOL_INFO_PARAMETER SYMF_PARAMETER // 0x0040 +#define IMAGEHLP_SYMBOL_INFO_LOCAL SYMF_LOCAL // 0x0080 +#define IMAGEHLP_SYMBOL_INFO_CONSTANT SYMF_CONSTANT // 0x0100 +#define IMAGEHLP_SYMBOL_FUNCTION SYMF_FUNCTION // 0x0800 +#define IMAGEHLP_SYMBOL_VIRTUAL SYMF_VIRTUAL // 0x1000 + +typedef struct _SYMBOL_INFO { + ULONG SizeOfStruct; + ULONG TypeIndex; // Type Index of symbol + ULONG64 Reserved[2]; + ULONG Reserved2; + ULONG Size; + ULONG64 ModBase; // Base Address of module comtaining this symbol + ULONG Flags; + ULONG64 Value; // Value of symbol, ValuePresent should be 1 + ULONG64 Address; // Address of symbol including base address of module + ULONG Register; // register holding value or pointer to value + ULONG Scope; // scope of the symbol + ULONG Tag; // pdb classification + ULONG NameLen; // Actual length of name + ULONG MaxNameLen; + CHAR Name[1]; // Name of symbol +} SYMBOL_INFO, *PSYMBOL_INFO; + +typedef struct _IMAGEHLP_STACK_FRAME +{ + ULONG64 InstructionOffset; + ULONG64 ReturnOffset; + ULONG64 FrameOffset; + ULONG64 StackOffset; + ULONG64 BackingStoreOffset; + ULONG64 FuncTableEntry; + ULONG64 Params[4]; + ULONG64 Reserved[5]; + BOOL Virtual; + ULONG Reserved2; +} IMAGEHLP_STACK_FRAME, *PIMAGEHLP_STACK_FRAME; + +typedef VOID IMAGEHLP_CONTEXT, *PIMAGEHLP_CONTEXT; + + +ULONG +IMAGEAPI +SymSetContext( + HANDLE hProcess, + PIMAGEHLP_STACK_FRAME StackFrame, + PIMAGEHLP_CONTEXT Context + ); + +BOOL +IMAGEAPI +SymFromAddr( + IN HANDLE hProcess, + IN DWORD64 Address, + OUT PDWORD64 Displacement, + IN OUT PSYMBOL_INFO Symbol + ); + +// While SymFromName will provide a symbol from a name, +// SymEnumSymbols can provide the same matching information +// for ALL symbols with a matching name, even regular +// expressions. That way you can search across modules +// and differentiate between identically named symbols. + +BOOL +IMAGEAPI +SymFromName( + IN HANDLE hProcess, + IN LPSTR Name, + OUT PSYMBOL_INFO Symbol + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACK)( + PSYMBOL_INFO pSymInfo, + ULONG SymbolSize, + PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumSymbols( + IN HANDLE hProcess, + IN ULONG64 BaseOfDll, + IN PCSTR Mask, + IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + IN PVOID UserContext + ); + +typedef enum _IMAGEHLP_SYMBOL_TYPE_INFO { + TI_GET_SYMTAG, + TI_GET_SYMNAME, + TI_GET_LENGTH, + TI_GET_TYPE, + TI_GET_TYPEID, + TI_GET_BASETYPE, + TI_GET_ARRAYINDEXTYPEID, + TI_FINDCHILDREN, + TI_GET_DATAKIND, + TI_GET_ADDRESSOFFSET, + TI_GET_OFFSET, + TI_GET_VALUE, + TI_GET_COUNT, + TI_GET_CHILDRENCOUNT, + TI_GET_BITPOSITION, + TI_GET_VIRTUALBASECLASS, + TI_GET_VIRTUALTABLESHAPEID, + TI_GET_VIRTUALBASEPOINTEROFFSET, + TI_GET_CLASSPARENTID, + TI_GET_NESTED, + TI_GET_SYMINDEX, + TI_GET_LEXICALPARENT, + TI_GET_ADDRESS, + TI_GET_THISADJUST, +} IMAGEHLP_SYMBOL_TYPE_INFO; + +typedef struct _TI_FINDCHILDREN_PARAMS { + ULONG Count; + ULONG Start; + ULONG ChildId[1]; +} TI_FINDCHILDREN_PARAMS; + +BOOL +IMAGEAPI +SymGetTypeInfo( + IN HANDLE hProcess, + IN DWORD64 ModBase, + IN ULONG TypeId, + IN IMAGEHLP_SYMBOL_TYPE_INFO GetType, + OUT PVOID pInfo + ); + +BOOL +IMAGEAPI +SymEnumTypes( + IN HANDLE hProcess, + IN ULONG64 BaseOfDll, + IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + IN PVOID UserContext + ); + +BOOL +IMAGEAPI +SymGetTypeFromName( + IN HANDLE hProcess, + IN ULONG64 BaseOfDll, + IN LPSTR Name, + OUT PSYMBOL_INFO Symbol + ); + +BOOL +IMAGEAPI +SymAddSymbol( + IN HANDLE hProcess, + IN ULONG64 BaseOfDll, + IN PCSTR Name, + IN DWORD64 Address, + IN DWORD Size, + IN DWORD Flags + ); + +BOOL +IMAGEAPI +SymDeleteSymbol( + IN HANDLE hProcess, + IN ULONG64 BaseOfDll, + IN PCSTR Name, + IN DWORD64 Address, + IN DWORD Flags + ); + +// +// Full user-mode dump creation. +// + +typedef BOOL (WINAPI *PDBGHELP_CREATE_USER_DUMP_CALLBACK)( + DWORD DataType, + PVOID* Data, + LPDWORD DataLength, + PVOID UserData + ); + +BOOL +WINAPI +DbgHelpCreateUserDump( + IN LPSTR FileName, + IN PDBGHELP_CREATE_USER_DUMP_CALLBACK Callback, + IN PVOID UserData + ); + +BOOL +WINAPI +DbgHelpCreateUserDumpW( + IN LPWSTR FileName, + IN PDBGHELP_CREATE_USER_DUMP_CALLBACK Callback, + IN PVOID UserData + ); + +// ----------------------------------------------------------------- +// The following 4 legacy APIs are fully supported, but newer +// ones are recommended. SymFromName and SymFromAddr provide +// much more detailed info on the returned symbol. + +BOOL +IMAGEAPI +SymGetSymFromAddr64( + IN HANDLE hProcess, + IN DWORD64 qwAddr, + OUT PDWORD64 pdwDisplacement, + OUT PIMAGEHLP_SYMBOL64 Symbol + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetSymFromAddr SymGetSymFromAddr64 +#else +BOOL +IMAGEAPI +SymGetSymFromAddr( + IN HANDLE hProcess, + IN DWORD dwAddr, + OUT PDWORD pdwDisplacement, + OUT PIMAGEHLP_SYMBOL Symbol + ); +#endif + +// While following two APIs will provide a symbol from a name, +// SymEnumSymbols can provide the same matching information +// for ALL symbols with a matching name, even regular +// expressions. That way you can search across modules +// and differentiate between identically named symbols. + +BOOL +IMAGEAPI +SymGetSymFromName64( + IN HANDLE hProcess, + IN PSTR Name, + OUT PIMAGEHLP_SYMBOL64 Symbol + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetSymFromName SymGetSymFromName64 +#else +BOOL +IMAGEAPI +SymGetSymFromName( + IN HANDLE hProcess, + IN PSTR Name, + OUT PIMAGEHLP_SYMBOL Symbol + ); +#endif + + +// ----------------------------------------------------------------- +// The following APIs exist only for backwards compatibility +// with a pre-release version documented in an MSDN release. + +// You should use SymFindFileInPath if you want to maintain +// future compatibility. + +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +FindFileInPath( + HANDLE hprocess, + LPSTR SearchPath, + LPSTR FileName, + PVOID id, + DWORD two, + DWORD three, + DWORD flags, + LPSTR FilePath + ); + +// You should use SymFindFileInPath if you want to maintain +// future compatibility. + +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +FindFileInSearchPath( + HANDLE hprocess, + LPSTR SearchPath, + LPSTR FileName, + DWORD one, + DWORD two, + DWORD three, + LPSTR FilePath + ); + +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +SymEnumSym( + IN HANDLE hProcess, + IN ULONG64 BaseOfDll, + IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + IN PVOID UserContext + ); + + +#include + +#pragma warning(disable:4200) // Zero length array + + +#define MINIDUMP_SIGNATURE ('PMDM') +#define MINIDUMP_VERSION (42899) +typedef DWORD RVA; +typedef ULONG64 RVA64; + +typedef struct _MINIDUMP_LOCATION_DESCRIPTOR { + ULONG32 DataSize; + RVA Rva; +} MINIDUMP_LOCATION_DESCRIPTOR; + +typedef struct _MINIDUMP_LOCATION_DESCRIPTOR64 { + ULONG64 DataSize; + RVA64 Rva; +} MINIDUMP_LOCATION_DESCRIPTOR64; + + +typedef struct _MINIDUMP_MEMORY_DESCRIPTOR { + ULONG64 StartOfMemoryRange; + MINIDUMP_LOCATION_DESCRIPTOR Memory; +} MINIDUMP_MEMORY_DESCRIPTOR, *PMINIDUMP_MEMORY_DESCRIPTOR; + +// DESCRIPTOR64 is used for full-memory minidumps where +// all of the raw memory is laid out sequentially at the +// end of the dump. There is no need for individual RVAs +// as the RVA is the base RVA plus the sum of the preceeding +// data blocks. +typedef struct _MINIDUMP_MEMORY_DESCRIPTOR64 { + ULONG64 StartOfMemoryRange; + ULONG64 DataSize; +} MINIDUMP_MEMORY_DESCRIPTOR64, *PMINIDUMP_MEMORY_DESCRIPTOR64; + + +typedef struct _MINIDUMP_HEADER { + ULONG32 Signature; + ULONG32 Version; + ULONG32 NumberOfStreams; + RVA StreamDirectoryRva; + ULONG32 CheckSum; + union { + ULONG32 Reserved; + ULONG32 TimeDateStamp; + }; + ULONG64 Flags; +} MINIDUMP_HEADER, *PMINIDUMP_HEADER; + +// +// The MINIDUMP_HEADER field StreamDirectoryRva points to +// an array of MINIDUMP_DIRECTORY structures. +// + +typedef struct _MINIDUMP_DIRECTORY { + ULONG32 StreamType; + MINIDUMP_LOCATION_DESCRIPTOR Location; +} MINIDUMP_DIRECTORY, *PMINIDUMP_DIRECTORY; + + +typedef struct _MINIDUMP_STRING { + ULONG32 Length; // Length in bytes of the string + WCHAR Buffer [0]; // Variable size buffer +} MINIDUMP_STRING, *PMINIDUMP_STRING; + + + +// +// The MINIDUMP_DIRECTORY field StreamType may be one of the following types. +// Types will be added in the future, so if a program reading the minidump +// header encounters a stream type it does not understand it should ignore +// the data altogether. Any tag above LastReservedStream will not be used by +// the system and is reserved for program-specific information. +// + +typedef enum _MINIDUMP_STREAM_TYPE { + + UnusedStream = 0, + ReservedStream0 = 1, + ReservedStream1 = 2, + ThreadListStream = 3, + ModuleListStream = 4, + MemoryListStream = 5, + ExceptionStream = 6, + SystemInfoStream = 7, + ThreadExListStream = 8, + Memory64ListStream = 9, + CommentStreamA = 10, + CommentStreamW = 11, + HandleDataStream = 12, + FunctionTableStream = 13, + + LastReservedStream = 0xffff + +} MINIDUMP_STREAM_TYPE; + + +// +// The minidump system information contains processor and +// Operating System specific information. +// + +typedef struct _MINIDUMP_SYSTEM_INFO { + + // + // ProcessorArchitecture, ProcessorLevel and ProcessorRevision are all + // taken from the SYSTEM_INFO structure obtained by GetSystemInfo( ). + // + + USHORT ProcessorArchitecture; + USHORT ProcessorLevel; + USHORT ProcessorRevision; + + USHORT Reserved0; // Reserved for future use. Must be zero. + + // + // MajorVersion, MinorVersion, BuildNumber, PlatformId and + // CSDVersion are all taken from the OSVERSIONINFO structure + // returned by GetVersionEx( ). + // + + ULONG32 MajorVersion; + ULONG32 MinorVersion; + ULONG32 BuildNumber; + ULONG32 PlatformId; + + // + // RVA to a CSDVersion string in the string table. + // + + RVA CSDVersionRva; + + ULONG32 Reserved1; // Reserved for future use. + + // + // CPU information is obtained from one of two places. + // + // 1) On x86 computers, CPU_INFORMATION is obtained from the CPUID + // instruction. You must use the X86 portion of the union for X86 + // computers. + // + // 2) On non-x86 architectures, CPU_INFORMATION is obtained by calling + // IsProcessorFeatureSupported(). + // + + union _CPU_INFORMATION { + + // + // X86 platforms use CPUID function to obtain processor information. + // + + struct { + + // + // CPUID Subfunction 0, register EAX (VendorId [0]), + // EBX (VendorId [1]) and ECX (VendorId [2]). + // + + ULONG32 VendorId [ 3 ]; + + // + // CPUID Subfunction 1, register EAX + // + + ULONG32 VersionInformation; + + // + // CPUID Subfunction 1, register EDX + // + + ULONG32 FeatureInformation; + + + // + // CPUID, Subfunction 80000001, register EBX. This will only + // be obtained if the vendor id is "AuthenticAMD". + // + + ULONG32 AMDExtendedCpuFeatures; + + } X86CpuInfo; + + // + // Non-x86 platforms use processor feature flags. + // + + struct { + + ULONG64 ProcessorFeatures [ 2 ]; + + } OtherCpuInfo; + + } Cpu; + +} MINIDUMP_SYSTEM_INFO, *PMINIDUMP_SYSTEM_INFO; + +typedef union _CPU_INFORMATION CPU_INFORMATION, *PCPU_INFORMATION; + + +// +// The minidump thread contains standard thread +// information plus an RVA to the memory for this +// thread and an RVA to the CONTEXT structure for +// this thread. +// + + +// +// ThreadId must be 4 bytes on all architectures. +// + +C_ASSERT (sizeof ( ((PPROCESS_INFORMATION)0)->dwThreadId ) == 4); + +typedef struct _MINIDUMP_THREAD { + ULONG32 ThreadId; + ULONG32 SuspendCount; + ULONG32 PriorityClass; + ULONG32 Priority; + ULONG64 Teb; + MINIDUMP_MEMORY_DESCRIPTOR Stack; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; +} MINIDUMP_THREAD, *PMINIDUMP_THREAD; + +// +// The thread list is a container of threads. +// + +typedef struct _MINIDUMP_THREAD_LIST { + ULONG32 NumberOfThreads; + MINIDUMP_THREAD Threads [0]; +} MINIDUMP_THREAD_LIST, *PMINIDUMP_THREAD_LIST; + + +typedef struct _MINIDUMP_THREAD_EX { + ULONG32 ThreadId; + ULONG32 SuspendCount; + ULONG32 PriorityClass; + ULONG32 Priority; + ULONG64 Teb; + MINIDUMP_MEMORY_DESCRIPTOR Stack; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; + MINIDUMP_MEMORY_DESCRIPTOR BackingStore; +} MINIDUMP_THREAD_EX, *PMINIDUMP_THREAD_EX; + +// +// The thread list is a container of threads. +// + +typedef struct _MINIDUMP_THREAD_EX_LIST { + ULONG32 NumberOfThreads; + MINIDUMP_THREAD_EX Threads [0]; +} MINIDUMP_THREAD_EX_LIST, *PMINIDUMP_THREAD_EX_LIST; + + +// +// The MINIDUMP_EXCEPTION is the same as EXCEPTION on Win64. +// + +typedef struct _MINIDUMP_EXCEPTION { + ULONG32 ExceptionCode; + ULONG32 ExceptionFlags; + ULONG64 ExceptionRecord; + ULONG64 ExceptionAddress; + ULONG32 NumberParameters; + ULONG32 __unusedAlignment; + ULONG64 ExceptionInformation [ EXCEPTION_MAXIMUM_PARAMETERS ]; +} MINIDUMP_EXCEPTION, *PMINIDUMP_EXCEPTION; + + +// +// The exception information stream contains the id of the thread that caused +// the exception (ThreadId), the exception record for the exception +// (ExceptionRecord) and an RVA to the thread context where the exception +// occured. +// + +typedef struct MINIDUMP_EXCEPTION_STREAM { + ULONG32 ThreadId; + ULONG32 __alignment; + MINIDUMP_EXCEPTION ExceptionRecord; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; +} MINIDUMP_EXCEPTION_STREAM, *PMINIDUMP_EXCEPTION_STREAM; + + +// +// The MINIDUMP_MODULE contains information about a +// a specific module. It includes the CheckSum and +// the TimeDateStamp for the module so the module +// can be reloaded during the analysis phase. +// + +typedef struct _MINIDUMP_MODULE { + ULONG64 BaseOfImage; + ULONG32 SizeOfImage; + ULONG32 CheckSum; + ULONG32 TimeDateStamp; + RVA ModuleNameRva; + VS_FIXEDFILEINFO VersionInfo; + MINIDUMP_LOCATION_DESCRIPTOR CvRecord; + MINIDUMP_LOCATION_DESCRIPTOR MiscRecord; + ULONG64 Reserved0; // Reserved for future use. + ULONG64 Reserved1; // Reserved for future use. +} MINIDUMP_MODULE, *PMINIDUMP_MODULE; + + +// +// The minidump module list is a container for modules. +// + +typedef struct _MINIDUMP_MODULE_LIST { + ULONG32 NumberOfModules; + MINIDUMP_MODULE Modules [ 0 ]; +} MINIDUMP_MODULE_LIST, *PMINIDUMP_MODULE_LIST; + + +// +// Memory Ranges +// + +typedef struct _MINIDUMP_MEMORY_LIST { + ULONG32 NumberOfMemoryRanges; + MINIDUMP_MEMORY_DESCRIPTOR MemoryRanges [0]; +} MINIDUMP_MEMORY_LIST, *PMINIDUMP_MEMORY_LIST; + +typedef struct _MINIDUMP_MEMORY64_LIST { + ULONG64 NumberOfMemoryRanges; + RVA64 BaseRva; + MINIDUMP_MEMORY_DESCRIPTOR64 MemoryRanges [0]; +} MINIDUMP_MEMORY64_LIST, *PMINIDUMP_MEMORY64_LIST; + + +// +// Support for user supplied exception information. +// + +typedef struct _MINIDUMP_EXCEPTION_INFORMATION { + DWORD ThreadId; + PEXCEPTION_POINTERS ExceptionPointers; + BOOL ClientPointers; +} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION; + + +// +// Support for capturing system handle state at the time of the dump. +// + +typedef struct _MINIDUMP_HANDLE_DESCRIPTOR { + ULONG64 Handle; + RVA TypeNameRva; + RVA ObjectNameRva; + ULONG32 Attributes; + ULONG32 GrantedAccess; + ULONG32 HandleCount; + ULONG32 PointerCount; +} MINIDUMP_HANDLE_DESCRIPTOR, *PMINIDUMP_HANDLE_DESCRIPTOR; + +typedef struct _MINIDUMP_HANDLE_DATA_STREAM { + ULONG32 SizeOfHeader; + ULONG32 SizeOfDescriptor; + ULONG32 NumberOfDescriptors; + ULONG32 Reserved; +} MINIDUMP_HANDLE_DATA_STREAM, *PMINIDUMP_HANDLE_DATA_STREAM; + + +// +// Support for capturing dynamic function table state at the time of the dump. +// + +typedef struct _MINIDUMP_FUNCTION_TABLE_DESCRIPTOR { + ULONG64 MinimumAddress; + ULONG64 MaximumAddress; + ULONG64 BaseAddress; + ULONG32 EntryCount; + ULONG32 SizeOfAlignPad; +} MINIDUMP_FUNCTION_TABLE_DESCRIPTOR, *PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR; + +typedef struct _MINIDUMP_FUNCTION_TABLE_STREAM { + ULONG32 SizeOfHeader; + ULONG32 SizeOfDescriptor; + ULONG32 SizeOfNativeDescriptor; + ULONG32 SizeOfFunctionEntry; + ULONG32 NumberOfDescriptors; + ULONG32 SizeOfAlignPad; +} MINIDUMP_FUNCTION_TABLE_STREAM, *PMINIDUMP_FUNCTION_TABLE_STREAM; + + +// +// Support for arbitrary user-defined information. +// + +typedef struct _MINIDUMP_USER_RECORD { + ULONG32 Type; + MINIDUMP_LOCATION_DESCRIPTOR Memory; +} MINIDUMP_USER_RECORD, *PMINIDUMP_USER_RECORD; + + +typedef struct _MINIDUMP_USER_STREAM { + ULONG32 Type; + ULONG BufferSize; + PVOID Buffer; + +} MINIDUMP_USER_STREAM, *PMINIDUMP_USER_STREAM; + + +typedef struct _MINIDUMP_USER_STREAM_INFORMATION { + ULONG UserStreamCount; + PMINIDUMP_USER_STREAM UserStreamArray; +} MINIDUMP_USER_STREAM_INFORMATION, *PMINIDUMP_USER_STREAM_INFORMATION; + +// +// Callback support. +// + +typedef enum _MINIDUMP_CALLBACK_TYPE { + ModuleCallback, + ThreadCallback, + ThreadExCallback, + IncludeThreadCallback, + IncludeModuleCallback, +} MINIDUMP_CALLBACK_TYPE; + + +typedef struct _MINIDUMP_THREAD_CALLBACK { + ULONG ThreadId; + HANDLE ThreadHandle; + CONTEXT Context; + ULONG SizeOfContext; + ULONG64 StackBase; + ULONG64 StackEnd; +} MINIDUMP_THREAD_CALLBACK, *PMINIDUMP_THREAD_CALLBACK; + + +typedef struct _MINIDUMP_THREAD_EX_CALLBACK { + ULONG ThreadId; + HANDLE ThreadHandle; + CONTEXT Context; + ULONG SizeOfContext; + ULONG64 StackBase; + ULONG64 StackEnd; + ULONG64 BackingStoreBase; + ULONG64 BackingStoreEnd; +} MINIDUMP_THREAD_EX_CALLBACK, *PMINIDUMP_THREAD_EX_CALLBACK; + + +typedef struct _MINIDUMP_INCLUDE_THREAD_CALLBACK { + ULONG ThreadId; +} MINIDUMP_INCLUDE_THREAD_CALLBACK, *PMINIDUMP_INCLUDE_THREAD_CALLBACK; + + +typedef enum _THREAD_WRITE_FLAGS { + ThreadWriteThread = 0x0001, + ThreadWriteStack = 0x0002, + ThreadWriteContext = 0x0004, + ThreadWriteBackingStore = 0x0008, + ThreadWriteInstructionWindow = 0x0010 +} THREAD_WRITE_FLAGS; + +typedef struct _MINIDUMP_MODULE_CALLBACK { + PWCHAR FullPath; + ULONG64 BaseOfImage; + ULONG SizeOfImage; + ULONG CheckSum; + ULONG TimeDateStamp; + VS_FIXEDFILEINFO VersionInfo; + PVOID CvRecord; + ULONG SizeOfCvRecord; + PVOID MiscRecord; + ULONG SizeOfMiscRecord; +} MINIDUMP_MODULE_CALLBACK, *PMINIDUMP_MODULE_CALLBACK; + + +typedef struct _MINIDUMP_INCLUDE_MODULE_CALLBACK { + ULONG64 BaseOfImage; +} MINIDUMP_INCLUDE_MODULE_CALLBACK, *PMINIDUMP_INCLUDE_MODULE_CALLBACK; + + +typedef enum _MODULE_WRITE_FLAGS { + ModuleWriteModule = 0x0001, + ModuleWriteDataSeg = 0x0002, + ModuleWriteMiscRecord = 0x0004, + ModuleWriteCvRecord = 0x0008, + ModuleReferencedByMemory = 0x0010 +} MODULE_WRITE_FLAGS; + + +typedef struct _MINIDUMP_CALLBACK_INPUT { + ULONG ProcessId; + HANDLE ProcessHandle; + ULONG CallbackType; + union { + MINIDUMP_THREAD_CALLBACK Thread; + MINIDUMP_THREAD_EX_CALLBACK ThreadEx; + MINIDUMP_MODULE_CALLBACK Module; + MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; + MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; + }; +} MINIDUMP_CALLBACK_INPUT, *PMINIDUMP_CALLBACK_INPUT; + +typedef struct _MINIDUMP_CALLBACK_OUTPUT { + union { + ULONG ModuleWriteFlags; + ULONG ThreadWriteFlags; + }; +} MINIDUMP_CALLBACK_OUTPUT, *PMINIDUMP_CALLBACK_OUTPUT; + + +// +// A normal minidump contains just the information +// necessary to capture stack traces for all of the +// existing threads in a process. +// +// A minidump with data segments includes all of the data +// sections from loaded modules in order to capture +// global variable contents. This can make the dump much +// larger if many modules have global data. +// +// A minidump with full memory includes all of the accessible +// memory in the process and can be very large. A minidump +// with full memory always has the raw memory data at the end +// of the dump so that the initial structures in the dump can +// be mapped directly without having to include the raw +// memory information. +// +// Stack and backing store memory can be filtered to remove +// data unnecessary for stack walking. This can improve +// compression of stacks and also deletes data that may +// be private and should not be stored in a dump. +// Memory can also be scanned to see what modules are +// referenced by stack and backing store memory to allow +// omission of other modules to reduce dump size. +// In either of these modes the ModuleReferencedByMemory flag +// is set for all modules referenced before the base +// module callbacks occur. +// + +typedef enum _MINIDUMP_TYPE { + MiniDumpNormal = 0x0000, + MiniDumpWithDataSegs = 0x0001, + MiniDumpWithFullMemory = 0x0002, + MiniDumpWithHandleData = 0x0004, + MiniDumpFilterMemory = 0x0008, + MiniDumpScanMemory = 0x0010, +} MINIDUMP_TYPE; + + +// +// The minidump callback should modify the FieldsToWrite parameter to reflect +// what portions of the specified thread or module should be written to the +// file. +// + +typedef +BOOL +(WINAPI * MINIDUMP_CALLBACK_ROUTINE) ( + IN PVOID CallbackParam, + IN CONST PMINIDUMP_CALLBACK_INPUT CallbackInput, + IN OUT PMINIDUMP_CALLBACK_OUTPUT CallbackOutput + ); + +typedef struct _MINIDUMP_CALLBACK_INFORMATION { + MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; + PVOID CallbackParam; +} MINIDUMP_CALLBACK_INFORMATION, *PMINIDUMP_CALLBACK_INFORMATION; + + + +//++ +// +// PVOID +// RVA_TO_ADDR( +// PVOID Mapping, +// ULONG Rva +// ) +// +// Routine Description: +// +// Map an RVA that is contained within a mapped file to it's associated +// flat address. +// +// Arguments: +// +// Mapping - Base address of mapped file containing the RVA. +// +// Rva - An Rva to fixup. +// +// Return Values: +// +// A pointer to the desired data. +// +//-- + +#define RVA_TO_ADDR(Mapping,Rva) ((PVOID)(((ULONG_PTR) (Mapping)) + (Rva))) + +BOOL +WINAPI +MiniDumpWriteDump( + IN HANDLE hProcess, + IN DWORD ProcessId, + IN HANDLE hFile, + IN MINIDUMP_TYPE DumpType, + IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL + IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL + IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL + ); + +BOOL +WINAPI +MiniDumpReadDumpStream( + IN PVOID BaseOfDump, + IN ULONG StreamNumber, + OUT PMINIDUMP_DIRECTORY * Dir, OPTIONAL + OUT PVOID * StreamPointer, OPTIONAL + OUT ULONG * StreamSize OPTIONAL + ); + +#include + +#ifdef __cplusplus +} +#endif + + +#endif // _DBGHELP_ diff --git a/cl_dll/aghl/irc.cpp b/cl_dll/aghl/irc.cpp new file mode 100644 index 00000000..b65cf0ed --- /dev/null +++ b/cl_dll/aghl/irc.cpp @@ -0,0 +1,603 @@ +// irc.cpp +// Made by Adi Degani - http://www.codeguru.com/network/irc.html +#include +#include +#include +#include "agglobal.h" + +#include "irc.h" + +using namespace irc; + +//////////////////////////////////////////////////////////////////// + +CIrcMessage::CIrcMessage(const char* lpszCmdLine, bool bIncoming) + : m_bIncoming(bIncoming) +{ + ParseIrcCommand(lpszCmdLine); +} + +CIrcMessage::CIrcMessage(const CIrcMessage& m) + : sCommand(m.sCommand), + parameters(m.parameters), + m_bIncoming(m.m_bIncoming) +{ + prefix.sNick = m.prefix.sNick; + prefix.sUser = m.prefix.sUser; + prefix.sHost = m.prefix.sHost; +} + +void CIrcMessage::Reset() +{ + prefix.sNick = prefix.sUser = prefix.sHost = sCommand = ""; + m_bIncoming = false; + parameters.clear(); +} + +CIrcMessage& CIrcMessage::operator = (const CIrcMessage& m) +{ + if( &m != this ) + { + sCommand = m.sCommand; + parameters = m.parameters; + prefix.sNick = m.prefix.sNick; + prefix.sUser = m.prefix.sUser; + prefix.sHost = m.prefix.sHost; + m_bIncoming = m.m_bIncoming; + } + return *this; +} + +CIrcMessage& CIrcMessage::operator = (const char* lpszCmdLine) +{ + Reset(); + ParseIrcCommand(lpszCmdLine); + return *this; +} + +void CIrcMessage::ParseIrcCommand(const char* lpszCmdLine) +{ + const char* p1 = lpszCmdLine; + const char* p2 = lpszCmdLine; + + assert(lpszCmdLine != NULL); + assert(*lpszCmdLine); + + // prefix exists ? + if( *p1 == ':' ) + { // break prefix into its components (nick!user@host) + p2 = ++p1; + while( *p2 && !strchr(" !", *p2) ) + ++p2; + prefix.sNick.assign(p1, p2 - p1); + if( *p2 != '!' ) + goto end_of_prefix; + p1 = ++p2; + while( *p2 && !strchr(" @", *p2) ) + ++p2; + prefix.sUser.assign(p1, p2 - p1); + if( *p2 != '@' ) + goto end_of_prefix; + p1 = ++p2; + while( *p2 && !isspace(*p2) ) + ++p2; + prefix.sHost.assign(p1, p2 - p1); +end_of_prefix : + while( *p2 && isspace(*p2) ) + ++p2; + p1 = p2; + } + + // get command + assert(*p1 != '\0'); + p2 = p1; + while( *p2 && !isspace(*p2) ) + ++p2; + sCommand.assign(p1, p2 - p1); + _strupr((char*)sCommand.c_str()); + while( *p2 && isspace(*p2) ) + ++p2; + p1 = p2; + + // get parameters + while( *p1 ) + { + if( *p1 == ':' ) + { + ++p1; + // seek end-of-message + while( *p2 ) + ++p2; + parameters.push_back(AgString(p1, p2 - p1)); + break; + } + else + { + // seek end of parameter + while( *p2 && !isspace(*p2) ) + ++p2; + parameters.push_back(AgString(p1, p2 - p1)); + // see next parameter + while( *p2 && isspace(*p2) ) + ++p2; + p1 = p2; + } + } // end parameters loop +} + +AgString CIrcMessage::AsString() const +{ + AgString s; + + if( prefix.sNick.length() ) + { + s += ":" + prefix.sNick; + if( prefix.sUser.length() && prefix.sHost.length() ) + s += "!" + prefix.sUser + "@" + prefix.sHost; + s += " "; + } + + s += sCommand; + + for(unsigned int i=0; i < parameters.size(); i++) + { + s += " "; + if( i == parameters.size() - 1 ) // is last parameter ? + s += ":"; + s += parameters[i]; + } + + s += endl; + + return s; +} + +//////////////////////////////////////////////////////////////////// + +CIrcSession::CIrcSession(IIrcSessionMonitor* pMonitor) + : m_hThread(NULL) +{ + InitializeCriticalSection(&m_cs); +} + +CIrcSession::~CIrcSession() +{ + Disconnect(); + DeleteCriticalSection(&m_cs); +} + +bool CIrcSession::Connect(const CIrcSessionInfo& info) +{ + assert(m_hThread==NULL && !(bool)m_socket); + + try + { + m_identServer.Start(info.sUserID.c_str()); + + if( !m_socket.Create() ) + throw "Failed to create socket!"; + + InetAddr addr(info.sServer.c_str(), (WORD)info.iPort); + if( !m_socket.Connect(addr) ) + { + m_socket.Close(); + throw "Failed to connect to host!"; + } + + m_info = info; + + // start receiving messages from host + DWORD dwThreadId = 0; + m_hThread = CreateThread(NULL, 0, ThreadProc, this, 0, &dwThreadId); + Sleep(100); + + if( info.sPassword.length() ) + m_socket.Send("PASS %s\r\n", info.sPassword.c_str()); + + m_socket.Send("NICK %s\r\n", info.sNick.c_str()); + + TCHAR szHostName[MAX_PATH]; + DWORD cbHostName = sizeof(szHostName); + GetComputerName(szHostName, &cbHostName); + + m_socket.Send("USER %s %s %s :%s\r\n", + info.sUserID.c_str(), szHostName, "server", info.sFullName.c_str()); + } + catch( const char* ) + { + Disconnect(); + } + catch( ... ) + { + Disconnect(); + } + + return (bool)m_socket; +} + +void CIrcSession::Disconnect(const char* lpszMessage) +{ + static const DWORD dwServerTimeout = 3 * 1000; + + if( !m_hThread ) + return; + + m_socket.Send("QUIT :%s\r\n", lpszMessage ? lpszMessage : "bye!"); + + if( m_hThread && WaitForSingleObject(m_hThread, dwServerTimeout) != WAIT_OBJECT_0 ) + { + m_socket.Close(); + Sleep(100); + if( m_hThread && WaitForSingleObject(m_hThread, dwServerTimeout) != WAIT_OBJECT_0 ) + { + TerminateThread(m_hThread, 1); + CloseHandle(m_hThread); + m_hThread = NULL; + m_info.Reset(); + } + } +} + +void CIrcSession::Notify(const CIrcMessage* pmsg) +{ + // forward message to monitor objects + EnterCriticalSection(&m_cs); + for(CIrcSessionMonitors::iterator it = m_monitors.begin(); + it != m_monitors.end(); + it++ + ) + { + (*it)->OnIrcMessage(pmsg); + } + LeaveCriticalSection(&m_cs); +} + +void CIrcSession::DoReceive() +{ +// CIrcIdentServer m_identServer; + char chBuf[1024*4+1]; + int cbInBuf = 0; + +// if( m_info.bIdentServer ) + //m_identServer.Start(m_info.sUserID.c_str()); + //Sleep(100); + + while( m_socket ) + { + int cbRead; + int nLinesProcessed = 0; + + cbRead = m_socket.Receive((unsigned char*)chBuf+cbInBuf, sizeof(chBuf)-cbInBuf-1); + if( cbRead <= 0 ) + break; + cbInBuf += cbRead; + chBuf[cbInBuf] = '\0'; + + char* pStart = chBuf; + while( *pStart ) + { + char* pEnd; + + // seek end-of-line + for(pEnd=pStart; *pEnd && *pEnd != '\r' && *pEnd != '\n'; ++pEnd) + ; + if( *pEnd == '\0' ) + break; // uncomplete message. stop parsing. + + ++nLinesProcessed; + + // replace end-of-line with NULLs and skip + while( *pEnd == '\r' || *pEnd == '\n' ) + *pEnd++ = '\0'; + + if( *pStart ) + { + // process single message by monitor objects + CIrcMessage msg(pStart, true); + Notify(&msg); + } + + cbInBuf -= pEnd - pStart; + assert(cbInBuf >= 0); + + pStart = pEnd; + } + + // discard processed messages + if( nLinesProcessed != 0 ) + memmove(chBuf, pStart, cbInBuf+1); + } + + if( m_socket ) + m_socket.Close(); + + if( m_info.bIdentServer ) + m_identServer.Stop(); + + // notify monitor objects that the connection has been closed + Notify(NULL); +} + +DWORD WINAPI CIrcSession::ThreadProc(LPVOID pparam) +{ + CIrcSession* pThis = (CIrcSession*)pparam; + try { pThis->DoReceive(); } catch( ... ) {} + pThis->m_info.Reset(); + CloseHandle(pThis->m_hThread); + pThis->m_hThread = NULL; + return 0; +} + +void CIrcSession::AddMonitor(IIrcSessionMonitor* pMonitor) +{ + assert(pMonitor != NULL); + EnterCriticalSection(&m_cs); + m_monitors.insert(pMonitor); + LeaveCriticalSection(&m_cs); +} + +void CIrcSession::RemoveMonitor(IIrcSessionMonitor* pMonitor) +{ + assert(pMonitor != NULL); + EnterCriticalSection(&m_cs); + m_monitors.erase(pMonitor); + LeaveCriticalSection(&m_cs); +} + +//////////////////////////////////////////////////////////////////// + +CIrcSessionInfo::CIrcSessionInfo() + : iPort(0), bIdentServer(false), iIdentServerPort(0) +{ +} + +CIrcSessionInfo::CIrcSessionInfo(const CIrcSessionInfo& si) + : sServer(si.sServer), + sServerName(si.sServerName), + iPort(si.iPort), + sNick(si.sNick), + sUserID(si.sUserID), + sFullName(si.sFullName), + sPassword(si.sPassword), + bIdentServer(si.bIdentServer), + sIdentServerType(si.sIdentServerType), + iIdentServerPort(si.iIdentServerPort) +{ +} + +void CIrcSessionInfo::Reset() +{ + sServer = ""; + sServerName = ""; + iPort = 0; + sNick = ""; + sUserID = ""; + sFullName = ""; + sPassword = ""; + bIdentServer = false; + sIdentServerType = ""; + iIdentServerPort = 0; +} + +//////////////////////////////////////////////////////////////////// + +CIrcIdentServer::CIrcIdentServer() + : m_uiPort(0), m_hThread(NULL) +{ + m_hReady = CreateEvent(NULL,TRUE,FALSE,"IDENTEVENT"); +} + +CIrcIdentServer::~CIrcIdentServer() +{ + CloseHandle(m_hReady); + Stop(); +} + +bool CIrcIdentServer::Start( + const char* lpszUserID, + unsigned int uiPort, + const char* lpszResponseType + ) +{ + if( m_socket ) + return false; + + if( !m_socket.Create() ) + return false; + + if( !m_socket.Bind(InetAddr((WORD)uiPort)) ) + { + m_socket.Close(); + return false; + } + + m_sResponseType = lpszResponseType; + m_sUserID = lpszUserID; + m_uiPort = uiPort; + + DWORD dwThreadId = 0; + m_hThread = CreateThread(NULL, 0, ListenProc, this, 0, &dwThreadId); + WaitForSingleObject(m_hReady,INFINITE); + + return true; +} + +void CIrcIdentServer::Stop() +{ + if( m_hThread ) + { + m_socket.Close(); + Sleep(100); + if( WaitForSingleObject(m_hThread, 2000) != WAIT_OBJECT_0 && m_hThread ) + { + TerminateThread(m_hThread, 1); + CloseHandle(m_hThread); + m_hThread = NULL; + } + } +} + +void CIrcIdentServer::DoThread() +{ + m_socket.Listen(); + + while( (bool)m_socket ) + { + InetAddr addr; + + SetEvent(m_hReady); + Socket s = m_socket.Accept(addr); + //int iErr = WSAGetLastError(); + if( !(bool)s ) + break; + + char szBuf[1024]; + int cbRead = s.Receive((unsigned char*)szBuf, sizeof(szBuf)-1); + if( cbRead <= 0 ) + continue; + szBuf[cbRead] = '\0'; + + // strip CRLF from query + for(char* p = szBuf; *p && *p != '\r' && *p != '\n'; ++p) + ; + *p = '\0'; + + s.Send("%s : USERID : %s : %s\r\n", + szBuf, m_sResponseType.c_str(), m_sUserID.c_str()); + Sleep(500); + s.Close(); + } + + SetEvent(m_hReady); + + m_socket.Close(); +} + +DWORD WINAPI CIrcIdentServer::ListenProc(LPVOID pparam) +{ + CIrcIdentServer* pThis = (CIrcIdentServer*)pparam; + + try { pThis->DoThread(); } catch( ... ) {} + + pThis->m_sResponseType = ""; + pThis->m_sUserID = ""; + pThis->m_uiPort = 0; + + CloseHandle(pThis->m_hThread); + pThis->m_hThread = NULL; + + return 0; +} + +//////////////////////////////////////////////////////////////////// + +CIrcMonitor::HandlersMap CIrcMonitor::m_handlers; +CIrcMonitor::IrcCommandsMapsListEntry CIrcMonitor::m_handlersMapsListEntry + = { &CIrcMonitor::m_handlers, NULL }; + + +CIrcMonitor::CIrcMonitor(CIrcSession& session) + : m_session(session) +{ + m_xPost.SetMonitor(this); +} + +CIrcMonitor::~CIrcMonitor() +{ +} + +void CIrcMonitor::OnIrcMessage(const CIrcMessage* pmsg) +{ + CIrcMessage* pMsgCopy = NULL; + if( pmsg ) + pMsgCopy = new CIrcMessage(*pmsg); + m_xPost.Post(0, (LPARAM)pMsgCopy); +} + +void CIrcMonitor::OnCrossThreadsMessage(WPARAM wParam, LPARAM lParam) +{ + CIrcMessage* pmsg = (CIrcMessage*)lParam; + + OnIrcAll(pmsg); + + if( pmsg ) + { + PfnIrcMessageHandler pfn = FindMethod(pmsg->sCommand.c_str()); + if( pfn ) + { + // call member function. if it returns 'false', + // call the default handling + if( !(this->*pfn)(pmsg) ) + OnIrcDefault(pmsg); + } + else // handler not found. call default handler + OnIrcDefault(pmsg); + delete pmsg; + } + else + OnIrcDisconnected(); +} + +CIrcMonitor::PfnIrcMessageHandler CIrcMonitor::FindMethod(const char* lpszName) +{ + // call the recursive version with the most derived map + return FindMethod(GetIrcCommandsMap(), lpszName); +} + +CIrcMonitor::PfnIrcMessageHandler CIrcMonitor::FindMethod(IrcCommandsMapsListEntry* pMapsList, const char* lpszName) +{ + HandlersMap::iterator it = pMapsList->pHandlersMap->find(lpszName); + if( it != pMapsList->pHandlersMap->end() ) + return (*it).second; // found ! + else if( pMapsList->pBaseHandlersMap ) + return FindMethod(pMapsList->pBaseHandlersMap, lpszName); // try at base class + return NULL; // not found in any map +} + +//////////////////////////////////////////////////////////////////// + +DECLARE_IRC_MAP(CIrcDefaultMonitor, CIrcMonitor) + +CIrcDefaultMonitor::CIrcDefaultMonitor(CIrcSession& session) + : CIrcMonitor(session) +{ + IRC_MAP_ENTRY(CIrcDefaultMonitor, "NICK", OnIrc_NICK) + IRC_MAP_ENTRY(CIrcDefaultMonitor, "PING", OnIrc_PING) + IRC_MAP_ENTRY(CIrcDefaultMonitor, "002", OnIrc_YOURHOST) + IRC_MAP_ENTRY(CIrcDefaultMonitor, "005", OnIrc_BOUNCE) +} + +bool CIrcDefaultMonitor::OnIrc_NICK(const CIrcMessage* pmsg) +{ + if( (m_session.GetInfo().sNick == pmsg->prefix.sNick) && (pmsg->parameters.size() > 0) ) + m_session.m_info.sNick = pmsg->parameters[0]; + return false; +} + +bool CIrcDefaultMonitor::OnIrc_PING(const CIrcMessage* pmsg) +{ + char szResponse[100]; + sprintf(szResponse, "PONG %s", pmsg->parameters[0].c_str()); + m_session << CIrcMessage(szResponse); + return false; +} + +bool CIrcDefaultMonitor::OnIrc_YOURHOST(const CIrcMessage* pmsg) +{ + static const char* lpszFmt = "Your host is %[^ \x5b,], running version %s"; + char szHostName[100], szVersion[100]; + if( sscanf(pmsg->parameters[1].c_str(), lpszFmt, &szHostName, &szVersion) > 0 ) + m_session.m_info.sServerName = szHostName; + return false; +} + +bool CIrcDefaultMonitor::OnIrc_BOUNCE(const CIrcMessage* pmsg) +{ + static const char* lpszFmt = "Try server %[^ ,], port %d"; + char szAltServer[100]; + int iAltPort = 0; + if( sscanf(pmsg->parameters[1].c_str(), lpszFmt, &szAltServer, &iAltPort) == 2 ) + { + } + return false; +} diff --git a/cl_dll/aghl/irc.h b/cl_dll/aghl/irc.h new file mode 100644 index 00000000..562dbf3b --- /dev/null +++ b/cl_dll/aghl/irc.h @@ -0,0 +1,257 @@ +// irc.h + +#ifndef _IRC_H_ +#define _IRC_H_ + +/* + IRC (RFC #1459) Client Implementation +*/ + +#pragma warning (disable: 4786) + +#include "socket.h" +#include "CrossThreadsMessagingDevice.h" + +//////////////////////////////////////////////////////////////////// +namespace irc { +//////////////////////////////////////////////////////////////////// + +static const char* endl = "\r\n"; + +// RFC's Identity Server (RFC #1413) +class CIrcIdentServer +{ +public : + CIrcIdentServer(); + virtual ~CIrcIdentServer(); + + bool Start( + const char* lpszUserID, + unsigned int uiPort = 113, + const char* lpszResponseType = "UNIX" + ); + void Stop(); + + HANDLE m_hReady; + +protected : + AgString m_sResponseType; + unsigned int m_uiPort; + AgString m_sUserID; + + void DoThread(); + +private : + Socket m_socket; + HANDLE m_hThread; + + static DWORD WINAPI ListenProc(LPVOID pparam); +}; + + +//////////////////////////////////////////////////////////////////// + +class CIrcMessage +{ +public : + struct Prefix + { + AgString sNick, sUser, sHost; + } prefix; + AgString sCommand; + vector parameters; + bool m_bIncoming; + + CIrcMessage() : m_bIncoming(false) {} // default constructor + CIrcMessage(const char* lpszCmdLine, bool bIncoming=false); // parser constructor + CIrcMessage(const CIrcMessage& m); // copy constructor + + void Reset(); + + CIrcMessage& operator = (const CIrcMessage& m); + CIrcMessage& operator = (const char* lpszCmdLine); + + AgString AsString() const; + +private : + void ParseIrcCommand(const char* lpszCmdLine); +}; + +//////////////////////////////////////////////////////////////////// + +struct IIrcSessionMonitor +{ + virtual void OnIrcMessage(const CIrcMessage* pmsg) = 0; +}; + +//////////////////////////////////////////////////////////////////// + +struct CIrcSessionInfo +{ + AgString sServer; + AgString sServerName; + unsigned int iPort; + AgString sNick; + AgString sUserID; + AgString sFullName; + AgString sPassword; + bool bIdentServer; + AgString sIdentServerType; + unsigned int iIdentServerPort; + + CIrcSessionInfo(); + CIrcSessionInfo(const CIrcSessionInfo& si); + + void Reset(); +}; + +//////////////////////////////////////////////////////////////////// + +class CIrcDefaultMonitor; // foreward + +class CIrcSession +{ +public : + friend class CIrcDefaultMonitor; + + CIrcSession(IIrcSessionMonitor* pMonitor = NULL); + virtual ~CIrcSession(); + + void AddMonitor(IIrcSessionMonitor* pMonitor); + void RemoveMonitor(IIrcSessionMonitor* pMonitor); + + bool Connect(const CIrcSessionInfo& info); + void Disconnect(const char* lpszMessage = "Bye!"); + + const CIrcSessionInfo& GetInfo() const + { return (const CIrcSessionInfo&)m_info; } + + operator bool() const { return (bool)m_socket; } + + // send-to-stream operators + friend CIrcSession& operator << (CIrcSession& os, const CIrcMessage& m); + +protected : + Socket m_socket; + CIrcSessionInfo m_info; + + void DoReceive(); + +private : + typedef set > CIrcSessionMonitors; + CIrcSessionMonitors m_monitors; + HANDLE m_hThread; + CRITICAL_SECTION m_cs; // protect m_monitors + + void Notify(const CIrcMessage* pmsg); + static DWORD WINAPI ThreadProc(LPVOID pparam); + + CIrcIdentServer m_identServer; +}; + + +__inline CIrcSession& operator << (CIrcSession& os, const CIrcMessage& m) +{ + if( os ) + { + os.m_socket.Send(m.AsString().c_str()); + os.Notify(&m); + } + return os; +} + +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// + +class CIrcMonitor : + public IIrcSessionMonitor, + private CCrossThreadsMessagingDevice::ICrossThreadsMessagingDeviceMonitor +{ +public : + typedef bool (CIrcMonitor::*PfnIrcMessageHandler)(const CIrcMessage* pmsg); + struct LessString + { + bool operator()(const char* s1, const char* s2) const + { return stricmp(s1, s2) < 0; } + }; + typedef map HandlersMap; + struct IrcCommandsMapsListEntry + { + HandlersMap* pHandlersMap; + IrcCommandsMapsListEntry* pBaseHandlersMap; + }; + + CIrcMonitor(CIrcSession& session); + virtual ~CIrcMonitor(); + + virtual void OnIrcMessage(const CIrcMessage* pmsg); + +protected : + CIrcSession& m_session; + + virtual IrcCommandsMapsListEntry* GetIrcCommandsMap() + { return &m_handlersMapsListEntry; } + + virtual void OnIrcAll(const CIrcMessage* pmsg) {} + virtual void OnIrcDefault(const CIrcMessage* pmsg) {} + virtual void OnIrcDisconnected() {} + +protected : + CCrossThreadsMessagingDevice m_xPost; + static IrcCommandsMapsListEntry m_handlersMapsListEntry; + static HandlersMap m_handlers; + + PfnIrcMessageHandler FindMethod(const char* lpszName); + PfnIrcMessageHandler FindMethod(IrcCommandsMapsListEntry* pMapsList, const char* lpszName); + + virtual void OnCrossThreadsMessage(WPARAM wParam, LPARAM lParam); +}; + +// define an IRC command-to-member map. +// put that macro inside the class definition (.H file) +#define DEFINE_IRC_MAP() \ +protected : \ + virtual IrcCommandsMapsListEntry* GetIrcCommandsMap() \ + { return &m_handlersMapsListEntry; } \ +protected : \ + static CIrcMonitor::IrcCommandsMapsListEntry m_handlersMapsListEntry; \ + static CIrcMonitor::HandlersMap m_handlers; \ +protected : + +// IRC command-to-member map's declaration. +// add this macro to the class's .CPP file +#define DECLARE_IRC_MAP(this_class, base_class) \ + CIrcMonitor::HandlersMap this_class##::m_handlers; \ + CIrcMonitor::IrcCommandsMapsListEntry this_class##::m_handlersMapsListEntry \ + = { &this_class##::m_handlers, &base_class##::m_handlersMapsListEntry }; + +// map actual member functions to their associated IRC command. +// put any number of this macro in the class's constructor. +#define IRC_MAP_ENTRY(class_name, name, member) \ + m_handlers[(name)] = (PfnIrcMessageHandler)&class_name##::member; + + +//////////////////////////////////////////////////////////////////// + +class CIrcDefaultMonitor : public CIrcMonitor +{ +public : + CIrcDefaultMonitor(CIrcSession& session); + + DEFINE_IRC_MAP() + +protected : + bool OnIrc_NICK(const CIrcMessage* pmsg); + bool OnIrc_PING(const CIrcMessage* pmsg); + bool OnIrc_YOURHOST(const CIrcMessage* pmsg); + bool OnIrc_BOUNCE(const CIrcMessage* pmsg); +}; + +//////////////////////////////////////////////////////////////////// +}; // end of namespace irc +//////////////////////////////////////////////////////////////////// + +#endif // _IRC_H_ + + diff --git a/cl_dll/aghl/socket.cpp b/cl_dll/aghl/socket.cpp new file mode 100644 index 00000000..004d66fa --- /dev/null +++ b/cl_dll/aghl/socket.cpp @@ -0,0 +1,152 @@ +// socket.cpp +// Made by Adi Degani - http://www.codeguru.com/network/irc.html + + +#include +#include +#include "socket.h" + +#define ASSERT + + +////////////////////////////////////////////////////////////////////////// + +WinsockInit::WinsockInit(WORD wVersionRequested) +{ + m_iStatus = WSAStartup(wVersionRequested, &m_wsd); +} + +WinsockInit::~WinsockInit() +{ + WSACleanup(); +} + +////////////////////////////////////////////////////////////////////////// + +InetAddr::InetAddr(WORD wPort) + { + memset(this, 0, sizeof(sockaddr_in)); + sin_family = AF_INET; + sin_addr.s_addr = htonl(INADDR_ANY); + sin_port = htons((u_short)wPort); + } + +InetAddr::InetAddr(LPCSTR lpszAddress, WORD wPort) + { + Resolve(lpszAddress, wPort); + } + +InetAddr& InetAddr::operator = (LPCSTR lpszAddress) + { + Resolve(lpszAddress); + return *this; + } + +void InetAddr::Resolve(LPCSTR lpszAddress, WORD wPort) + { + memset(this, 0, sizeof(sockaddr_in)); + sin_family = AF_INET; + sin_addr.s_addr = inet_addr((LPTSTR)lpszAddress); + if( sin_addr.s_addr == INADDR_NONE && strcmp((LPTSTR)lpszAddress, "255.255.255.255")!=0 ) + { + HOSTENT* lphost = gethostbyname((LPTSTR)lpszAddress); + if( lphost ) + sin_addr.s_addr = ((IN_ADDR*)lphost->h_addr)->s_addr; + else + sin_addr.s_addr = INADDR_ANY; + } + sin_port = htons((u_short)wPort); + } + +////////////////////////////////////////////////////////////////////////// + +Socket::Socket() + : m_sock(INVALID_SOCKET), m_bOwnSocket(false) + { + } + +Socket::Socket(const Socket& s) + : m_sock(s.m_sock), m_bOwnSocket(false) + { + } + +Socket::Socket(SOCKET s) + : m_sock(s), m_bOwnSocket(false) + { + } + +Socket::~Socket() + { + if( m_bOwnSocket && m_sock != INVALID_SOCKET ) + Close(); + } + +bool Socket::Create() + { +// _ASSERT(m_sock == INVALID_SOCKET); + m_sock = socket(AF_INET, SOCK_STREAM, 0); + return (m_bOwnSocket = (m_sock != INVALID_SOCKET)); + } + +void Socket::Close() + { +// _ASSERT(m_sock != INVALID_SOCKET); + shutdown(m_sock, 2); + closesocket(m_sock); + m_sock = INVALID_SOCKET; + } + +bool Socket::Bind(const InetAddr& addr) + { + return bind(m_sock, (const sockaddr*)&addr, sizeof(sockaddr)) != SOCKET_ERROR; + } + +bool Socket::Connect(const InetAddr& addr) + { + return connect(m_sock, (const sockaddr*)&addr, sizeof(sockaddr)) != SOCKET_ERROR; + } + +bool Socket::Listen() + { + return listen(m_sock, 5) != SOCKET_ERROR; + } + +Socket Socket::Accept(InetAddr& addr) + { + int len = sizeof(sockaddr); + return Socket(accept(m_sock, (sockaddr*)&addr, &len)); + } + +int Socket::Send(const unsigned char* buf, int cbBuf) + { + return send(m_sock, (const char*)buf, cbBuf, 0); + } + +int Socket::Send(const char* fmt, ...) + { + va_list marker; + va_start(marker, fmt); + + char szBuf[1024*4]; + vsprintf(szBuf, fmt, marker); + + va_end(marker); + + return Send((unsigned char*)szBuf, strlen(szBuf)); + } + +int Socket::Receive(unsigned char* buf, int cbBuf) + { + int n = recv(m_sock, (char*)buf, cbBuf, 0); + return n; + } + +bool Socket::SetOpt(int opt, const char* pBuf, int cbBuf) + { + return setsockopt(m_sock, SOL_SOCKET, opt, pBuf, cbBuf) != SOCKET_ERROR; + } + +bool Socket::GetOpt(int opt, char* pBuf, int& cbBuf) + { + return getsockopt(m_sock, SOL_SOCKET, opt, pBuf, &cbBuf) != SOCKET_ERROR; + } diff --git a/cl_dll/aghl/socket.h b/cl_dll/aghl/socket.h new file mode 100644 index 00000000..4c01ada7 --- /dev/null +++ b/cl_dll/aghl/socket.h @@ -0,0 +1,64 @@ +// socket.h + +#ifndef SOCKET_H +#define SOCKET_H + +#pragma comment(lib, "wsock32.lib") + +#include + + +class WinsockInit + { + public : + WSADATA m_wsd; + int m_iStatus; + + WinsockInit(WORD wVersionRequested = 0x0101); + ~WinsockInit(); + }; + + +class InetAddr : public sockaddr_in + { + public : + InetAddr(WORD wPort = 0); + InetAddr(LPCSTR lpszAddress, WORD wPort = 0); + InetAddr& operator = (LPCSTR lpszAddress); + + protected : + void Resolve(LPCSTR lpszAddress, WORD wPort = 0); + }; + + +class Socket + { + public : + Socket(); + Socket(SOCKET s); + Socket(const Socket& s); + virtual ~Socket(); + + bool Create(); + void Close(); + bool Bind(const InetAddr& addr); + bool Connect(const InetAddr& addr); + bool Listen(); + Socket Accept(InetAddr& addr); + int Send(const unsigned char* buf, int cbBuf); + int Send(const char* fmt, ...); + int Receive(unsigned char* buf, int cbBuf); + bool SetOpt(int opt, const char* pBuf, int cbBuf); + bool GetOpt(int opt, char* pBuf, int& cbBuf); + operator SOCKET& () const { return (SOCKET&)m_sock; } + operator bool() const { return m_sock != INVALID_SOCKET; } + + protected : + SOCKET m_sock; + + private : + bool m_bOwnSocket; + }; + + +#endif diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index 988bd6fa..fffe5358 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -28,6 +28,10 @@ #include "ammohistory.h" +//++ BulliT +extern cvar_t* g_phud_weapon; +//-- Martin Webrant + WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise // this points to the active weapon menu item WEAPON *gpLastSel; // Last weapon menu selection @@ -52,6 +56,11 @@ int WeaponsResource::CountAmmo( int iId ) if( iId < 0 ) return 0; +//++ BulliT + //Fixes some crashes. + if( iId > MAX_AMMO_TYPES ) + return 0; +//-- Martin Webrant return riAmmo[iId]; } @@ -911,6 +920,27 @@ int CHudAmmo::Draw( float flTime ) SPR_DrawAdditive( 0, x, y - iOffset, &m_pWeapon->rcAmmo ); } +//++ BulliT + //Draw the weaponsprite in spectator mode. + if( g_iUser1 == OBS_IN_EYE || 0 != g_phud_weapon->value ) + { + if( gWR.HasAmmo( m_pWeapon ) ) + { + ScaleColors( r, g, b, 192 ); + } + else + { + UnpackRGB( r,g,b, RGB_REDISH ); + ScaleColors( r, g, b, 128 ); + } + + SPR_Set( m_pWeapon->hInactive, r, g, b ); + x = (ScreenWidth / 1.73); //- ( ( m_pWeapon->rcInactive.right - m_pWeapon->rcInactive.left ) / 2 ); + int iOffset = ( m_pWeapon->rcInactive.bottom - m_pWeapon->rcInactive.top ) / 8; + SPR_DrawAdditive( 0, x, y - iOffset , &m_pWeapon->rcInactive ); + } +//-- Martin Webrant + // Does weapon have seconday ammo? if( pw->iAmmo2Type > 0 ) { diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 13200a89..9653d87a 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -21,6 +21,12 @@ #include "hud.h" #include "cl_util.h" #include "netadr.h" +//++ BulliT +#include "AgVariableChecker.h" +#include "AgGlobal.h" +//#include "irc.h" +#include "agwallhack.h" +//-- Martin Webrant extern "C" { @@ -30,6 +36,9 @@ extern "C" #include cl_enginefunc_t gEngfuncs; +//++ BulliT +//irc::CIrcSession g_ircSession; +//-- Martin Webrant CHud gHUD; mobile_engfuncs_t *gMobileEngfuncs = NULL; void InitInput( void ); @@ -132,7 +141,12 @@ void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ) PM_Move( ppmove, server ); } +#ifdef AG_USE_CHEATPROTECTION +void* pFromModuleAddress = 0; +int DLLEXPORT Initialize_Body( cl_enginefunc_t *pEnginefuncs, int iVersion ) +#else int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) +#endif { gEngfuncs = *pEnginefuncs; @@ -143,9 +157,26 @@ int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) EV_HookEvents(); +//++ BulliT + AgInitClientDll(); + +#ifdef AG_USE_CHEATPROTECTION + g_Wallhack.SetHLAddressToValidate( (DWORD)pFromModuleAddress ); +#endif +//-- Martin Webrant + return 1; } +#ifdef AG_USE_CHEATPROTECTION +__declspec(naked) int Initialize( cl_enginefunc_t *pEnginefuncs, int Version ) +{ + __asm pop pFromModuleAddress; + __asm push pFromModuleAddress; + __asm jmp[Initialize_Body]; +} +#endif + /* ================= HUD_GetRect @@ -196,6 +227,9 @@ void DLLEXPORT HUD_Init( void ) { InitInput(); gHUD.Init(); +#ifdef AG_USE_CHEATPROTECTION + g_VariableChecker.Activate(); +#endif //AG_USE_CHEATPROTECTION } /* @@ -256,7 +290,11 @@ Called by engine every frame that client .dll is loaded */ void DLLEXPORT HUD_Frame( double time ) -{ gEngfuncs.VGui_ViewportPaintBackground(HUD_GetRect()); +{ + gEngfuncs.VGui_ViewportPaintBackground(HUD_GetRect()); +#ifdef AG_USE_CHEATPROTECTION + g_VariableChecker.Check(); +#endif //AG_USE_CHEATPROTECTION } /* diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 84488050..8e72b56c 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -100,7 +100,31 @@ inline int TextMessageDrawChar( int x, int y, int number, int r, int g, in return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); } -inline int DrawConsoleString( int x, int y, const char *string ) +//++ BulliT +#include "agglobal.h" +inline int DrawConsoleString( int x, int y, const char *string, float r = 0, float g = 0, float b = 0 ) +//inline int DrawConsoleString( int x, int y, const char *string, float r = 0 ) +{ +//++ BulliT + if( !( r == 0 && g == 0 && b == 0 ) ) + gEngfuncs.pfnDrawSetTextColor( r, g, b ); + return AgDrawConsoleString( x, y, string, r ,g, b ); + //return gEngfuncs.pfnDrawConsoleString( x, y, (char*)string ); +} +//-- Martin Webrant + +inline void GetConsoleStringSize( const char *string, int *width, int *height ) +{ +//++ BulliT + char *pszString = strdup( string ); + AgStripColors( (char*)pszString ); + gEngfuncs.pfnDrawConsoleStringLen( pszString, width, height ); + free( pszString ); + //gEngfuncs.pfnDrawConsoleStringLen( string, width, height ); +//-- Martin Webrant +} + +/*inline int DrawConsoleString( int x, int y, const char *string ) { if( hud_textmode->value == 1 ) return gHUD.DrawHudString( x, y, 9999, (char*)string, 255 * g_hud_text_color[0], 255 * g_hud_text_color[1], 255 * g_hud_text_color[2] ); @@ -114,6 +138,7 @@ inline void GetConsoleStringSize( const char *string, int *width, int *height ) else gEngfuncs.pfnDrawConsoleStringLen( (char*)string, width, height ); } +*/ inline int ConsoleStringLen( const char *string ) { @@ -126,12 +151,24 @@ inline int ConsoleStringLen( const char *string ) inline void ConsolePrint( const char *string ) { - gEngfuncs.pfnConsolePrint( string ); +//++ BulliT + char *pszString = strdup( string ); + AgStripColors( (char*)pszString ); + gEngfuncs.pfnConsolePrint( pszString ); + free( pszString ); + //gEngfuncs.pfnConsolePrint( string ); +//-- Martin Webrant } inline void CenterPrint( const char *string ) { - gEngfuncs.pfnCenterPrint( string ); +//++ BulliT + char *pszString = strdup( string ); + AgStripColors( (char*)pszString ); + gEngfuncs.pfnCenterPrint( pszString ); + free( pszString ); + //gEngfuncs.pfnCenterPrint( string ); +//-- Martin Webrant } // returns the players name of entity no. @@ -167,6 +204,13 @@ extern vec3_t vec3_origin; inline void UnpackRGB( int &r, int &g, int &b, unsigned long ulRGB )\ {\ +//++ BulliT + if( ulRGB == RGB_YELLOWISH ) + { + AgGetHudColor( r, g, b ); + return; + } +//-- Martin Webrant r = ( ulRGB & 0xFF0000 ) >> 16;\ g = ( ulRGB & 0xFF00 ) >> 8;\ b = ulRGB & 0xFF;\ diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index 455dfd36..7a0bb61e 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -50,6 +50,10 @@ float g_ColorGreen[3] = { 0.6, 1.0, 0.6 }; float g_ColorYellow[3] = { 1.0, 0.7, 0.0 }; float g_ColorGrey[3] = { 0.8, 0.8, 0.8 }; +//++ BulliT +float g_ColorConsole[3] = { 1.0, 0.7, 0.0 }; +//-- Martin Webrant + float *GetClientColor( int clientIndex ) { switch( g_PlayerExtraInfo[clientIndex].teamnumber ) @@ -58,7 +62,10 @@ float *GetClientColor( int clientIndex ) case 2: return g_ColorRed; case 3: return g_ColorYellow; case 4: return g_ColorGreen; - case 0: return g_ColorYellow; + //case 0: return g_ColorYellow; +//++ BulliT + case 0: return g_ColorConsole; +//-- Martin Webrant default: return g_ColorGrey; } @@ -124,8 +131,12 @@ int CHudDeathNotice::Draw( float flTime ) // Draw killers name if( rgDeathNoticeList[i].KillerColor ) - DrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); - x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); +//++ BulliT + //gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); + x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller, rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); + else +//-- Martin Webrant + x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); } r = 255; g = 80; b = 0; @@ -144,8 +155,12 @@ int CHudDeathNotice::Draw( float flTime ) if( rgDeathNoticeList[i].iNonPlayerKill == FALSE ) { if( rgDeathNoticeList[i].VictimColor ) - DrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); - x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); +//++ BulliT + //gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); + x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim, rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); + else +//-- Martin Webrant + x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); } } } diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 9787a839..f4829196 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -1440,7 +1440,13 @@ void EV_EgonFire( event_args_t *args ) if( EV_IsLocal( idx ) ) gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[gEngfuncs.pfnRandomLong( 0, 3 )], 1 ); - if( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. +//++ BulliT +#define INSET_IN_EYE 2 +#define OBS_IN_EYE 4 +#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE || ( g_iUser1 && ( gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) ) ) + //if( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. + if( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value && !IS_FIRSTPERSON_SPEC ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. +//-- Martin Webrant { vec3_t vecSrc, vecEnd, angles, forward, right, up; pmtrace_t tr; diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index d4979c35..bd2b21b8 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -231,7 +231,11 @@ int CHudHealth::Draw( float flTime ) int iHeight = gHUD.m_iFontHeight; int iWidth = HealthWidth / 10; - FillRGBA( x, y, iWidth, iHeight, 255, 160, 0, a ); +//++ BulliT + //FillRGBA( x, y, iWidth, iHeight, 255, 160, 0, a ); + UnpackRGB( r, g, b, RGB_YELLOWISH ); + FillRGBA( x, y, iWidth, iHeight, r, g, b, a ); +//-- Martin Webrant } DrawDamage( flTime ); diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index 0f3b45bc..7492521d 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -170,10 +170,13 @@ void CHud::Init( void ) HOOK_MESSAGE( ValClass ); HOOK_MESSAGE( TeamNames ); - HOOK_MESSAGE( Feign ); - HOOK_MESSAGE( Detpack ); - HOOK_MESSAGE( BuildSt ); - HOOK_MESSAGE( RandomPC ); +//++ BulliT + //TFC JUNK + //HOOK_MESSAGE( Feign ); + //HOOK_MESSAGE( Detpack ); + //HOOK_MESSAGE( BuildSt ); + //HOOK_MESSAGE( RandomPC ); +//-- Martin Webrant HOOK_MESSAGE( ServerName ); HOOK_MESSAGE( Spectator ); @@ -228,8 +231,24 @@ void CHud::Init( void ) m_TextMessage.Init(); m_StatusIcons.Init(); m_MOTD.Init(); +//++ BulliT + m_Splash.Init(); + m_Countdown.Init(); + m_Timer.Init(); + m_PlayerId.Init(); + m_Settings.Init(); + m_SuddenDeath.Init(); + m_Longjump.Init(); + m_CustomTimer.Init(); + m_Timeout.Init(); + m_Global.Init(); + m_Vote.Init(); + m_Nextmap.Init(); + m_Location.Init(); + //m_IRC.Init(); + m_CTF.Init(); m_Scoreboard.Init(); - +//-- Martin Webrant m_Menu.Init(); MsgFunc_ResetHUD( 0, 0, NULL ); @@ -254,6 +273,9 @@ CHud::~CHud() } m_pHudList = NULL; } +//++ BulliT + //m_IRC.UserCmd_IRCDisconnect(); +//-- Martin Webrant } // GetSpriteIndex() @@ -396,7 +418,24 @@ void CHud::VidInit( void ) m_AmmoSecondary.VidInit(); m_TextMessage.VidInit(); m_StatusIcons.VidInit(); +//++ BulliT + m_Splash.VidInit(); + m_Countdown.VidInit(); + m_Timer.VidInit(); + m_PlayerId.VidInit(); + m_Settings.VidInit(); + m_SuddenDeath.VidInit(); + m_Longjump.VidInit(); + m_CustomTimer.VidInit(); + m_Timeout.VidInit(); + m_Global.VidInit(); + m_Vote.VidInit(); + m_Nextmap.VidInit(); + m_Location.VidInit(); + m_IRC.VidInit(); + m_CTF.VidInit(); m_Scoreboard.VidInit(); +//-- Martin Webrant m_MOTD.VidInit(); } @@ -511,9 +550,11 @@ int CHud::MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf ) int newfov = READ_BYTE(); int def_fov = CVAR_GET_FLOAT( "default_fov" ); +#ifdef CLIENT_WEAPONS //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). if( cl_lw && cl_lw->value ) return 1; +#endif g_lastFOV = newfov; diff --git a/cl_dll/hud.h b/cl_dll/hud.h index ec236003..2036f715 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -323,6 +323,9 @@ struct extra_player_info_t short playerclass; short teamnumber; char teamname[MAX_TEAM_NAME]; +//++ BulliT + short flag; +//-- Martin Webrant }; struct team_info_t @@ -556,6 +559,25 @@ private: icon_sprite_t m_IconList[MAX_ICONSPRITES]; }; +//++ BulliT +#include "AgGlobal.h" +#include "AgHudSplash.h" +#include "AgHudCountdown.h" +#include "AgHudTimer.h" +#include "AgHudPlayerId.h" +#include "AgHudSettings.h" +#include "AgHudSuddenDeath.h" +#include "AgHudLongjump.h" +#include "AgHudCustomTimer.h" +#include "AgHudTimeout.h" +#include "AgHudGlobal.h" +#include "AgHudVote.h" +#include "AgHudNextmap.h" +#include "AgHudLocation.h" +//#include "AgHudIRC.h" +#include "AgHudCTF.h" +#include "AgHudScoreboard.h" +//-- Martin Webrant // //----------------------------------------------------- // @@ -633,7 +655,24 @@ public: CHudStatusIcons m_StatusIcons; CHudScoreboard m_Scoreboard; CHudMOTD m_MOTD; - +//++ BulliT + AgHudSplash m_Splash; + AgHudCountdown m_Countdown; + AgHudTimer m_Timer; + AgHudPlayerId m_PlayerId; + AgHudSettings m_Settings; + AgHudSuddenDeath m_SuddenDeath; + AgHudLongjump m_Longjump; + AgHudCustomTimer m_CustomTimer; + AgHudTimeout m_Timeout; + AgHudGlobal m_Global; + AgHudVote m_Vote; + AgHudNextmap m_Nextmap; + AgHudLocation m_Location; + //AgHudIRC m_IRC; + AgHudCTF m_CTF; + //AgHudScoreboard m_Scoreboard; +//-- Martin Webrant void Init( void ); void VidInit( void ); void Think(void); diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index aed98455..6df37d82 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -20,6 +20,11 @@ #include "cl_util.h" //#include "triangleapi.h" +//++ BulliT +#include +#include "AgMatchReport.h" +//-- Martin Webrant + #define MAX_LOGO_FRAMES 56 int grgLogoFrame[MAX_LOGO_FRAMES] = @@ -93,6 +98,22 @@ int CHud::Redraw( float flTime, int intermission ) if( m_flTimeDelta < 0 ) m_flTimeDelta = 0; + if( m_iIntermission && !intermission ) + { +//++ BulliT + //Stop recording the demo. + if( gEngfuncs.pDemoAPI->IsRecording() ) + gEngfuncs.pfnClientCmd( "stop\n" ); +//-- Martin Webrant + } + else if( !m_iIntermission && intermission ) + { +//++ BulliT + AgMatchReport Report; + Report.Save(); +//-- Martin Webrant + } + if( m_flShotTime && m_flShotTime < flTime ) { gEngfuncs.pfnClientCmd( "snapshot\n" ); @@ -194,6 +215,9 @@ const unsigned char colors[8][3] = int CHud::DrawHudString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) { +//++ BulliT + return AgDrawHudString( xpos, ypos, iMaxX, szIt, r, g, b ); +/* if( hud_textmode->value == 2 ) { gEngfuncs.pfnDrawSetTextColor( r / 255.0, g / 255.0, b / 255.0 ); @@ -224,6 +248,8 @@ int CHud::DrawHudString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g } return xpos; +*/ +//-- Martin Webrant } int CHud::DrawHudStringLen( char *szIt ) diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index ff6eb8ff..7045772d 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -133,8 +133,8 @@ int CHudSpectator::Init() m_drawnames = gEngfuncs.pfnRegisterVariable( "spec_drawnames", "1", 0 ); m_drawcone = gEngfuncs.pfnRegisterVariable( "spec_drawcone", "1", 0 ); m_drawstatus = gEngfuncs.pfnRegisterVariable( "spec_drawstatus", "1", 0 ); - m_autoDirector = gEngfuncs.pfnRegisterVariable( "spec_autodirector", "1", 0 ); - m_pip = gEngfuncs.pfnRegisterVariable( "spec_pip", "1", 0 ); + m_autoDirector = gEngfuncs.pfnRegisterVariable( "spec_autodirector", "0", 0 ); + m_pip = gEngfuncs.pfnRegisterVariable( "spec_pip", "0", 0 ); if( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector || !m_pip ) { @@ -315,6 +315,16 @@ void CHudSpectator::SetSpectatorStartPosition() else if( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) iJumpSpectator = 1; +//++ BulliT + else if( UTIL_FindEntityInMap( "info_player_team1", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + else if( UTIL_FindEntityInMap( "info_player_team2", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + else if( UTIL_FindEntityInMap( "ctf_redspawn", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + else if( UTIL_FindEntityInMap( "ctf_bluespawn", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; +//-- Martin Webrant else { // jump to 0,0,0 if no better position was found @@ -417,9 +427,11 @@ int CHudSpectator::Draw( float flTime ) sprintf( string, "%s", g_PlayerInfoList[i + 1].name ); lx = strlen( string ) * 3; // 3 is avg. character length :) - - DrawSetTextColor( color[0], color[1], color[2] ); - DrawConsoleString( m_vPlayerPos[i][0] - lx,m_vPlayerPos[i][1], string ); +//++ BulliT + //gEngfuncs.pfnDrawSetTextColor( color[0], color[1], color[2] ); + //DrawConsoleString( m_vPlayerPos[i][0] - lx, m_vPlayerPos[i][1], string ); + DrawConsoleString( m_vPlayerPos[i][0] - lx, m_vPlayerPos[i][1], string, color[0], color[1], color[2] ); +//-- Martin Webrant } return 1; @@ -736,6 +748,11 @@ void CHudSpectator::SetModes( int iNewMainMode, int iNewInsetMode ) // if we are NOT in HLTV mode, main spectator mode is set on server if( !gEngfuncs.IsSpectateOnly() ) { + char cmdstring[32]; + + // forward command to server + sprintf( cmdstring, "spec_mode %i", iNewMainMode ); + gEngfuncs.pfnServerCmd( cmdstring ); return; } @@ -1430,12 +1447,14 @@ void CHudSpectator::CheckSettings() // HL/TFC has no oberserver corsshair, so set it client side if( ( g_iUser1 == OBS_IN_EYE ) || ( g_iUser1 == OBS_ROAMING ) ) { +/* m_crosshairRect.left = 24; m_crosshairRect.top = 0; m_crosshairRect.right = 48; m_crosshairRect.bottom = 24; SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); +*/ } else { diff --git a/cl_dll/in_camera.cpp b/cl_dll/in_camera.cpp index 92051afe..3ba6c106 100644 --- a/cl_dll/in_camera.cpp +++ b/cl_dll/in_camera.cpp @@ -153,7 +153,8 @@ void DLLEXPORT CAM_Think( void ) #endif vec3_t viewangles; - switch( (int)cam_command->value ) +//++ BulliT +/* switch( (int)cam_command->value ) { case CAM_COMMAND_TOTHIRDPERSON: CAM_ToThirdPerson(); @@ -165,6 +166,8 @@ void DLLEXPORT CAM_Think( void ) default: break; } +*/ +//-- Martin Webrant if( !cam_thirdperson ) return; @@ -642,7 +645,7 @@ void CAM_EndDistance( void ) int DLLEXPORT CL_IsThirdPerson( void ) { - return ( cam_thirdperson ? 1 : 0 ) || ( g_iUser1 && ( g_iUser2 == gEngfuncs.GetLocalPlayer()->index ) ); + return cam_thirdperson ? 1 : 0; } void DLLEXPORT CL_CameraOffset( float *ofs ) diff --git a/cl_dll/input.cpp b/cl_dll/input.cpp index fd1ef7da..97816619 100644 --- a/cl_dll/input.cpp +++ b/cl_dll/input.cpp @@ -23,6 +23,9 @@ extern "C" #include "usercmd.h" #include "const.h" #include "camera.h" +//++ BulliT +#include "AgVariableChecker.h" +//-- Martin Webrant #include "in_defs.h" //#include "view.h" #include @@ -549,7 +552,9 @@ extern void __CmdFunc_InputPlayerSpecial( void ); void IN_Attack2Down( void ) { KeyDown( &in_attack2 ); - +//++ BulliT + //Removed unused function that sends extra command to server. __CmdFunc_InputPlayerSpecial(); +//-- Martin Webrant gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK2 ); } @@ -736,28 +741,49 @@ void CL_AdjustAngles( float frametime, float *viewangles ) if( !( in_strafe.state & 1 ) ) { - viewangles[YAW] -= speed * cl_yawspeed->value * CL_KeyState( &in_right ); - viewangles[YAW] += speed * cl_yawspeed->value * CL_KeyState( &in_left ); +//++ BulliT + viewangles[YAW] -= speed * ag_cl_yawspeed() * CL_KeyState( &in_right ); + viewangles[YAW] += speed * ag_cl_yawspeed() * CL_KeyState( &in_left ); + //viewangles[YAW] -= speed * cl_yawspeed->value * CL_KeyState( &in_right ); + //viewangles[YAW] += speed * cl_yawspeed->value * CL_KeyState( &in_left ); +//-- Martin Webrant viewangles[YAW] = anglemod( viewangles[YAW] ); } if( in_klook.state & 1 ) { +//++ BulliT + viewangles[PITCH] -= speed * ag_cl_pitchspeed() * CL_KeyState( &in_forward ); + viewangles[PITCH] += speed * ag_cl_pitchspeed() * CL_KeyState( &in_back ); +/* viewangles[PITCH] -= speed * cl_pitchspeed->value * CL_KeyState( &in_forward ); viewangles[PITCH] += speed * cl_pitchspeed->value * CL_KeyState( &in_back ); +*/ +//-- Martin Webrant } up = CL_KeyState( &in_lookup ); down = CL_KeyState( &in_lookdown ); - viewangles[PITCH] -= speed * cl_pitchspeed->value * up; - viewangles[PITCH] += speed * cl_pitchspeed->value * down; +//++ BulliT + viewangles[PITCH] -= speed * ag_cl_pitchspeed() * up; + viewangles[PITCH] += speed * ag_cl_pitchspeed() * down; + //viewangles[PITCH] -= speed * cl_pitchspeed->value * up; + //viewangles[PITCH] += speed * cl_pitchspeed->value * down; +//-- Martin Webran +//++ BulliT + if( viewangles[PITCH] > ag_cl_pitchdown() ) + viewangles[PITCH] = ag_cl_pitchdown(); + if( viewangles[PITCH] < -ag_cl_pitchup() ) + viewangles[PITCH] = -ag_cl_pitchup(); +/* if( viewangles[PITCH] > cl_pitchdown->value ) viewangles[PITCH] = cl_pitchdown->value; if( viewangles[PITCH] < -cl_pitchup->value ) viewangles[PITCH] = -cl_pitchup->value; - +*/ +//-- Martin Webrant if( viewangles[ROLL] > 50 ) viewangles[ROLL] = 50; if( viewangles[ROLL] < -50 ) diff --git a/cl_dll/inputw32.cpp b/cl_dll/inputw32.cpp index 5c8210fa..f44a18be 100644 --- a/cl_dll/inputw32.cpp +++ b/cl_dll/inputw32.cpp @@ -19,8 +19,12 @@ #include "in_defs.h" #include "../engine/keydefs.h" //#include "view.h" -#include "windows.h" +//#include "windows.h" +//++ BulliT +extern int g_iPure; +#include "AgVariableChecker.h" +//-- Martin Webrant #define MOUSE_BUTTON_COUNT 5 // Set this to 1 to show mouse cursor. Experimental @@ -151,6 +155,10 @@ Force_CenterView_f */ void Force_CenterView_f( void ) { +//++ BulliT + if( 0 < g_iPure ) + return; +//-- Martin Webrant vec3_t viewangles; if( !iMouseInUse ) @@ -349,10 +357,18 @@ void IN_MouseMove( float frametime, usercmd_t *cmd ) if( ( in_mlook.state & 1 ) && !( in_strafe.state & 1 ) ) { viewangles[PITCH] += m_pitch->value * mouse_y; +//++ BulliT + if( viewangles[PITCH] > ag_cl_pitchdown() ) + viewangles[PITCH] = ag_cl_pitchdown(); + if( viewangles[PITCH] < -ag_cl_pitchup() ) + viewangles[PITCH] = -ag_cl_pitchup(); +/* if( viewangles[PITCH] > cl_pitchdown->value ) viewangles[PITCH] = cl_pitchdown->value; if( viewangles[PITCH] < -cl_pitchup->value ) viewangles[PITCH] = -cl_pitchup->value; +*/ +//-- Martin Webrant } else { @@ -769,11 +785,17 @@ void IN_JoyMove( float frametime, usercmd_t *cmd ) // only absolute control support here (joy_advanced is 0) if( m_pitch->value < 0.0 ) { - viewangles[PITCH] -= ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; +//++ BulliT + //viewangles[PITCH] -= ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; + viewangles[PITCH] -= ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * ag_cl_pitchspeed(); +//-- Martin Webrant } else { - viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; +//++ BulliT + //viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; + viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * ag_cl_pitchspeed(); +//-- Martin Webrant } } } @@ -808,7 +830,8 @@ void IN_JoyMove( float frametime, usercmd_t *cmd ) { if( dwControlMap[i] == JOY_ABSOLUTE_AXIS ) { - viewangles[YAW] += ( fAxisValue * joy_yawsensitivity->value ) * aspeed * cl_yawspeed->value; + viewangles[YAW] += ( fAxisValue * joy_yawsensitivity->value ) * aspeed * ag_cl_yawspeed(); + //viewangles[YAW] += ( fAxisValue * joy_yawsensitivity->value ) * aspeed * cl_yawspeed->value; } else { @@ -825,7 +848,10 @@ void IN_JoyMove( float frametime, usercmd_t *cmd ) // pitch movement detected and pitch movement desired by user if( dwControlMap[i] == JOY_ABSOLUTE_AXIS ) { - viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; +//++ BulliT + //viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; + viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * ag_cl_pitchspeed(); +//-- Martin Webrant } else { @@ -840,11 +866,18 @@ void IN_JoyMove( float frametime, usercmd_t *cmd ) } // bounds check pitch +//++ BulliT + if( viewangles[PITCH] > ag_cl_pitchdown() ) + viewangles[PITCH] = ag_cl_pitchdown(); + if( viewangles[PITCH] < -ag_cl_pitchup() ) + viewangles[PITCH] = -ag_cl_pitchup(); +/* if( viewangles[PITCH] > cl_pitchdown->value ) viewangles[PITCH] = cl_pitchdown->value; if( viewangles[PITCH] < -cl_pitchup->value ) viewangles[PITCH] = -cl_pitchup->value; - +*/ +//-- Martin Webrant gEngfuncs.SetViewAngles( (float *)viewangles ); } diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp index 8f2e2520..7091ad60 100644 --- a/cl_dll/saytext.cpp +++ b/cl_dll/saytext.cpp @@ -25,6 +25,10 @@ #include #include +//++ BulliT +extern cvar_t *g_pcl_playtalk; +//-- Martin Webrant + extern float *GetClientColor( int clientIndex ); #define MAX_LINES 5 @@ -128,9 +132,11 @@ int CHudSayText::Draw( float flTime ) // draw the first x characters in the player color strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH + 32 ) ); buf[min( g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH + 31 )] = 0; - DrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); - int x = DrawConsoleString( LINE_START, y, buf ); - +//++ BulliT + int x = DrawConsoleString( LINE_START, y, buf, g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); + //DrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); + //int x = DrawConsoleString( LINE_START, y, buf ); +//-- Martin Webrant // color is reset after each string draw DrawConsoleString( x, y, g_szLineBuffer[i] + g_iNameLengths[i] ); } @@ -162,6 +168,16 @@ void CHudSayText::SayTextPrint( const char *pszBuf, int iBufSize, int clientInde int i; ConsolePrint( pszBuf ); +//++ BulliT + if( CVAR_GET_FLOAT( "cl_only_team_talk" ) == 1 ) + { + if( 0 != strncmp( pszBuf + 1,"(T)", 3 ) && 0 != strncmp( pszBuf + 1, "(C)", 3 ) ) + { + ConsolePrint( pszBuf ); + return; + } + } +//-- Martin Webrant // find an empty string slot for( i = 0; i < MAX_LINES; i++ ) { @@ -198,6 +214,9 @@ void CHudSayText::SayTextPrint( const char *pszBuf, int iBufSize, int clientInde strncpy( g_szLineBuffer[i], pszBuf, max( iBufSize - 1, MAX_CHARS_PER_LINE - 1 ) ); +//++ BulliT + gHUD.m_Location.ParseAndEditSayString( g_szLineBuffer[i],clientIndex ); +//-- Martin Webrant // make sure the text fits in one line EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); @@ -208,8 +227,10 @@ void CHudSayText::SayTextPrint( const char *pszBuf, int iBufSize, int clientInde } m_iFlags |= HUD_ACTIVE; - PlaySound( "misc/talk.wav", 1 ); - +//++ BulliT + if( 0 < g_pcl_playtalk->value ) + PlaySound( "misc/talk.wav", 1 ); +//-- Martin Webrant if( ScreenHeight >= 480 ) Y_START = ScreenHeight - 60; else diff --git a/cl_dll/statusbar.cpp b/cl_dll/statusbar.cpp index 98b317c5..bd053bde 100644 --- a/cl_dll/statusbar.cpp +++ b/cl_dll/statusbar.cpp @@ -202,9 +202,12 @@ int CHudStatusBar::Draw( float fTime ) } if( m_pflNameColors[i] ) - DrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); - - DrawConsoleString( x, y, m_szStatusBar[i] ); +//++ BulliT + //gEngfuncs.pfnDrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); + DrawConsoleString( x, y, m_szStatusBar[i], m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); + else +//-- Martin Webrant + DrawConsoleString( x, y, m_szStatusBar[i] ); } return 1; diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index b581cc82..239582f5 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -1393,7 +1393,7 @@ void V_CalcSpectatorRefdef( struct ref_params_s * pparams ) } // predict missing client data and set weapon model ( in HLTV mode or inset in eye mode ) - if( gEngfuncs.IsSpectateOnly() ) + if( 1 ) //gEngfuncs.IsSpectateOnly() ) { V_GetInEyePos( g_iUser2, pparams->simorg, pparams->cl_viewangles ); diff --git a/dlls/aghl/agadmin.cpp b/dlls/aghl/agadmin.cpp new file mode 100644 index 00000000..d8d18a0f --- /dev/null +++ b/dlls/aghl/agadmin.cpp @@ -0,0 +1,21 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "agglobal.h" +#include "agadmin.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgAdmin::AgAdmin() +{ +} + +AgAdmin::~AgAdmin() +{ + +} + +//-- Martin Webrant diff --git a/dlls/aghl/agadmin.h b/dlls/aghl/agadmin.h new file mode 100644 index 00000000..c90fecdc --- /dev/null +++ b/dlls/aghl/agadmin.h @@ -0,0 +1,24 @@ +//++ BulliT + +#if !defined(AFX_AGADMIN_H__E1E58F06_B2BD_43F9_99A0_0B3F6D6B7B16__INCLUDED_) +#define AFX_AGADMIN_H__E1E58F06_B2BD_43F9_99A0_0B3F6D6B7B16__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// The admin user +class AgAdmin +{ +public: + AgAdmin(); + virtual ~AgAdmin(); + + AgString m_sAdmin; + AgString m_sPassword; + AgString m_sAuthID; +}; + +#endif // !defined(AFX_AGADMIN_H__E1E58F06_B2BD_43F9_99A0_0B3F6D6B7B16__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agadmincache.cpp b/dlls/aghl/agadmincache.cpp new file mode 100644 index 00000000..75a4ebac --- /dev/null +++ b/dlls/aghl/agadmincache.cpp @@ -0,0 +1,261 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" + +#include "agadmin.h" +#include "agadmincache.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DLL_GLOBAL AgAdminCache AdminCache; //The one and only + +AgAdminCache::AgAdminCache() +{ + +} + +AgAdminCache::~AgAdminCache() +{ + //Delete all. + for (AgAdminList::iterator itrAdmins = m_lstAdmins.begin() ;itrAdmins != m_lstAdmins.end(); ++itrAdmins) + delete *itrAdmins; + m_lstAdmins.clear(); +} + +void AgAdminCache::RestoreAdmin(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + if (g_bLangame) + return; + + for (AgAdminList::iterator itrAdmins = m_lstAdmins.begin() ;itrAdmins != m_lstAdmins.end(); ++itrAdmins) + { + if ((*itrAdmins)->m_sAuthID == pPlayer->GetAuthID()) + { + //Set admin flag. + pPlayer->SetIsAdmin(true); + break; + } + } +} + +void AgAdminCache::Load() +{ + if (0 != m_lstAdmins.size()) + return; //Already loaded. + + char szFile[MAX_PATH]; + char szData[4096]; + sprintf(szFile, "%s/admin.txt", AgGetDirectory()); + FILE* pFile = fopen(szFile,"r"); + if (!pFile) + { + return; + } + + enum enumParseState { User, Pass, AuthID }; + enumParseState ParseState = User; + AgAdmin* pAdmin = new AgAdmin; + int iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile); + if (0 >= iRead) + return; + szData[iRead] = '\0'; + + char* pszParse = NULL; + pszParse = strtok(szData, "#"); + if (pszParse) + { + while (pszParse) + { + if (User == ParseState) + { + pAdmin->m_sAdmin = pszParse; + ParseState = Pass; + } + else if (Pass == ParseState) + { + pAdmin->m_sPassword = pszParse; + ParseState = AuthID; + } + else if (AuthID == ParseState) + { + pAdmin->m_sAuthID = pszParse; + m_lstAdmins.push_back(pAdmin); + pAdmin = new AgAdmin; + ParseState = User; + } + pszParse = strtok(NULL, "#"); + } + } + delete pAdmin; + + fclose(pFile); +} + + +void AgAdminCache::Save(CBasePlayer* pPlayer) +{ + if (0 == m_lstAdmins.size()) + return; + + char szFile[MAX_PATH]; + sprintf(szFile, "%s/admin.txt", AgGetDirectory()); + FILE* pFile = fopen(szFile,"wb"); + if (!pFile) + { + AgConsole(UTIL_VarArgs("Couldn't create/save %s.",szFile),pPlayer); + return; + } + + //Loop and write the file. + for (AgAdminList::iterator itrAdmins = m_lstAdmins.begin() ;itrAdmins != m_lstAdmins.end(); ++itrAdmins) + { + //Append. + AgAdmin* pAdmin = *itrAdmins; + fprintf(pFile,"%s#%s#%s#",pAdmin->m_sAdmin.c_str(),pAdmin->m_sPassword.c_str(),pAdmin->m_sAuthID.c_str()); + } + + fflush(pFile); + fclose(pFile); +} + +void AgAdminCache::AddAdmin(const AgString& sAdmin, const AgString& sPassword, CBasePlayer* pPlayer) +{ + AgAdmin* pAdmin = NULL; + //Check if same name is used before. + bool bNameAlreadyInUse = false; + + for (AgAdminList::iterator itrAdmins = m_lstAdmins.begin() ;itrAdmins != m_lstAdmins.end(); ++itrAdmins) + { + if ((*itrAdmins)->m_sAdmin == sAdmin) + { + bNameAlreadyInUse = true; + break; + } + } + + if (bNameAlreadyInUse) + { + AgConsole(UTIL_VarArgs("Admin \"%s\" already exist.",sAdmin.c_str()),pPlayer); + } + else + { + //Name was ok. + pAdmin = new AgAdmin; + pAdmin->m_sAdmin = sAdmin; + pAdmin->m_sPassword = sPassword; + pAdmin->m_sAuthID = ""; + m_lstAdmins.push_back(pAdmin); + AgConsole(UTIL_VarArgs("Added admin %s/%s.",pAdmin->m_sAdmin.c_str(),pAdmin->m_sPassword.c_str()),pPlayer); + Save(pPlayer); + } +} + +void AgAdminCache::ListAdmins(CBasePlayer* pPlayer) +{ + if (0 == m_lstAdmins.size()) + { + AgConsole("There are no admins.",pPlayer); + } + else + { + for (AgAdminList::iterator itrAdmins = m_lstAdmins.begin() ;itrAdmins != m_lstAdmins.end(); ++itrAdmins) + { + AgConsole(UTIL_VarArgs("%s",(*itrAdmins)->m_sAdmin.c_str()),pPlayer); + } + } +} + +void AgAdminCache::DelAdmin(const AgString& sAdmin,CBasePlayer* pPlayer) +{ + if (0 == m_lstAdmins.size()) + { + AgConsole("There are no admins.",pPlayer); + } + else + { + for (AgAdminList::iterator itrAdmins = m_lstAdmins.begin() ;itrAdmins != m_lstAdmins.end(); ++itrAdmins) + { + AgAdmin* pAdmin = *itrAdmins; + if (pAdmin->m_sAdmin == sAdmin) + { + AgConsole(UTIL_VarArgs("Deleted admin %s.",sAdmin.c_str()),pPlayer); + m_lstAdmins.erase(itrAdmins); + delete pAdmin; + Save(pPlayer); + break; + } + } + } +} + + +void AgAdminCache::Auth(const AgString& sAdmin, const AgString& sPassword, CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + for (AgAdminList::iterator itrAdmins = m_lstAdmins.begin() ;itrAdmins != m_lstAdmins.end(); ++itrAdmins) + { + AgAdmin* pAdmin = *itrAdmins; + + if (pAdmin->m_sAdmin == sAdmin && pAdmin->m_sPassword == sPassword) + { + //Set as admin + pPlayer->SetIsAdmin(true); + //Save autoid - used for auto authentication. + pAdmin->m_sAuthID = pPlayer->GetAuthID(); + + AgConsole("You are now authenticated as an admin.",pPlayer); + Save(pPlayer); + break; + } + } +} + +void AgAdminCache::Newpass(const AgString& sOldpass, const AgString& sPassword, CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (!pPlayer->IsAdmin() || 0 == sPassword.size()) + return; + + for (AgAdminList::iterator itrAdmins = m_lstAdmins.begin() ;itrAdmins != m_lstAdmins.end(); ++itrAdmins) + { + AgAdmin* pAdmin = *itrAdmins; + + if (pAdmin->m_sAuthID == pPlayer->GetAuthID() && pAdmin->m_sPassword == sOldpass) + { + //Set new pass + pAdmin->m_sPassword = sPassword; + + //Save auth - used for auto authentication. + pAdmin->m_sAuthID = pPlayer->GetAuthID(); + + AgConsole("Changed password.",pPlayer); + Save(pPlayer); + break; + } + } +} + +//-- Martin Webrant diff --git a/dlls/aghl/agadmincache.h b/dlls/aghl/agadmincache.h new file mode 100644 index 00000000..ec758f59 --- /dev/null +++ b/dlls/aghl/agadmincache.h @@ -0,0 +1,40 @@ +//++ BulliT + +#if !defined(AFX_AGADMINCACHE_H__638C4983_F4E5_4118_B00C_BC595A3C3415__INCLUDED_) +#define AFX_AGADMINCACHE_H__638C4983_F4E5_4118_B00C_BC595A3C3415__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "agadmin.h" +class CBasePlayer; + +// Contains list of all admins and ability to save/load/restore and admin. +class AgAdminCache +{ + typedef list AgAdminList; + AgAdminList m_lstAdmins; + +public: + AgAdminCache(); + virtual ~AgAdminCache(); + + void RestoreAdmin(CBasePlayer* pPlayer); + void Load(); + void Save(CBasePlayer* pPlayer = NULL); + + void AddAdmin(const AgString& sAdmin, const AgString& sPassword, CBasePlayer* pPlayer = NULL); + void ListAdmins(CBasePlayer* pPlayer = NULL); + void DelAdmin(const AgString& sAdmin, CBasePlayer* pPlayer = NULL); + + void Auth(const AgString& sAdmin, const AgString& sPassword, CBasePlayer* pPlayer); + void Newpass(const AgString& sOldpassword, const AgString& sPassword, CBasePlayer* pPlayer); + +}; + +extern DLL_GLOBAL AgAdminCache AdminCache; + +#endif // !defined(AFX_AGADMINCACHE_H__638C4983_F4E5_4118_B00C_BC595A3C3415__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agarena.cpp b/dlls/aghl/agarena.cpp new file mode 100644 index 00000000..3d176cb5 --- /dev/null +++ b/dlls/aghl/agarena.cpp @@ -0,0 +1,356 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" + +#include "aggamerules.h" +#include "agglobal.h" +#include "agarena.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +extern int gmsgCountdown; + +AgArena::AgArena() +{ + m_fMatchStart = 0.0; + m_fNextCountdown = 0.0; + m_fNextSay = 0.0; + m_Player1 = NULL; + m_Player2 = NULL; + m_Status = Waiting; +} + +AgArena::~AgArena() +{ + +} + + +void AgArena::Think() +{ + if (!g_pGameRules) + return; + + if (Playing == m_Status) + { + CBasePlayer* pPlayer1 = GetPlayer1(); + CBasePlayer* pPlayer2 = GetPlayer2(); + + if (!pPlayer1 || pPlayer1 && !pPlayer1->IsAlive() || !pPlayer2 || pPlayer2 && !pPlayer2->IsAlive()) + { + m_Status = PlayerDied; + m_fNextCountdown = gpGlobals->time + 3.0; //Let the effect of him dying play for 3 seconds + + if (pPlayer1) + pPlayer1->SetIngame(false); //Cant respawn + if (pPlayer2) + pPlayer2->SetIngame(false); //Cant respawn + } + } + else + { + //We only update status once every second. + if (m_fNextCountdown > gpGlobals->time) + return; + m_fNextCountdown = gpGlobals->time + 1.0; + + //Handle the status + if (Waiting == m_Status) + { + //Get new arena players. + if (!GetPlayer1()) + { + //Get one from top of list. + if (0 != m_lstWaitList.size()) + { + m_Player1 = AgPlayerByIndex(m_lstWaitList.front()); + m_lstWaitList.pop_front(); + } + } + + if (!GetPlayer2()) + { + //Get one from top of list. + if (0 != m_lstWaitList.size()) + { + m_Player2 = AgPlayerByIndex(m_lstWaitList.front()); + m_lstWaitList.pop_front(); + } + } + + if (GetPlayer1() && GetPlayer2()) + { + m_Status = Countdown; + m_fMatchStart = gpGlobals->time + 5.0; + m_fNextCountdown = gpGlobals->time + 2.0; + } + + + //Write waiting message +#ifdef AG_NO_CLIENT_DLL + if (0 != m_sWinner.size()) + { + AgString s; + s = "Last match won by " + m_sWinner; + AgSay(NULL,s.c_str(),NULL,10,0.4,0.1,2); + m_sWinner = ""; + } + AgSay(NULL,"Waiting for players to get ready!\n",&m_fNextSay,2,0.4,0.5); +#else + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( 50 ); + WRITE_BYTE( 1 ); + WRITE_STRING( m_sWinner.c_str() ); + WRITE_STRING( "" ); + MESSAGE_END(); +#endif + } + else if (Countdown == m_Status) + { + if (!GetPlayer1() || !GetPlayer2()) + { + m_Status = Waiting; //Someone left in middle of countdown. Go back to waiting. + return; + } + + if (m_fMatchStart < gpGlobals->time) + { + //Clear out the map + AgResetMap(); + + GetPlayer1()->SetIngame(true); + GetPlayer2()->SetIngame(true); + g_pGameRules->m_ScoreCache.UpdateScore(GetPlayer1()); + g_pGameRules->m_ScoreCache.UpdateScore(GetPlayer2()); + + m_Status = Spawning; + m_sWinner = ""; + + //Time to start playing. + if (GetPlayer1()->IsSpectator()) + { + GetPlayer1()->Spectate_Stop(); + } + else + GetPlayer1()->RespawnMatch(); + + if (GetPlayer2()->IsSpectator()) + { + GetPlayer2()->Spectate_Stop(); + } + else + GetPlayer2()->RespawnMatch(); + + m_Status = Playing; + +#ifndef AG_NO_CLIENT_DLL + //Stop countdown + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( -1 ); + WRITE_BYTE( 0 ); + WRITE_STRING( "" ); + WRITE_STRING( "" ); + MESSAGE_END(); +#endif + } + else + { + //Write countdown message. +#ifdef AG_NO_CLIENT_DLL + char szMatchStart[128]; + sprintf(szMatchStart,"Match %s vs %s in %d seconds!\n",GetPlayer1()->GetName(),GetPlayer2()->GetName(),(int)(m_fMatchStart - gpGlobals->time)); + AgSay(NULL,szMatchStart,&m_fNextSay,1,0.3,0.5); +#else + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( (int)(m_fMatchStart - gpGlobals->time) ); + WRITE_BYTE( 1 ); + WRITE_STRING( GetPlayer1()->GetName() ); + WRITE_STRING( GetPlayer2()->GetName() ); + MESSAGE_END(); +#endif + } + } + else if (PlayerDied == m_Status) + { + CBasePlayer* pPlayer1 = GetPlayer1(); + CBasePlayer* pPlayer2 = GetPlayer2(); + + m_Status = Waiting; + m_sWinner = ""; + + if (pPlayer1 && !pPlayer1->IsAlive()) + { + if(!pPlayer1->IsSpectator()) + { + pPlayer1->Spectate_Start(false); + pPlayer1->Spectate_Follow(m_Player2,OBS_IN_EYE); + } + m_lstWaitList.push_back(pPlayer1->entindex()); + pPlayer1->SetIngame(false); + m_Player1 = NULL; + + if (pPlayer2) + { + pPlayer2->SetIngame(false); + if (pPlayer2->IsAlive()) + m_sWinner = pPlayer2->GetName(); + } + } + + if (pPlayer2 && !pPlayer2->IsAlive()) + { + if(!pPlayer2->IsSpectator()) + { + pPlayer2->Spectate_Start(false); + pPlayer2->Spectate_Follow(m_Player1,OBS_IN_EYE); + } + m_lstWaitList.push_back(pPlayer2->entindex()); + pPlayer2->SetIngame(false); + m_Player2 = NULL; + if (pPlayer1) + { + pPlayer1->SetIngame(false); + if (pPlayer1->IsAlive()) + m_sWinner = pPlayer1->GetName(); + } + } + + //Stop sounds. + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + CLIENT_COMMAND(pPlayerLoop->edict(),"stopsound\n"); + } + } + } + } +} + +void AgArena::Add(CBasePlayer* pPlayer) +{ + if (GetPlayer1() == pPlayer || GetPlayer2() == pPlayer) + return; + + if (0 == m_lstWaitList.size()) + { + m_lstWaitList.push_back(pPlayer->entindex()); + } + else + { + AgWaitList::iterator itrWaitlist = find(m_lstWaitList.begin(),m_lstWaitList.end(),pPlayer->entindex()); + if (itrWaitlist == m_lstWaitList.end()) + m_lstWaitList.push_back(pPlayer->entindex()); + } +} + +void AgArena::Remove(CBasePlayer* pPlayer) +{ + if (GetPlayer1() == pPlayer) + { + m_Player1 = NULL; + } + else if (GetPlayer2() == pPlayer) + { + m_Player2 = NULL; + } + else if (0 != m_lstWaitList.size()) + { + AgWaitList::iterator itrWaitlist = find(m_lstWaitList.begin(),m_lstWaitList.end(),pPlayer->entindex()); + if (itrWaitlist == m_lstWaitList.end()) + m_lstWaitList.erase(itrWaitlist); + //m_lstWaitList.remove(pPlayer->entindex()); + } +} + +void AgArena::Ready(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (Countdown != m_Status) + { + Add(pPlayer); + ClientPrint( pPlayer->pev, HUD_PRINTCONSOLE, "Changed mode to READY.\n"); + } + else + { + ClientPrint( pPlayer->pev, HUD_PRINTCONSOLE, "Can not change ready state at this point.\n"); + } +} + +void AgArena::NotReady(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (Countdown != m_Status) + { + pPlayer->SetIngame(false); + if(!pPlayer->IsSpectator()) + { + pPlayer->Spectate_Start(false); + } + Remove(pPlayer); + ClientPrint( pPlayer->pev, HUD_PRINTCONSOLE, "Changed mode to NOT READY.\n"); + } + else + { + ClientPrint( pPlayer->pev, HUD_PRINTCONSOLE, "Can not change ready state at this point.\n"); + } +} + +void AgArena::ClientConnected(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + //Set status + pPlayer->SetIngame(false); + + if (!pPlayer->IsProxy()) + Add(pPlayer); +} + + +void AgArena::ClientDisconnected(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + //Set status + pPlayer->SetIngame(false); + + //Just blank if active in arena. + //This will put the status into waiting mode within a second. + if (!pPlayer->IsProxy()) + Remove(pPlayer); +} + + +//-- Martin Webrant + diff --git a/dlls/aghl/agarena.h b/dlls/aghl/agarena.h new file mode 100644 index 00000000..36658051 --- /dev/null +++ b/dlls/aghl/agarena.h @@ -0,0 +1,80 @@ +// agarena.h: interface for the AgArena class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_AGARENA_H__1929C55A_3034_4C89_8398_1F8243B83499__INCLUDED_) +#define AFX_AGARENA_H__1929C55A_3034_4C89_8398_1F8243B83499__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgArena +{ + typedef list AgWaitList; + enum ArenaStatus { Waiting, Countdown, Spawning, Playing, PlayerDied }; + + AgWaitList m_lstWaitList; + ArenaStatus m_Status; + + float m_fNextCountdown; + float m_fMatchStart; + float m_fNextSay; + + EHANDLE m_Player1; + EHANDLE m_Player2; + + AgString m_sWinner; + + CBasePlayer* GetPlayer1(); + CBasePlayer* GetPlayer2(); + + void Add(CBasePlayer* pPlayer); + void Remove(CBasePlayer* pPlayer); + +public: + AgArena(); + virtual ~AgArena(); + + void Think(); + + void Ready(CBasePlayer* pPlayer); + void NotReady(CBasePlayer* pPlayer); + + void ClientDisconnected(CBasePlayer* pPlayer); + void ClientConnected(CBasePlayer* pPlayer); + + bool CanTakeDamage(); + bool CanHaveItem(); + +}; + + +inline CBasePlayer* AgArena::GetPlayer1() +{ + if (m_Player1) + return (CBasePlayer*)(CBaseEntity*)m_Player1; + else + return NULL; +}; + +inline CBasePlayer* AgArena::GetPlayer2() +{ + if (m_Player2) + return (CBasePlayer*)(CBaseEntity*)m_Player2; + else + return NULL; +}; + +inline bool AgArena::CanTakeDamage() +{ + return Playing == m_Status || PlayerDied == m_Status; +} + +inline bool AgArena::CanHaveItem() +{ + return Spawning == m_Status; +} + + +#endif // !defined(AFX_AGARENA_H__1929C55A_3034_4C89_8398_1F8243B83499__INCLUDED_) diff --git a/dlls/aghl/agclient.cpp b/dlls/aghl/agclient.cpp new file mode 100644 index 00000000..7584aba0 --- /dev/null +++ b/dlls/aghl/agclient.cpp @@ -0,0 +1,799 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "game.h" +#include "gamerules.h" +#include "teamplay_gamerules.h" + +#include "aggamerules.h" +#include "agclient.h" + +#include "voice_gamemgr.h" +extern CVoiceGameMgr g_VoiceGameMgr; + +#ifdef AGMSGSTAT +#include "agmsgstat.h" +#endif + +extern cvar_t timeleft, fragsleft; +extern int gmsgSayText; +extern int gmsgLocation; +extern int gmsgAuthID; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +extern int gmsgPlaySound; +extern int gmsgTeamInfo; +extern int g_teamplay; + +AgClient::AgClient() +{ + +} + +AgClient::~AgClient() +{ +} + +FILE_GLOBAL char* s_szCommands[] = +{ + "hud_spectatebar <1,0> - Spectator bar with information.", + "hud_timer <0-3> - Timer mode, 0 off, 1 = Time remaining, 2 = Effective time, 3 clock.", + "hud_playerid <1,0> - Player id.", + "hud_settings <1,0> - Show server settings.", + "cl_matchreport <1,0> - Save matchreport in /report directory.", + "cl_autowepswitch <2,1,0> - Switch to better weapon when you walk over it. 2 = Ag switch", + "cl_scores <0 - 32> - Amount of scores to draw on hud.", + "cl_only_team_talk <1,0> - Only print team talk.", + "auth - Authenticate you as an admin.", + "newpass - Change password.", + "settings - Shows server settings.", + "timeleft - Shows time left.", + "timeout - Call 1 minute timeout.", + "play_team - Players wave file to m8's.", + "play_close - Players wave file to m8's that are close.", + "say enhancements - %%h health, %%a armour, %%q ammo, %%w weapon, %%l location", + "more say - %%p longjump status %%s your score", + "say_close - Says a message to team m8's close to you.", + "spectate - Leave/enter spectator mode.", + "ready/notready - Set ready mode.", + "winamp play/pause/stop/forward/back/next/prev/close/shuffle/repeat/volume 0-255", + "dropitems - Drops flag in CTF mode", +}; + + +bool AgClient::HandleCommand(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return false; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return false; + ASSERT(NULL != g_pGameRules); + + if (!g_pGameRules || 0 == CMD_ARGC()) + return false; + + if (FStrEq(CMD_ARGV(0), "_special")) + { + return true; + } + else if (FStrEq(CMD_ARGV(0), "say")) + { + Say(pPlayer, All); + return true; + } + else if (FStrEq(CMD_ARGV(0), "say_team")) + { + Say(pPlayer, Team); + return true; + } + else if (FStrEq(CMD_ARGV(0), "say_close")) + { + Say(pPlayer, Close); + return true; + } + else if (FStrEq(CMD_ARGV(0), "spectate" )) + { + if (pPlayer->IsProxy()) + return pPlayer->Spectate_HLTV(); + + //Dont spectate if player is in game in arena. + //Use sound and text flood checks, We dont want lamers to change to often. + if (pPlayer->IsIngame() && ARENA == AgGametype() || pPlayer->FloodCheck() || pPlayer->FloodSound()) + return true; + + if (2 == CMD_ARGC() && 1 == atoi(CMD_ARGV(1))) + pPlayer->Spectate_Start(); + else if (2 == CMD_ARGC() && 0 == atoi(CMD_ARGV(1))) + pPlayer->Spectate_Stop(); + else + pPlayer->Spectate_Spectate(); + return true; + } + else if (FStrEq(CMD_ARGV(0), "follownext") && 2 == CMD_ARGC()) + { + bool bReverse = 1 == atoi(CMD_ARGV(1)); + pPlayer->Spectate_Nextplayer(bReverse); + return true; + } + else if (FStrEq(CMD_ARGV(0), "spec_mode") && 2 == CMD_ARGC()) + { + int iSpecMode = atoi(CMD_ARGV(1)); + pPlayer->Spectate_SetMode(iSpecMode); + return true; + } + else if (FStrEq(CMD_ARGV(0), "jointeam" ) && 2 == CMD_ARGC()) + { + if (pPlayer->IsProxy()) + return true; + + if (g_teamplay) + { + const char* pszTeamName = ""; + const char* pszTeamNumber = CMD_ARGV(1); + int iTeam = atoi(pszTeamNumber)-1; + if (5 == iTeam && g_teamplay) + { + if (!g_pGameRules->IsValidTeam(pPlayer->TeamID())) + { + ((CHalfLifeTeamplay*)g_pGameRules)->RecountTeams(); + pszTeamName = ((CHalfLifeTeamplay*)g_pGameRules)->TeamWithFewestPlayers(); + } + } + else + pszTeamName = g_pGameRules->GetIndexedTeamName(iTeam); + if (strlen(pszTeamName)) + g_pGameRules->ChangePlayerTeam(pPlayer,pszTeamName,TRUE,TRUE); + } + + if (pPlayer->IsSpectator()) + pPlayer->Spectate_Stop(); + return true; + } + else if (FStrEq(CMD_ARGV(0), "timeleft" )) + { + if (timelimit.value && timeleft.value) + AgConsole(UTIL_VarArgs("timeleft = %.0f",timeleft.value),pPlayer); + return true; + } + else if (FStrEq(CMD_ARGV(0), "timeout" )) + { + if (ARENA != AgGametype() || LMS != AgGametype()) + g_pGameRules->m_Timeout.Timeout(pPlayer); + return true; + } + else if (FStrEq(CMD_ARGV(0), "ready" )) + { + if (ARENA == AgGametype()) + { + g_pGameRules->m_Arena.Ready(pPlayer); + return true; + } + else if (LMS == AgGametype()) + { + ClientPrint( pPlayer->pev, HUD_PRINTCONSOLE, "Changed mode to READY.\n"); + if (!pPlayer->m_bReady) + { + pPlayer->m_bReady = true; + //Send new team name + if (g_pGameRules->IsTeamplay()) + { + MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + WRITE_BYTE( pPlayer->entindex() ); + WRITE_STRING( pPlayer->TeamID() ); + MESSAGE_END(); + } + } + + return true; + } + } + else if (FStrEq(CMD_ARGV(0), "notready" )) + { + if (ARENA == AgGametype()) + { + g_pGameRules->m_Arena.NotReady(pPlayer); + return true; + } + else if (LMS == AgGametype()) + { + ClientPrint( pPlayer->pev, HUD_PRINTCONSOLE, "Changed mode to NOT READY.\n"); + if (pPlayer->m_bReady) + { + pPlayer->m_bReady = false; + pPlayer->SetIngame(false); //Cant respawn + if(!pPlayer->IsSpectator()) + { + pPlayer->Spectate_Start(true); + pPlayer->Spectate_SetMode(OBS_IN_EYE); + } + else + { + //Send new team name (blank for specs) + if (g_pGameRules->IsTeamplay()) + { + MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + WRITE_BYTE( pPlayer->entindex() ); + WRITE_STRING( pPlayer->TeamID() ); + MESSAGE_END(); + } + } + } + + return true; + } + } + else if (FStrEq(CMD_ARGV(0), "play_team" )) + { + if (2 == CMD_ARGC()) + { + Play(pPlayer, Team, CMD_ARGV(1)); + } + return true; + } + else if (FStrEq(CMD_ARGV(0), "play_close" )) + { + if (2 == CMD_ARGC()) + { + Play(pPlayer, Close, CMD_ARGV(1)); + } + return true; + } else if (FStrEq(CMD_ARGV(0), "auth" )) + { + if (3 == CMD_ARGC()) + { + AdminCache.Auth(CMD_ARGV(1), CMD_ARGV(2), pPlayer); + } + return true; + } + else if (FStrEq(CMD_ARGV(0), "newpass" )) + { + if (3 == CMD_ARGC()) + { + AdminCache.Newpass(CMD_ARGV(1), CMD_ARGV(2), pPlayer); + } + return true; + } + else if (FStrEq(CMD_ARGV(0), "help")) + { + for (int i = 0; i < sizeof(s_szCommands)/sizeof(s_szCommands[0]); i++) + AgConsole(s_szCommands[i],pPlayer); + + //Continue with more help commands. + return false; + } + else if (FStrEq(CMD_ARGV(0), "settings")) + { + pPlayer->SetDisplayGamemode(0); + return true; + } +#ifndef AG_NO_CLIENT_DLL + else if (FStrEq(CMD_ARGV(0), "dropitems") && CTF == AgGametype()) + { + g_pGameRules->m_CTF.PlayerDropFlag(pPlayer,true); + return true; + } +#ifdef _DEBUG + else if (FStrEq(CMD_ARGV(0), "addctfitem")) +#else + else if (FStrEq(CMD_ARGV(0), "addctfitem") && g_bLangame) +#endif + { + if (2 == CMD_ARGC()) + { + g_pGameRules->m_CTF.m_FileItemCache.Add(CMD_ARGV(1), pPlayer); + } + return true; + } +#ifdef _DEBUG + else if (FStrEq(CMD_ARGV(0), "dellastctfitem")) +#else + else if (FStrEq(CMD_ARGV(0), "dellastctfitem") && g_bLangame) +#endif + { + if (1 == CMD_ARGC()) + { + g_pGameRules->m_CTF.m_FileItemCache.Del(pPlayer); + } + return true; + } +#ifdef _DEBUG + else if (FStrEq(CMD_ARGV(0), "listctfitem")) +#else + else if (FStrEq(CMD_ARGV(0), "listctfitem") && g_bLangame) +#endif + { + if (1 == CMD_ARGC()) + { + g_pGameRules->m_CTF.m_FileItemCache.List(pPlayer); + } + return true; + } +//++ muphicks +#ifdef _DEBUG + else if (FStrEq(CMD_ARGV(0), "adddomitem")) +#else + else if (FStrEq(CMD_ARGV(0), "adddomitem") && g_bLangame) +#endif + { + if (2 == CMD_ARGC()) + { + g_pGameRules->m_DOM.m_FileItemCache.Add(CMD_ARGV(1), pPlayer); + } + return true; + } +#ifdef _DEBUG + else if (FStrEq(CMD_ARGV(0), "dellastdomitem")) +#else + else if (FStrEq(CMD_ARGV(0), "dellastdomitem") && g_bLangame) +#endif + { + if (1 == CMD_ARGC()) + { + g_pGameRules->m_DOM.m_FileItemCache.Del(pPlayer); + } + return true; + } +#ifdef _DEBUG + else if (FStrEq(CMD_ARGV(0), "listdomitem")) +#else + else if (FStrEq(CMD_ARGV(0), "listdomitem") && g_bLangame) +#endif + { + if (1 == CMD_ARGC()) + { + g_pGameRules->m_DOM.m_FileItemCache.List(pPlayer); + } + return true; + } +//-- muphicks +#endif + else if (FStrEq(CMD_ARGV(0), "changeteam")) + { + #define MENU_TEAM 2 + pPlayer->ShowVGUI(MENU_TEAM); + return true; + } + else if (FStrEq(CMD_ARGV(0), "fullupdate")) + { + pPlayer->ForceClientDllUpdate(); + return true; + } + else if (FStrEq(CMD_ARGV(0), "agosinfo")) + { + AgConsole(AgOSVersion(),pPlayer); + return true; + } +#ifndef AG_NO_CLIENT_DLL + else if (FStrEq(CMD_ARGV(0), "maplist")) + { + g_pGameRules->SendMapListToClient(pPlayer,true); + return true; + } +#endif +#ifdef AGMSGSTAT + else if (FStrEq(CMD_ARGV(0), "agmsgstat")) + { + g_MsgStat.DumpStats(); + return true; + } +#endif + + /* + else if (FStrEq(CMD_ARGV(0), "botme")) + { + edict_t* pEntity = g_engfuncs.pfnCreateFakeClient( "botme" ); + entvars_t *pev = &pEntity->v; + CBasePlayer* pBot = GetClassPtr((CBasePlayer*)pev); //Link bot object to the edict + + pBot->Init(); + pev->flags |= FL_FAKECLIENT; // bot is fakeclient + pBot->Spawn(); + pev->flags |= FL_FAKECLIENT; // bot is fakeclient + pBot = (CBasePlayer *)CBasePlayer::Instance(pEntity); + g_pGameRules->PlayerThink( pBot); + g_engfuncs.pfnSetClientKeyValue( pPlayer->entindex(), + g_engfuncs.pfnGetInfoKeyBuffer(pEntity), "model", "xxx"); + } + */ + + return false; +} + +CBaseEntity* FindEntityForward( CBasePlayer* pMe ) +{ + TraceResult tr; + UTIL_MakeVectors(pMe->pev->v_angle); + UTIL_TraceLine(pMe->pev->origin + pMe->pev->view_ofs,pMe->pev->origin + pMe->pev->view_ofs + gpGlobals->v_forward * 2048,missile, pMe->edict(), &tr ); + if ( tr.flFraction != 1.0 && !FNullEnt( tr.pHit) ) + { + CBaseEntity* pHit = CBaseEntity::Instance( tr.pHit ); + return pHit; + } + return NULL; +} + +void AgClient::Say(CBasePlayer* pPlayer, say_type Type ) +{ + char* pSayText = (char*)CMD_ARGS(); + + if ( CMD_ARGC() < 2 || 128 < strlen(pSayText) || !pPlayer || !g_pGameRules || 1 > strlen(pSayText)) + return; + + //Check if the user is flooding us with nonsens. + if ((All == Type || pPlayer->IsSpectator()) && pPlayer->FloodCheck() || pPlayer->FloodText()) + return; + + bool bSendLocation = false; + bool bSendDeathLocation = false; + + char szText[256]; + char* pText = szText; + + if (pPlayer->IsSpectator() && Team == Type) + pText = pText + sprintf(pText,"%c(ST) %s: ", 2, pPlayer->GetName()); + else if (pPlayer->IsSpectator()) + pText = pText + sprintf(pText,"%c(S) %s: ", 2, pPlayer->GetName()); + else if (Team == Type) + pText = pText + sprintf(pText,"%c(T) %s: ", 2, pPlayer->GetName()); + else if (Close == Type) + pText = pText + sprintf(pText,"%c(C) %s: ", 2, pPlayer->GetName()); + else + pText = pText + sprintf(pText,"%c(A) %s: ", 2, pPlayer->GetName()); + + //Remove quotes + if (*pSayText == '"') + { + pSayText++; + pSayText[strlen(pSayText)-1] = 0; + } + + if (1 > strlen(pSayText)) + return; + + //Check AG teambind + while (*pSayText && (pText - szText) < 200) //Dont overflow the string. Stop when its 200 chars. + { + if ('%' == *pSayText) + { + pSayText++; + if ('h' == *pSayText || 'H' == *pSayText) + { + //Health. + if (pPlayer && pPlayer->IsAlive() && !pPlayer->IsSpectator()) + pText = pText + sprintf(pText,"%.0f",pPlayer->pev->health); + pSayText++; + continue; + } + else if ('a' == *pSayText || 'A' == *pSayText) + { + //Armour. + if (pPlayer && pPlayer->IsAlive() && !pPlayer->IsSpectator()) + pText = pText + sprintf(pText,"%.0f",pPlayer->pev->armorvalue); + pSayText++; + continue; + } + else if ('q' == *pSayText || 'Q' == *pSayText) + { + //Ammo. + if (pPlayer && pPlayer->IsAlive() && !pPlayer->IsSpectator() && pPlayer->m_pActiveItem && pPlayer->m_pActiveItem->m_iId < MAX_AMMO_SLOTS) + { + CBasePlayerWeapon* pWeapon = (CBasePlayerWeapon*)pPlayer->m_pActiveItem->GetWeaponPtr(); + if (pWeapon) + { + int iAmmoIndex1 = -1; + int iAmmoIndex2 = -1; + + if (pWeapon->pszAmmo1()) + iAmmoIndex1 = pPlayer->GetAmmoIndex( pWeapon->pszAmmo1() ); + if (pWeapon->pszAmmo2()) + iAmmoIndex2 = pPlayer->GetAmmoIndex( pWeapon->pszAmmo2() ); + + if (iAmmoIndex1 != -1 && iAmmoIndex2 != -1) + pText = pText + sprintf(pText,"%d/%d",(int)(pPlayer->m_rgAmmo[iAmmoIndex1] + pWeapon->m_iClip),(int)(pPlayer->m_rgAmmo[iAmmoIndex2])); + else if (iAmmoIndex1 != -1) + pText = pText + sprintf(pText,"%d",(int)(pPlayer->m_rgAmmo[iAmmoIndex1] + pWeapon->m_iClip)); + else if (iAmmoIndex2 != -1) + pText = pText + sprintf(pText,"%d",(int)(pPlayer->m_rgAmmo[iAmmoIndex2] + pWeapon->m_iClip)); + else + pText = pText + sprintf(pText,"0"); + } + } + pSayText++; + continue; + } + else if ('w' == *pSayText || 'W' == *pSayText) + { + //Weapon + if (pPlayer && pPlayer->IsAlive() && !pPlayer->IsSpectator() && pPlayer->m_pActiveItem && pPlayer->m_pActiveItem->m_iId < MAX_WEAPONS) + { + char* pWeapon = strstr(pPlayer->m_pActiveItem->pszName(),"weapon_"); + if (pWeapon) + { + pText = pText + sprintf(pText,"%s",&pWeapon[7]); + } + } + pSayText++; + continue; + } + else if ('p' == *pSayText || 'P' == *pSayText) + { + //LJ Status + if (pPlayer && pPlayer->IsAlive() && !pPlayer->IsSpectator()) + { + if (pPlayer->m_fLongJump) + pText = pText + sprintf(pText,"got LJ"); + else + pText = pText + sprintf(pText,"no LJ"); + } + pSayText++; + continue; + } + /* + else if ('o' == *pSayText || 'o' == *pSayText) + { + //Looking at. + if (pPlayer && pPlayer->IsAlive() && !pPlayer->IsSpectator()) + { + CBaseEntity* pEntity = FindEntityForward(pPlayer); + if (pEntity && pEntity->pev) + pText = pText + sprintf(pText,STRING(pEntity->pev->classname)); + } + pSayText++; + continue; + } + */ + else if ('s' == *pSayText || 'S' == *pSayText) + { + //Score + if (pPlayer && pPlayer->IsAlive() && !pPlayer->IsSpectator()) + pText = pText + sprintf(pText,"%.0f/%d",pPlayer->pev->frags,pPlayer->m_iDeaths); + pSayText++; + continue; + } + else if ('f' == *pSayText || 'F' == *pSayText) + { + //Flag info + if (pPlayer && pPlayer->IsAlive() && !pPlayer->IsSpectator()) + if (pPlayer->m_bFlagTeam1) + pText = pText + sprintf(pText,CTF_TEAM1_NAME); + else if (pPlayer->m_bFlagTeam2) + pText = pText + sprintf(pText,CTF_TEAM2_NAME); + pSayText++; + continue; + } + else if ('l' == *pSayText || 'L' == *pSayText) + { +#ifdef AG_NO_CLIENT_DLL + pText = pText + sprintf(pText,g_pGameRules->m_LocationCache.Location(pPlayer->pev->origin).c_str()); + pSayText++; + continue; +#else + bSendLocation = true; + pText[0] = '%'; + pText++; +#endif + } + else if ('d' == *pSayText || 'D' == *pSayText) + { +#ifdef AG_NO_CLIENT_DLL + pText = pText + sprintf(pText,g_pGameRules->m_LocationCache.Location(pPlayer->GetKilledPosition()).c_str()); + pSayText++; + continue; +#else + bSendDeathLocation = true; + pText[0] = '%'; + pText++; +#endif + } + else + { + pText[0] = '%'; + pText++; + continue; + } + } + + *pText = *pSayText; + pText++; + pSayText++; + } + *pText = '\0'; +#ifdef AG_NO_CLIENT_DLL + AgStripColors(szText); +#endif + + // team match? + char * temp; + if (All == Type) + temp = "say"; + else + temp = "say_team"; + + if ( g_teamplay ) + { + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" %s \"%s\"\n", + STRING( pPlayer->edict()->v.netname ), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERAUTHID( pPlayer->edict() ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ), + temp, + szText ); + } + else + { + UTIL_LogPrintf( "\"%s<%i><%s><%i>\" %s \"%s\"\n", + STRING( pPlayer->edict()->v.netname ), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERAUTHID( pPlayer->edict() ), + GETPLAYERUSERID( pPlayer->edict() ), + temp, + szText ); + } + + if (pPlayer->IsSpectator()) + { + //Spectators can talk to team m8 + //Loop through all players + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayerLoop->IsNetClient()) + { + // can the receiver hear the sender? or has he muted him? + if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( pPlayerLoop, pPlayer ) ) + continue; + + //Sort team messages. Only talk to team m8's that are spectators + if ( (Team == Type || Close == Type ) + && !pPlayerLoop->IsSpectator() && pPlayer != pPlayerLoop) + continue; + + //Dont let specs talk to all if spectalk = 0 if it aint an admin on a match + if (0 == ag_spectalk.value && !pPlayer->IsAdmin() && All == Type && 0 < ag_match_running.value && pPlayer != pPlayerLoop) + continue; + +#ifndef AG_NO_CLIENT_DLL + if (bSendLocation) + { + MESSAGE_BEGIN( MSG_ONE, gmsgLocation, NULL, pPlayerLoop->edict() ); + WRITE_BYTE( ENTINDEX(pPlayer->edict()) ); + WRITE_COORD( pPlayer->pev->origin[0]); + WRITE_COORD( pPlayer->pev->origin[1]); + WRITE_COORD( pPlayer->pev->origin[2]); + MESSAGE_END(); + } + + if (bSendDeathLocation) + { + MESSAGE_BEGIN( MSG_ONE, gmsgLocation, NULL, pPlayerLoop->edict() ); + WRITE_BYTE( ENTINDEX(pPlayer->edict()) ); + WRITE_COORD( pPlayer->GetKilledPosition()[0]); + WRITE_COORD( pPlayer->GetKilledPosition()[1]); + WRITE_COORD( pPlayer->GetKilledPosition()[2]); + MESSAGE_END(); + } +#endif + + //Ok to send text. + MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, pPlayerLoop->edict() ); + WRITE_BYTE( pPlayer->entindex() ); + WRITE_STRING( UTIL_VarArgs("%s\n", szText) ); + MESSAGE_END(); + } + } + } + else + { + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayerLoop->IsNetClient()) + { + // can the receiver hear the sender? or has he muted him? + if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( pPlayerLoop, pPlayer ) ) + continue; + + if (Close == Type && pPlayer != pPlayerLoop) + { + //Check if team m8 is close enough. + vec3_t vDist = pPlayerLoop->pev->origin - pPlayer->pev->origin; + if (vDist .Length () > 700) + continue; + } + + // for team or close we only say to our own team + if ( (Team == Type || Close == Type ) && + g_pGameRules->PlayerRelationship(pPlayerLoop, pPlayer) != GR_TEAMMATE && + pPlayer != pPlayerLoop) + continue; + + //Dont let spectators read your team talk. + if ( (Team == Type || Close == Type ) && pPlayerLoop->IsSpectator()) + continue; + +#ifndef AG_NO_CLIENT_DLL + if (bSendLocation) + { + MESSAGE_BEGIN( MSG_ONE, gmsgLocation, NULL, pPlayerLoop->edict() ); + WRITE_BYTE( ENTINDEX(pPlayer->edict()) ); + WRITE_COORD( pPlayer->pev->origin[0]); + WRITE_COORD( pPlayer->pev->origin[1]); + WRITE_COORD( pPlayer->pev->origin[2]); + MESSAGE_END(); + } + + if (bSendDeathLocation) + { + MESSAGE_BEGIN( MSG_ONE, gmsgLocation, NULL, pPlayerLoop->edict() ); + WRITE_BYTE( ENTINDEX(pPlayer->edict()) ); + WRITE_COORD( pPlayer->GetKilledPosition()[0]); + WRITE_COORD( pPlayer->GetKilledPosition()[1]); + WRITE_COORD( pPlayer->GetKilledPosition()[2]); + MESSAGE_END(); + } +#endif + + //Ok to send text. + MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, pPlayerLoop->edict() ); + WRITE_BYTE( pPlayer->entindex() ); + WRITE_STRING( UTIL_VarArgs("%s\n", szText) ); + MESSAGE_END(); + } + } + } + + // echo to server console + AgConsole(szText); +} + +void AgClient::Play(CBasePlayer* pPlayer, say_type Type, const char* pszWave) +{ + //Check for flooding if spectator + if (pPlayer->IsSpectator() && pPlayer->FloodCheck() || !g_pGameRules->IsTeamplay() || pPlayer->FloodSound()) + return; + + //Play sound to teammates. + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + // for team or close we only play to our own team + if ( (Team == Type || Close == Type) && !(pPlayerLoop == pPlayer || g_pGameRules->PlayerRelationship( pPlayer, pPlayerLoop ) == GR_TEAMMATE)) + continue; + + vec3_t vDist = pPlayerLoop->pev->origin - pPlayer->pev->origin; + if (Type == Close && vDist.Length () > 700) + continue; + + //Dont let spectators hear your team talk. + if ( (Team == Type || Close == Type ) && pPlayerLoop->IsSpectator()) + continue; + +#ifdef AG_NO_CLIENT_DLL + AgSound(pPlayerLoop, pszWave); +#else + MESSAGE_BEGIN( MSG_ONE_UNRELIABLE, gmsgPlaySound, NULL, pPlayerLoop->pev ); + WRITE_BYTE( pPlayer->entindex()); + WRITE_COORD( pPlayer->pev->origin[0]); + WRITE_COORD( pPlayer->pev->origin[1]); + WRITE_COORD( pPlayer->pev->origin[2]); + WRITE_STRING(pszWave); + MESSAGE_END(); +#endif + + /* + MESSAGE_BEGIN( MSG_ONE, gmsgPlaySound, NULL, pPlayerLoop->pev ); + WRITE_SHORT( pPlayer->entindex()); + WRITE_STRING(CMD_ARGV(1)); + MESSAGE_END(); + */ + } +} +//-- Martin Webrant diff --git a/dlls/aghl/agclient.h b/dlls/aghl/agclient.h new file mode 100644 index 00000000..44f1170c --- /dev/null +++ b/dlls/aghl/agclient.h @@ -0,0 +1,25 @@ +//++ BulliT + +#if !defined(AFX_AGCLIENT_H__F5D30437_55C8_4113_B813_61931ACAC42B__INCLUDED_) +#define AFX_AGCLIENT_H__F5D30437_55C8_4113_B813_61931ACAC42B__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgClient +{ +public: + AgClient(); + virtual ~AgClient(); + + enum say_type { All, Team, Close }; + bool HandleCommand(CBasePlayer* pPlayer); + void Say(CBasePlayer* pPlayer, say_type Type ); + void Play(CBasePlayer* pPlayer, say_type Type, const char* pszWave); + +}; + +#endif // !defined(AFX_AGCLIENT_H__F5D30437_55C8_4113_B813_61931ACAC42B__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agcommand.cpp b/dlls/aghl/agcommand.cpp new file mode 100644 index 00000000..a7896478 --- /dev/null +++ b/dlls/aghl/agcommand.cpp @@ -0,0 +1,553 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "gamerules.h" +#include "agcommand.h" +#include "agadmincache.h" +#include "agglobal.h" + +DLL_GLOBAL AgCommand Command; //The one and only +FILE_GLOBAL CBasePlayer* s_pAdmin = NULL; + + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +struct COMMANDS +{ + char szCommand[18]; + void (*pServer)(void); + void (*pClient)(CBasePlayer* pPlayer); + char szDescription[64]; +}; + + +void addadmin_client(CBasePlayer* pPlayer) +{ + if (3 == CMD_ARGC()) + Command.AddAdmin(CMD_ARGV(1),CMD_ARGV(2),pPlayer); +} + +void addadmin(void) +{ + addadmin_client(NULL); +} + +void listadmins_client(CBasePlayer* pPlayer) +{ + if (1 == CMD_ARGC()) + Command.ListAdmins(pPlayer); +} + +void listadmins(void) +{ + listadmins_client(NULL); +} + +void deladmin_client(CBasePlayer* pPlayer) +{ + if (2 == CMD_ARGC()) + Command.DelAdmin(CMD_ARGV(1),pPlayer); +} + +void deladmin(void) +{ + deladmin_client(NULL); +} + +void allow_client(CBasePlayer* pPlayer) +{ + if (2 == CMD_ARGC()) + Command.Allow(CMD_ARGV(1),pPlayer); + else if (1 == CMD_ARGC()) + Command.Allow("",pPlayer); +} + +void allow(void) +{ + allow_client(NULL); +} + +void agabort_client(CBasePlayer* pPlayer) +{ + Command.Abort(pPlayer); +} + +void agabort(void) +{ + agabort_client(NULL); +} + + +void start_client(CBasePlayer* pPlayer) +{ + if (1 == CMD_ARGC()) + Command.Start(""); + if (2 <= CMD_ARGC()) + Command.Start(CMD_ARGS()); +} + +void start(void) +{ + start_client(NULL); +} + +void pause_client(CBasePlayer* pPlayer) +{ + Command.Pause(pPlayer); +} + +void agpause(void) +{ + pause_client(NULL); +} + +void kick_client(CBasePlayer* pPlayer) +{ + if (2 == CMD_ARGC()) + Command.Kick(CMD_ARGV(1)); +} + +void map_client(CBasePlayer* pPlayer) +{ + if (2 == CMD_ARGC()) + Command.Map(CMD_ARGV(1)); +} + +void help_client(CBasePlayer* pPlayer) +{ + if (1 == CMD_ARGC()) + Command.Help(pPlayer); +} + +void help(void) +{ + help_client(NULL); +} + +void nextmap_client(CBasePlayer* pPlayer) +{ + if (2 == CMD_ARGC()) + Command.NextMap(CMD_ARGV(1),pPlayer); + else if (1 == CMD_ARGC()) + Command.NextMap("",pPlayer); +} + +void nextmap(void) +{ + nextmap_client(NULL); + +} + +void spectator_client(CBasePlayer* pPlayer) +{ + if (2 == CMD_ARGC()) + Command.Spectator(pPlayer,CMD_ARGV(1)); +} + +void spectator(void) +{ + spectator_client(NULL); +} + + +void teamup_client(CBasePlayer* pPlayer) +{ + if (3 == CMD_ARGC()) + Command.TeamUp(pPlayer,CMD_ARGV(1),CMD_ARGV(2)); +} + +void teamup(void) +{ + teamup_client(NULL); +} + +void variables_client(CBasePlayer* pPlayer) +{ + if (1 == CMD_ARGC()) + Command.Variables(pPlayer); +} + +void variables(void) +{ + variables_client(NULL); +} + + +void exec_client(CBasePlayer* pPlayer) +{ + if (2 == CMD_ARGC()) + Command.Exec(CMD_ARGV(1),pPlayer); +} + +void exec(void) +{ + exec_client(NULL); +} + +FILE_GLOBAL COMMANDS s_Commands[]= +{ + "agaddadmin",addadmin,NULL,"agaddadmin - Add new admin.", + "aglistadmins",listadmins,NULL,"aglistadmins - List all admins.", + "agdeladmin",deladmin,NULL,"agdeladmin - Delete existing admin.", + + "agforcespectator",spectator,spectator_client,"agforcespectator Force a player into specmode", + "agforceteamup",teamup,teamup_client,"agforceteamup team - Force a player into a team", + "agkick",NULL,kick_client,"agkick - Kick a player.", + "agmap",NULL,map_client,"agmap - Change level.", + "agnextmap",nextmap,nextmap_client,"agnextmap - Set next level.", + "agexec",exec,exec_client,"agexec - Executes a server configuration.", + + "agstart",start,start_client,"agstart - Start a match.", + "agabort",agabort,agabort_client,"agabort - Abort a match.", + "agallow",allow,allow_client,"agallow - Allow a player into the match.", + "agpause",agpause,pause_client,"agpause - Pause server.", + "help",help,help_client,"help - List commands.", + "variables",variables,variables_client,"variables - Server variable list.", +}; + + +FILE_GLOBAL char* s_szVars[] = +{ + "sv_ag_max_spectators <0-32> - Max spectators allowed.", + "sv_ag_spec_enable_disable<0/1> - Allow players to disable tracking in spectator.", + "sv_ag_pure <0/1> - 0 spike check and simple variable checks, 1 harder variable check.", + "sv_ag_match_running <0/1> - Tells if a match is running.", + "sv_ag_allow_vote <0/1> - Allow any vote.", + "sv_ag_vote_setting <0/1> - Vote ag_xxx and mp_xxx settings.", + "sv_ag_vote_gamemode <0/1> - Allow gamemode switching.", + "sv_ag_vote_kick <0/1> - Allow voting a kick.", + "sv_ag_vote_admin <0/1> - Allow voting an admin.", + "sv_ag_vote_map <0/1> - Allow map voting.", + "sv_ag_vote_mp_timelimit_low <0-999> - Lowest timelimit to vote on.", + "sv_ag_vote_mp_timelimit_high <0-999> - Highest timelimit to vote on.", + "sv_ag_vote_mp_fraglimit_low <0-999> - Lowest fraglimit to vote on.", + "sv_ag_vote_mp_fraglimit_high <0-999> - Highest fraglimit to vote on.", + "sv_ag_floodmsgs <4> - Flood messages to tolerate. 0 will deactive it.", + "sv_ag_floodpersecond <4> - Flood messages per second.", + "sv_ag_floodwaitdelay <10> - Flood penalty timer.", + "sv_ag_show_gibs <0/1> - Show dead bodies.", + "sv_ag_spawn_volume <0-1> - The spawn sound volume.", + "sv_ag_player_id <5> - Player id show to other players. In seconds.", + "sv_ag_auto_admin <1> - Give auto admin to admins in admin list.", + "sv_ag_lj_timer <0-999> - Countdown seconds for long jump. 0 turns it off.", + "sv_ag_wallgauss <0/1> - Wallgauss on/off. On is for the weak :)", + "sv_ag_headshot <1-3> - Set power of headshot. Normally 3.", + "sv_ag_blastradius <1> - Blast radius for explosions. Normally 1", + "sv_ag_allowed_gamemodes - Allowed gamemodes, could be any off ffa;tdm;arena;arcade;sgbow;instagib", +}; + +AgCommand::AgCommand() +{ + +} + +AgCommand::~AgCommand() +{ + +} + +void AgCommand::Init() +{ + for (int i = 0; i < sizeof(s_Commands)/sizeof(s_Commands[0]); i++) + { + if (s_Commands[i].pServer) + ADD_SERVER_COMMAND(s_Commands[i].szCommand,s_Commands[i].pServer); + } +} + +bool AgCommand::HandleCommand(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return false; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return false; + + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules || 0 == CMD_ARGC()) + return false; + + if (pPlayer->IsAdmin()) + { + //Server command + for (int i = 0; i < sizeof(s_Commands)/sizeof(s_Commands[0]); i++) + { + if (s_Commands[i].pClient) + { + if (FStrEq(s_Commands[i].szCommand,CMD_ARGV(0))) + { + s_Commands[i].pClient(pPlayer); + if (FStrEq(s_Commands[i].szCommand,"help")) + return false; + else + return true; + } + } + else if (s_Commands[i].pServer) + { + if (FStrEq(s_Commands[i].szCommand,CMD_ARGV(0))) + { + s_Commands[i].pServer(); + return true; + } + } + } + + if (1 == CMD_ARGC()) + { + if (GameMode.IsGamemode(CMD_ARGV(0))) + { + if (!GameMode.IsAllowedGamemode(CMD_ARGV(0),pPlayer)) + { + AgConsole("Gamemode not allowed by server admin.",pPlayer); + return true; + } + + GameMode.Gamemode(CMD_ARGV(0)); + return true; + } + } + + + if (0 < CMD_ARGC() && + (0 == strnicmp(CMD_ARGV(0),"ag_spectalk",11) + ||0 == strnicmp(CMD_ARGV(0),"mp_timelimit",12) + ||0 == strnicmp(CMD_ARGV(0),"ag_gauss_fix",12) + ||0 == strnicmp(CMD_ARGV(0),"ag_rpg_fix",10) + ||0 == strnicmp(CMD_ARGV(0),"mp_fraglimit",12) + ||0 == strnicmp(CMD_ARGV(0),"mp_friendlyfire",15) + ||0 == strnicmp(CMD_ARGV(0),"mp_weaponstay",13) + )) + { + if (1 == CMD_ARGC()) + Setting(CMD_ARGV(0), "", pPlayer); + else if (2 == CMD_ARGC()) + Setting(CMD_ARGV(0), CMD_ARGV(1), pPlayer); + return true; + } + } + return false; +} + +void AgCommand::AddAdmin(const AgString& sAdmin, const AgString& sPassword, CBasePlayer* pPlayer) +{ + AdminCache.AddAdmin(sAdmin,sPassword,pPlayer); +} + +void AgCommand::ListAdmins(CBasePlayer* pPlayer) +{ + AdminCache.ListAdmins(pPlayer); +} + +void AgCommand::DelAdmin(const AgString& sAdmin,CBasePlayer* pPlayer) +{ + AdminCache.DelAdmin(sAdmin,pPlayer); +} + + + +void AgCommand::Allow(const AgString& sPlayerIdOrName,CBasePlayer* pPlayer) +{ + if (!g_pGameRules) + return; + + if (ARENA == AgGametype() || LMS == AgGametype()) + { + AgConsole("Not allowed.",pPlayer); + return; + } + + //Get player. + CBasePlayer* pPlayerLoop = AgPlayerByName(sPlayerIdOrName); + if (!pPlayerLoop && pPlayer && 0 == sPlayerIdOrName.size()) + pPlayerLoop = pPlayer; + + if (pPlayerLoop) + { + g_pGameRules->m_Match.Allow(pPlayerLoop); + } + else + { + AgConsole("No such player exist on server.",pPlayer); + } +} + +void AgCommand::Abort(CBasePlayer* pPlayer) +{ + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + + if (LMS == AgGametype() || ARENA == AgGametype()) + { + AgConsole("Abort is not allowed in this gamemode.",pPlayer); + return; + } + + g_pGameRules->m_Match.Abort(); +} + +void AgCommand::Start(const AgString& sSpawn) +{ + if (LMS == AgGametype() || ARENA == AgGametype()) + { + AgConsole("Start is not allowed in this gamemode."); + return; + } + + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + + + g_pGameRules->Start(sSpawn); +} + +void AgCommand::Pause(CBasePlayer* pPlayer) +{ + if (LMS == AgGametype() || ARENA == AgGametype()) + { + AgConsole("Pause is not allowed in this gamemode."); + return; + } + + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + + g_pGameRules->m_Timeout.TogglePause(); +} + +void AgCommand::Kick(const AgString& sPlayerIdOrName) +{ + if (32 < sPlayerIdOrName.size()) + return; + + char szCommand[128]; + sprintf(szCommand,"kick %s\n",sPlayerIdOrName.c_str()); + SERVER_COMMAND( szCommand ); +} + +void AgCommand::Map(const AgString& sMap) +{ + if (32 < sMap.size() || !g_pGameRules) + return; + + g_pGameRules->m_Settings.Changelevel(sMap); +} + +void AgCommand::NextMap(const AgString& sMap, CBasePlayer* pPlayer) +{ + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + + if (sMap.size() && 32 > sMap.size()) + { + g_pGameRules->m_Settings.SetNextLevel(sMap); + } + else + { + char szSetting[64]; + sprintf(szSetting,"ag_nextmap is \"%s\"",g_pGameRules->m_Settings.GetNextLevel().c_str()); + AgConsole(szSetting,pPlayer); + } +} + + +void AgCommand::Setting(const AgString& sSetting, const AgString& sValue, CBasePlayer* pPlayer) +{ + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + + if (sValue.size()) + { + g_pGameRules->m_Settings.AdminSetting(sSetting,sValue); + } + else + { + char szSetting[64]; + sprintf(szSetting,"%s is \"%s\"",sSetting.c_str(),CVAR_GET_STRING(sSetting.c_str())); + AgConsole(szSetting,pPlayer); + } +} + +void AgCommand::Help(CBasePlayer* pPlayer) +{ + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + + for (int i = 0; i < sizeof(s_Commands)/sizeof(s_Commands[0]); i++) + { + if (!pPlayer && s_Commands[i].pServer) + AgConsole(s_Commands[i].szDescription,pPlayer); + else if (pPlayer + && 0 == strcmp(s_Commands[i].szCommand,"agaddadmin") + && 0 == strcmp(s_Commands[i].szCommand,"aglistadmins") + && 0 == strcmp(s_Commands[i].szCommand,"agdeladmin")) + AgConsole(s_Commands[i].szDescription,pPlayer); + } + + GameMode.Help(pPlayer); +} + + +void AgCommand::Variables(CBasePlayer* pPlayer) +{ + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + + for (int i = 0; i < sizeof(s_szVars)/sizeof(s_szVars[0]); i++) + AgConsole(s_szVars[i],pPlayer); +} + +void AgCommand::TeamUp(CBasePlayer* pPlayer, const AgString& sPlayerIdOrName, const AgString& sTeam) +{ + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + if (!g_pGameRules->IsTeamplay()) + return; + + CBasePlayer* pTeamUpPlayer = AgPlayerByName(sPlayerIdOrName); + if (pTeamUpPlayer) + pTeamUpPlayer->ChangeTeam(sTeam.c_str(),true); +} + +void AgCommand::Spectator(CBasePlayer* pPlayer, const AgString& sPlayerIdOrName) +{ + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + if (!g_pGameRules->IsTeamplay()) + return; + + CBasePlayer* pSpectatorPlayer = AgPlayerByName(sPlayerIdOrName); + if (pSpectatorPlayer) + pSpectatorPlayer->Spectate_Start(); +} + + +void AgCommand::Exec(const AgString& sExec, CBasePlayer* pPlayer) +{ + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules) + return; + + char szCommand[128]; + sprintf(szCommand,"exec %s\n",sExec.c_str()); + SERVER_COMMAND( szCommand ); + SERVER_EXECUTE(); +} + +//-- Martin Webrant diff --git a/dlls/aghl/agcommand.h b/dlls/aghl/agcommand.h new file mode 100644 index 00000000..cdafe515 --- /dev/null +++ b/dlls/aghl/agcommand.h @@ -0,0 +1,50 @@ +//++ BulliT + +#if !defined(AFX_AGCOMMANDS_H__B6D8EF5B_9423_4422_B935_1D71B6146DCA__INCLUDED_) +#define AFX_AGCOMMANDS_H__B6D8EF5B_9423_4422_B935_1D71B6146DCA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "agglobal.h" + + +class AgCommand +{ +public: + AgCommand(); + virtual ~AgCommand(); + + static void Init(); + + static bool HandleCommand(CBasePlayer* pPlayer); + + static void AddAdmin(const AgString& sAdmin, const AgString& sPassword, CBasePlayer* pPlayer = NULL); + static void ListAdmins(CBasePlayer* pPlayer = NULL); + static void DelAdmin(const AgString& sAdmin,CBasePlayer* pPlayer = NULL); + + static void Start(const AgString& sSpawn); + static void Allow(const AgString& sPlayerIdOrName,CBasePlayer* pPlayer = NULL); + static void Abort(CBasePlayer* pPlayer); + static void Pause(CBasePlayer* pPlayer); + + static void Kick(const AgString& sPlayerIdOrName); + static void Map(const AgString& sMap); + static void NextMap(const AgString& sMap, CBasePlayer* pPlayer = NULL); + + static void Setting(const AgString& sSetting, const AgString& sValue, CBasePlayer* pPlayer = NULL); + + static void Help(CBasePlayer* pPlayer); + static void Variables(CBasePlayer* pPlayer); + + static void TeamUp(CBasePlayer* pPlayer, const AgString& sPlayerIdOrName, const AgString& sTeam); + static void Spectator(CBasePlayer* pPlayer, const AgString& sPlayerIdOrName); + + static void Exec(const AgString& sExec, CBasePlayer* pPlayer); +}; + +extern DLL_GLOBAL AgCommand Command; + +#endif // !defined(AFX_AGCOMMANDS_H__B6D8EF5B_9423_4422_B935_1D71B6146DCA__INCLUDED_) +//-- Martin Webrant diff --git a/dlls/aghl/agctf.cpp b/dlls/aghl/agctf.cpp new file mode 100644 index 00000000..9d834a45 --- /dev/null +++ b/dlls/aghl/agctf.cpp @@ -0,0 +1,1511 @@ +//++ BulliT - with ideas from http://www.planethalflife.com/whenitsdone/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" + +#include "aggamerules.h" +#include "agglobal.h" +#include "agctf.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +extern int gmsgCTFSound; +extern int gmsgCTFFlag; +extern int gmsgCountdown; + +enum CTFSound +{ + YouHaveFlag = 0, + TeamHaveFlag, + EnemyHaveFlag, + BlueFlagReturned, + RedFlagReturned, + BlueScores, + RedScores, + BlueFlagStolen, + RedFlagStolen, + //not used... + BlueLeads, + RedLeads, + TeamsTied, + SuddenDeath, + Stolen, + Capture, +}; + +FILE_GLOBAL int s_iTeam1Captures; +FILE_GLOBAL int s_iTeam2Captures; + +DLL_GLOBAL bool g_bTeam1FlagStolen; +DLL_GLOBAL bool g_bTeam2FlagStolen; + +DLL_GLOBAL bool g_bTeam1FlagLost; +DLL_GLOBAL bool g_bTeam2FlagLost; +FILE_GLOBAL int s_iPlayerFlag1; +FILE_GLOBAL int s_iPlayerFlag2; + +extern int gmsgTeamScore; + +AgCTF::AgCTF() +{ + m_iTeam1Captures = 0; + m_iTeam2Captures = 0; + s_iTeam1Captures = s_iTeam2Captures = 0; + g_bTeam1FlagStolen = g_bTeam2FlagStolen = false; + g_bTeam1FlagLost = g_bTeam2FlagLost = false; + s_iPlayerFlag1 = 0; + s_iPlayerFlag2 = 0; + m_iPlayerFlag1 = 0; + m_iPlayerFlag2= 0; + m_fNextCountdown = 0.0; + m_fMatchStart = 0.0; + + if (ag_ctf_roundbased.value) + m_Status = Waiting; + else + m_Status = Playing; +} + +AgCTF::~AgCTF() +{ + +} + +void AgCTF::PlayerInitHud(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev ); + WRITE_STRING( CTF_TEAM1_NAME); + WRITE_SHORT( m_iTeam1Captures ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev ); + WRITE_STRING( CTF_TEAM2_NAME); + WRITE_SHORT( m_iTeam2Captures ); + WRITE_SHORT( 0 ); + MESSAGE_END(); +} + +bool AgCTF::CaptureLimit() +{ + if (ag_ctf_capture_limit.value > 1 + && ( s_iTeam1Captures == ag_ctf_capture_limit.value + ||s_iTeam2Captures == ag_ctf_capture_limit.value)) + return true; + + return false; +} + +void AgCTF::SendCaptures(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev ); + WRITE_STRING( CTF_TEAM1_NAME); + WRITE_SHORT( s_iTeam1Captures ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev ); + WRITE_STRING( CTF_TEAM2_NAME); + WRITE_SHORT( s_iTeam2Captures ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + +} + +void AgCTF::ResetScore(bool bResetCaptures) +{ + m_iTeam1Captures = -1; + m_iTeam2Captures = -1; + s_iTeam1Captures = s_iTeam2Captures = 0; + m_Status = Playing; + + if (bResetCaptures) + ResetCaptures(); +} + +void AgCTF::ResetCaptures() +{ + g_bTeam1FlagStolen = g_bTeam2FlagStolen = false; + + //Reset flag carrier. + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + pPlayerLoop->m_bFlagTeam1 = false; + pPlayerLoop->m_bFlagTeam2 = false; + } + } + + //Remove carried flag + CBaseEntity* pEntity = NULL; + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "carried_flag_team1" )) != NULL) + UTIL_Remove(pEntity); + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "carried_flag_team2" )) != NULL) + UTIL_Remove(pEntity); + + //Remove dropped flag + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "item_flag_team1" )) != NULL) + { + if (((AgCTFFlag*)pEntity)->m_bDropped) + UTIL_Remove(pEntity); + } + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "item_flag_team2" )) != NULL) + { + if (((AgCTFFlag*)pEntity)->m_bDropped) + UTIL_Remove(pEntity); + } + + //Reset base flag + AgCTFFlag::ResetFlag(CTF_TEAM1_NAME); + AgCTFFlag::ResetFlag(CTF_TEAM2_NAME); +} + +void AgCTF::Think() +{ + if (!g_pGameRules) + return; + + if (m_iTeam1Captures != s_iTeam1Captures + ||m_iTeam2Captures != s_iTeam2Captures) + { + m_iTeam1Captures = s_iTeam1Captures; + + //Send new team score to all clients. + MESSAGE_BEGIN( MSG_ALL, gmsgTeamScore ); + WRITE_STRING( CTF_TEAM1_NAME); + WRITE_SHORT( s_iTeam1Captures ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + + m_iTeam2Captures = s_iTeam2Captures; + + //Send new team score to all clients. + MESSAGE_BEGIN( MSG_ALL, gmsgTeamScore ); + WRITE_STRING( CTF_TEAM2_NAME); + WRITE_SHORT( s_iTeam2Captures ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + } + + if (m_iPlayerFlag1 != s_iPlayerFlag1 + ||m_iPlayerFlag2 != s_iPlayerFlag2) + { + m_iPlayerFlag1 = s_iPlayerFlag1; + m_iPlayerFlag2 = s_iPlayerFlag2; + + //Send new flag status to all clients. + MESSAGE_BEGIN( MSG_ALL, gmsgCTFFlag ); + WRITE_BYTE( m_iPlayerFlag1 ); + WRITE_BYTE( m_iPlayerFlag2 ); + MESSAGE_END(); + } + + m_FileItemCache.Init(); + + RoundBasedThink(); +} + +void AgCTF::RoundBasedThink() +{ + //We only update status once every second. + if (m_fNextCountdown > gpGlobals->time) + return; + m_fNextCountdown = gpGlobals->time + 1.0; + + //Handle the status + if (Waiting == m_Status) + { + g_bPaused = true; + m_Status = Countdown; + m_fMatchStart = gpGlobals->time + 8.0; + m_fNextCountdown = gpGlobals->time + 3.0; + + //Write waiting message + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( 50 ); + WRITE_BYTE( 1 ); + WRITE_STRING( m_sWinner.c_str() ); + WRITE_STRING( "" ); + MESSAGE_END(); + } + else if (Countdown == m_Status) + { + if (m_fMatchStart < gpGlobals->time) + { + //Clear out the map + AgResetMap(); + + //Reset CTF items + ResetCaptures(); + + m_Status = Spawning; + m_sWinner = ""; + + //Time to start playing. + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayerLoop->m_bReady) + { + if (!pPlayerLoop->IsSpectator()) + pPlayerLoop->RespawnMatch(); + } + } + + m_Status = Playing; + + //Stop countdown + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( -1 ); + WRITE_BYTE( 0 ); + WRITE_STRING( "" ); + WRITE_STRING( "" ); + MESSAGE_END(); + + g_bPaused = false; + } + else + { + //Write countdown message. + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( (int)(m_fMatchStart - gpGlobals->time) ); + WRITE_BYTE( 1 ); + WRITE_STRING( "" ); + WRITE_STRING( "" ); + MESSAGE_END(); + } + } +} + +void AgCTF::RoundOver(const char* pszWinner) +{ + m_sWinner = pszWinner; + m_Status = Waiting; +} + + +void AgCTF::ClientConnected(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; +} + + +void AgCTF::ClientDisconnected(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + PlayerDropFlag(pPlayer); +} + +void AgCTF::PlayerKilled(CBasePlayer* pPlayer,entvars_t *pKiller) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + CBaseEntity* pKillerBE = CBaseEntity::Instance(pKiller); + if (pKillerBE && CLASS_PLAYER == pKillerBE->Classify()) + { + CBasePlayer* pKillerPlayer = ((CBasePlayer*)pKillerBE); + AddPointsForKill(pKillerPlayer,pPlayer); + } + + bool bReturnDirectly = (0 == strcmp(STRING(pKiller->classname),"trigger_hurt")); + + if (bReturnDirectly) + { + if (pPlayer->m_bFlagTeam1) + { + CBaseEntity* pEntity = NULL; + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "carried_flag_team1" )) != NULL) + UTIL_Remove(pEntity); + pPlayer->m_bFlagTeam1 = false; + AgCTFFlag::ResetFlag(CTF_TEAM1_NAME); + + char szText[201]; + sprintf(szText, "%s flag returned!", CTF_TEAM1_NAME); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( BlueFlagReturned ); + MESSAGE_END(); + } + else if (pPlayer->m_bFlagTeam2) + { + CBaseEntity* pEntity = NULL; + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "carried_flag_team2" )) != NULL) + UTIL_Remove(pEntity); + pPlayer->m_bFlagTeam2 = false; + AgCTFFlag::ResetFlag(CTF_TEAM2_NAME); + + char szText[201]; + sprintf(szText, "%s flag returned!", CTF_TEAM2_NAME); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( RedFlagReturned ); + MESSAGE_END(); + } + } + else + PlayerDropFlag(pPlayer); +} + +void AgCTF::AddPointsForKill(CBasePlayer *pAttacker, CBasePlayer *pKilled) +{ + if ( pAttacker != pKilled && g_pGameRules->PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) + return; //Killed his team m8. + + if (FStrEq(CTF_TEAM1_NAME, pKilled->m_szTeamName) && pKilled->m_bFlagTeam2 + ||FStrEq(CTF_TEAM2_NAME, pKilled->m_szTeamName) && pKilled->m_bFlagTeam1) + { + //He killed the flag carrier. + pAttacker->AddPoints(ag_ctf_carrierkillpoints.value, TRUE); + } + + //Check if he is 192 units within his own flag (defending) + edict_t* pFind = NULL; + if (FStrEq(CTF_TEAM1_NAME, pAttacker->m_szTeamName)) + pFind = FIND_ENTITY_BY_CLASSNAME(NULL,"item_flag_team1"); + else if (FStrEq(CTF_TEAM2_NAME, pAttacker->m_szTeamName)) + pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "item_flag_team2" ); + if (pFind) + { + Vector vtFlag = pFind->v.origin; + Vector vtPlayer = pKilled->pev->origin; + float fDistance = (vtFlag - vtPlayer).Length(); + if (fDistance < 192) + //Add points for defending. + pAttacker->AddPoints(ag_ctf_defendpoints.value, TRUE); + } +} + + +void AgCTF::PlayerDropFlag(CBasePlayer* pPlayer, bool bPlayerDrop) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + //When carrying a flag, drop it! + if (pPlayer->m_bFlagTeam1 || pPlayer->m_bFlagTeam2) + { + char szText [201]; + + CBaseEntity *pEnt = NULL; + + if (bPlayerDrop) + UTIL_MakeVectors ( pPlayer->pev->angles ); + + if (pPlayer->m_bFlagTeam1) + { + pEnt = CBaseEntity::Create( "item_flag_team1", bPlayerDrop? (pPlayer->pev->origin + gpGlobals->v_forward * 10) : pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); + sprintf(szText, "%s lost the %s flag!", STRING(pPlayer->pev->netname), CTF_TEAM1_NAME); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + g_bTeam1FlagLost = true; + } + else if (pPlayer->m_bFlagTeam2) + { + pEnt = CBaseEntity::Create( "item_flag_team2", bPlayerDrop? (pPlayer->pev->origin + gpGlobals->v_forward * 10) : pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); + sprintf(szText, "%s lost the %s flag!", STRING(pPlayer->pev->netname), CTF_TEAM2_NAME); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + g_bTeam2FlagLost = true; + } + + if (bPlayerDrop) + { + pEnt->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100; + pEnt->pev->angles.z = 0; + } + else + pEnt->pev->velocity = pPlayer->pev->velocity * 1.2; + pEnt->pev->angles.x = 0; + + AgCTFFlag *pFlag = (AgCTFFlag *)pEnt; + + if (bPlayerDrop) + pFlag->m_fNextTouch = gpGlobals->time + 0.5; //Gotta give the flag a bit of time to fly away from player before it can be picked up again. + pFlag->m_bDropped = true; + + pFlag->m_fNextReset = gpGlobals->time + ag_ctf_flag_resettime.value; + + pPlayer->m_bFlagTeam1 = false; + pPlayer->m_bFlagTeam2 = false; + } +} + + +extern int gmsgItemPickup; + +enum Flag_Animations +{ + ON_GROUND = 0, + NOT_CARRIED, + CARRIED, + WAVE_IDLE, + FLAG_POSITION +}; + +void AgCTFFlag::Spawn ( void ) +{ + m_fNextTouch = 0; + + Precache( ); + SET_MODEL(ENT(pev), "models/flag.mdl"); + + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_TRIGGER; + UTIL_SetOrigin( pev, pev->origin ); + UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); + + SetThink( &AgCTFFlag::Think ); + SetTouch( &AgCTFFlag::FlagTouch ); + + pev->nextthink = gpGlobals->time + 0.1; + + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + pev->skin = 1; + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + pev->skin = 2; + + m_bDropped = false; + + pev->sequence = NOT_CARRIED; + pev->framerate = 1.0; + + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + { + pev->rendercolor.x = 0; + pev->rendercolor.y = 0; + pev->rendercolor.z = 128; + } + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + { + pev->rendercolor.x = 128; + pev->rendercolor.y = 0; + pev->rendercolor.z = 0; + } + pev->renderamt = 50; + pev->renderfx = kRenderFxGlowShell; +} + +void AgCTFFlag::Precache( void ) +{ + PRECACHE_MODEL ("models/flag.mdl"); +} + +void AgCTFFlag::Capture(CBasePlayer *pPlayer, const char *m_szTeamName) +{ + char szText[201]; + + sprintf(szText, "%s captured the %s flag!", STRING(pPlayer->pev->netname), m_szTeamName); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + + //Give the player the points + pPlayer->AddPoints(ag_ctf_capturepoints.value, TRUE); + pPlayer->AddPointsToTeam(ag_ctf_teamcapturepoints.value, TRUE); + + //And give the team a capture + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + { + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( RedScores ); + MESSAGE_END(); + + s_iTeam2Captures++; + UTIL_LogPrintf("Team \"%s\" triggered \"Capture\" (%s \"%d\") (%s \"%d\")\n",CTF_TEAM2_NAME,CTF_TEAM1_NAME,s_iTeam1Captures,CTF_TEAM2_NAME,s_iTeam2Captures); + + if (ag_ctf_roundbased.value) + g_pGameRules->m_CTF.RoundOver(CTF_TEAM2_NAME); + } + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + { + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( BlueScores ); + MESSAGE_END(); + + s_iTeam1Captures++; + UTIL_LogPrintf("Team \"%s\" triggered \"Capture\" (%s \"%d\") (%s \"%d\")\n",CTF_TEAM1_NAME,CTF_TEAM1_NAME,s_iTeam1Captures,CTF_TEAM2_NAME,s_iTeam2Captures); + + if (ag_ctf_roundbased.value) + g_pGameRules->m_CTF.RoundOver(CTF_TEAM1_NAME); + } + + ResetFlag( m_szTeamName ); +} + +void AgCTFFlag::ResetFlag() +{ + AgCTFFlag::ResetFlag(m_szTeamName); + + char szText[201]; + sprintf(szText, "%s flag returned!", m_szTeamName); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + { + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( BlueFlagReturned ); + MESSAGE_END(); + } + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + { + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( RedFlagReturned ); + MESSAGE_END(); + } + + if (m_bDropped) + UTIL_Remove( this ); +} + +void AgCTFFlag::ResetFlag(const char *szTeamName) +{ + edict_t *pFind; + + if (FStrEq(CTF_TEAM1_NAME, szTeamName)) + { + pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "item_flag_team1" ); + g_bTeam1FlagStolen = false; + g_bTeam1FlagLost = false; + } + else if (FStrEq(CTF_TEAM2_NAME, szTeamName)) + { + pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "item_flag_team2" ); + g_bTeam2FlagStolen = false; + g_bTeam2FlagLost = false; + } + else + return; + + while ( !FNullEnt( pFind ) ) + { + CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); + AgCTFFlag *pFlag = (AgCTFFlag *)pEnt; + + pFlag->Materialize( ); + + if (FStrEq(CTF_TEAM1_NAME, szTeamName)) + pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "item_flag_team1" ); + else if (FStrEq(CTF_TEAM2_NAME, szTeamName)) + pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "item_flag_team2" ); + } +} + +void AgCTFFlag::FlagTouch( CBaseEntity *pOther ) +{ + if (m_fNextTouch > gpGlobals->time) + return; + + // if it's not a player, ignore + if ( !pOther->IsPlayer() ) + return; + + if ( !pOther->IsAlive() ) + return; + + + CBasePlayer *pPlayer = (CBasePlayer *)pOther; + + if (MyTouch( pPlayer )) + { + SUB_UseTargets( pOther, USE_TOGGLE, 0 ); + SetTouch( NULL ); + SetThink( NULL ); + + //if it's a dropped flag, remove. Else make it invisible + if (m_bDropped) + UTIL_Remove( this ); + else + pev->effects |= EF_NODRAW; + } +} + +void AgCTFFlag::Materialize( void ) +{ + if ( pev->effects & EF_NODRAW ) + { + // changing from invisible state to visible. + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); + pev->effects &= ~EF_NODRAW; + pev->effects |= EF_MUZZLEFLASH; + } + + SetTouch( &AgCTFFlag::FlagTouch ); + SetThink( &AgCTFFlag::Think ); +} + +BOOL AgCTFFlag::MyTouch( CBasePlayer *pPlayer ) +{ + char szText[201]; + + // Can only carry one flag and can not pickup own flag + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + { + //if client has other teams flag and it isn't a dropped flag, then there is a capture! + if ( pPlayer->m_bFlagTeam2 && !m_bDropped) + { + pPlayer->m_bFlagTeam2 = false; + + UTIL_SendDirectorMessage( pPlayer->edict(), this->edict(), 10 | DRC_FLAG_DRAMATIC); + Capture(pPlayer, CTF_TEAM2_NAME); + return FALSE; + } + else if ( pPlayer->m_bFlagTeam1 ) + { + return FALSE; + } + else if (FStrEq(pPlayer->m_szTeamName, CTF_TEAM1_NAME)) + { + //if dropped, return flag + if (m_bDropped) + { + ResetFlag(CTF_TEAM1_NAME); + sprintf(szText, "%s returned the %s flag!", STRING(pPlayer->pev->netname), m_szTeamName); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + UTIL_Remove( this ); + + pPlayer->AddPoints(ag_ctf_returnpoints.value, TRUE); + + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( BlueFlagReturned ); + MESSAGE_END(); + } + //but don't pick it up! + return FALSE; + } + } + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + { + //if client has other teams flag and it isn't a dropped flag, then there is a capture! + if ( pPlayer->m_bFlagTeam1 && !m_bDropped) + { + pPlayer->m_bFlagTeam1 = false; + + UTIL_SendDirectorMessage( pPlayer->edict(), this->edict(), 10 | DRC_FLAG_DRAMATIC); + Capture(pPlayer, CTF_TEAM1_NAME); + + return FALSE; + } + else if ( pPlayer->m_bFlagTeam2 ) + { + return FALSE; + } + else if (FStrEq(pPlayer->m_szTeamName, CTF_TEAM2_NAME)) + { + //if dropped, return flag + if (m_bDropped) + { + ResetFlag(CTF_TEAM2_NAME); + sprintf(szText, "%s returned the %s flag!", STRING(pPlayer->pev->netname), m_szTeamName); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + UTIL_Remove( this ); + + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( RedFlagReturned ); + MESSAGE_END(); + + pPlayer->AddPoints(ag_ctf_returnpoints.value, TRUE); + } + //but don't pick it up! + return FALSE; + } + } + + if ( ( pPlayer->pev->weapons & (1<m_bFlagTeam1 = true; + // player is now carrying the flag of team1, so give him the flag + + CBaseEntity *pEnt = CBaseEntity::Create( "carried_flag_team1", pev->origin, pev->angles, pPlayer->edict() ); + AgCTFPlayerFlag *pCarriedFlag = (AgCTFPlayerFlag *)pEnt; + pCarriedFlag->m_pOwner = pPlayer; + s_iPlayerFlag1 = pPlayer->entindex(); + + /* + //Glow blue + pCarriedFlag->pev->renderfx = kRenderFxGlowShell; + pCarriedFlag->pev->rendercolor = Vector( 0, 0, 255 ); // RGB + pCarriedFlag->pev->renderamt = 100; // Shell size + */ + } + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + { + pPlayer->m_bFlagTeam2 = true; + // player is now carrying the flag of team2, so give him the flag + CBaseEntity *pEnt = CBaseEntity::Create( "carried_flag_team2", pev->origin, pev->angles, pPlayer->edict() ); + AgCTFPlayerFlag *pCarriedFlag = (AgCTFPlayerFlag *)pEnt; + pCarriedFlag->m_pOwner = pPlayer; + s_iPlayerFlag2 = pPlayer->entindex(); + /* + //Glow red + pCarriedFlag->pev->renderfx = kRenderFxGlowShell; + pCarriedFlag->pev->rendercolor = Vector( 255, 0, 0 ); // RGB + pCarriedFlag->pev->renderamt = 100; // Shell size + */ + } + MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); + WRITE_STRING( STRING(pev->classname) ); + MESSAGE_END(); + + //Let all players hear and read that the flag is gone + char szText[201]; + + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + { + if (!g_bTeam1FlagLost) + pPlayer->AddPoints(ag_ctf_stealpoints.value, TRUE); + sprintf(szText, "%s got the %s flag!\n", STRING(pPlayer->pev->netname), CTF_TEAM1_NAME); + } + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + { + if (!g_bTeam2FlagLost) + pPlayer->AddPoints(ag_ctf_stealpoints.value, TRUE); + sprintf(szText, "%s got the %s flag!\n", STRING(pPlayer->pev->netname), CTF_TEAM2_NAME); + } + + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + if (pPlayer != pPlayerLoop) + { + if (pPlayerLoop->IsSpectator() || pPlayerLoop->IsProxy()) + { + if (!m_bDropped) + { + if (FStrEq(m_szTeamName, CTF_TEAM1_NAME)) + { + MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev ); + WRITE_BYTE(BlueFlagStolen); + MESSAGE_END(); + } + else + { + MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev ); + WRITE_BYTE(RedFlagStolen); + MESSAGE_END(); + } + } + } + else if (FStrEq(pPlayerLoop->m_szTeamName, m_szTeamName)) + { + MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev ); + WRITE_BYTE(EnemyHaveFlag); + MESSAGE_END(); + } + else + { + MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev ); + WRITE_BYTE(TeamHaveFlag); + MESSAGE_END(); + } + } + else + { + MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev ); + WRITE_BYTE(YouHaveFlag); + MESSAGE_END(); + } + } + } + + int iPowerUp = 0; + + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + { + g_bTeam1FlagStolen = true; + g_bTeam1FlagLost = false; + + + //Glow red + pPlayer->pev->renderfx = kRenderFxGlowShell; + pPlayer->pev->rendercolor = Vector( 128, 0, 0 ); // RGB + pPlayer->pev->renderamt = 50; // Shell size + + iPowerUp = 2; + } + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + { + g_bTeam2FlagStolen = true; + g_bTeam2FlagLost = false; + + //Glow blue + pPlayer->pev->renderfx = kRenderFxGlowShell; + pPlayer->pev->rendercolor = Vector( 0, 0, 128 ); // RGB + pPlayer->pev->renderamt = 50; // Shell size + + iPowerUp = 2; + } + + UTIL_SendDirectorMessage( pPlayer->edict(), this->edict(), 8 | DRC_FLAG_DRAMATIC); + + return TRUE; + } + return FALSE; +} + +void AgCTFFlag::Think( void ) +{ + if (m_bDropped && m_fNextReset <= gpGlobals->time) + { + //Let all players know that the flag has been returned + char szText[201]; + + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + { + sprintf(szText, "The %s flag has returned.\n", CTF_TEAM1_NAME); + ResetFlag(CTF_TEAM1_NAME); + + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( BlueFlagReturned ); + MESSAGE_END(); + } + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + { + sprintf(szText, "The %s flag has returned.\n", CTF_TEAM2_NAME); + ResetFlag(CTF_TEAM2_NAME); + + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( RedFlagReturned ); + MESSAGE_END(); + } + + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + UTIL_Remove( this ); + return; + } + pev->frame += pev->framerate; + if (pev->frame < 0.0 || pev->frame >= 256.0) + { + pev->frame -= (int)(pev->frame / 256.0) * 256.0; + } + pev->nextthink = gpGlobals->time + 0.1; +} + +class AgCTFFlagTeam1 : public AgCTFFlag +{ + void Spawn( void ) + { + pev->classname = MAKE_STRING("item_flag_team1"); //CCTF map compatibility hack + strcpy( m_szTeamName, CTF_TEAM1_NAME ); + + AgCTFFlag::Spawn( ); + } +}; + +#ifndef AG_NO_CLIENT_DLL +LINK_ENTITY_TO_CLASS( item_flag_team1, AgCTFFlagTeam1 ); +LINK_ENTITY_TO_CLASS( ctf_blueflag, AgCTFFlagTeam1 ); //CCTF map compatibility hack +#endif + +class AgCTFFlagTeam2 : public AgCTFFlag +{ + void Spawn( void ) + { + pev->classname = MAKE_STRING("item_flag_team2"); //CCTF map compatibility hack + strcpy( m_szTeamName, CTF_TEAM2_NAME ); + + AgCTFFlag::Spawn( ); + } +}; + +#ifndef AG_NO_CLIENT_DLL +LINK_ENTITY_TO_CLASS( item_flag_team2, AgCTFFlagTeam2 ); +LINK_ENTITY_TO_CLASS( ctf_redflag, AgCTFFlagTeam2 ); //CCTF map compatibility hack +#endif + +class AgCTFFlagTeamOP4 : public AgCTFFlag +{ + int m_iTeam; + void KeyValue( KeyValueData *pkvd ) + { + if (FStrEq(pkvd->szKeyName, "goal_no")) + { + m_iTeam = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "ctf_flag")) //HLE map compatibility hack + { + if (1 == atoi(pkvd->szValue)) + m_iTeam = 2; + else if (2 == atoi(pkvd->szValue)) + m_iTeam = 1; + + pkvd->fHandled = TRUE; + } + else + AgCTFFlag::KeyValue( pkvd ); + } + + void Spawn( void ) + { + if (1 == m_iTeam) + { + pev->classname = MAKE_STRING("item_flag_team1"); + strcpy( m_szTeamName, CTF_TEAM1_NAME ); + } + else if (2 == m_iTeam) + { + pev->classname = MAKE_STRING("item_flag_team2"); + strcpy( m_szTeamName, CTF_TEAM2_NAME ); + } + + AgCTFFlag::Spawn( ); + } +}; +#ifndef AG_NO_CLIENT_DLL +LINK_ENTITY_TO_CLASS( item_ctfflag, AgCTFFlagTeamOP4 ); //OP4CTF map compatibility hack. +LINK_ENTITY_TO_CLASS( info_flag_ctf, AgCTFFlagTeamOP4 ); //HLE map compatibility hack +#endif + + + +//========================================================= +// Carried Flag +// +// This is a complete new entity because it doesn't behave +// as a flag. It just sits on the back of the player and +// removes itself at the right time. (When player is gone +// or death or lost the flag.) +//========================================================= +void AgCTFPlayerFlag ::Spawn( ) +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/flag.mdl"); + UTIL_SetOrigin( pev, pev->origin ); + + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT; + + //HACKHACKHACK: Overcome the attachment with no owner yet model "hop" by making it invisible + pev->effects |= EF_NODRAW; + + pev->sequence = WAVE_IDLE; + pev->framerate = 1.0; + + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + pev->skin = 1; + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + pev->skin = 2; + + SetThink( &AgCTFPlayerFlag::Think ); + pev->nextthink = gpGlobals->time + 0.1; +} + +void AgCTFPlayerFlag::UpdateOnRemove( void ) +{ + if (FStrEq(CTF_TEAM1_NAME, m_szTeamName)) + s_iPlayerFlag1 = 0; + else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName)) + s_iPlayerFlag2 = 0; +} + + +void AgCTFPlayerFlag::Precache( ) +{ + PRECACHE_MODEL ("models/flag.mdl"); +} + +void AgCTFPlayerFlag::Think( ) +{ + //Make it visible + pev->effects &= ~EF_NODRAW; + + //And let if follow + pev->aiment = ENT(m_pOwner->pev); + pev->movetype = MOVETYPE_FOLLOW; + + //Remove if owner is death + if (!m_pOwner->IsAlive()) + UTIL_Remove( this ); + + //If owner lost flag, remove + if ( !m_pOwner->m_bFlagTeam1 && !m_pOwner->m_bFlagTeam2) + { + UTIL_Remove( this ); + } + else + { + //If owners speed is low, go in idle mode + if (m_pOwner->pev->velocity.Length() <= 75 && pev->sequence != WAVE_IDLE) + { + pev->sequence = WAVE_IDLE; + } + //Else let the flag go wild + else if (m_pOwner->pev->velocity.Length() >= 75 && pev->sequence != CARRIED) + { + pev->sequence = CARRIED; + } + pev->frame += pev->framerate; + if (pev->frame < 0.0 || pev->frame >= 256.0) + { + pev->frame -= (int)(pev->frame / 256.0) * 256.0; + } + pev->nextthink = gpGlobals->time + 0.1; + } +} + +class AgCTFPlayerFlagTeam1 : public AgCTFPlayerFlag +{ + void Spawn( void ) + { + strcpy( m_szTeamName, CTF_TEAM1_NAME ); + + AgCTFPlayerFlag::Spawn( ); + } +}; + +#ifndef AG_NO_CLIENT_DLL +LINK_ENTITY_TO_CLASS( carried_flag_team1, AgCTFPlayerFlagTeam1 ); +#endif + +class AgCTFPlayerFlagTeam2 : public AgCTFPlayerFlag +{ + void Spawn( void ) + { + strcpy( m_szTeamName, CTF_TEAM2_NAME ); + + AgCTFPlayerFlag::Spawn( ); + } +}; + +#ifndef AG_NO_CLIENT_DLL +LINK_ENTITY_TO_CLASS( carried_flag_team2, AgCTFPlayerFlagTeam2 ); +#endif + +class AgCTFDetect : public CBaseEntity +{ + void Spawn( void ) + { + UTIL_SetOrigin( pev, pev->origin ); + pev->solid = SOLID_NOT; + pev->effects = EF_NODRAW; + + AgString sGametype = CVAR_GET_STRING("sv_ag_gametype"); + if (sGametype != "ctf") + CVAR_SET_STRING("sv_ag_gamemode","ctf"); + } + void KeyValue( KeyValueData* pkvd) + { + pkvd->fHandled = FALSE; + } +}; +#ifndef AG_NO_CLIENT_DLL +LINK_ENTITY_TO_CLASS( info_hmctfdetect, AgCTFDetect ); +LINK_ENTITY_TO_CLASS( info_ctfdetect, AgCTFDetect ); //OP4 CTF detect +LINK_ENTITY_TO_CLASS( game_mode_ctf, AgCTFDetect ); //HLE CTF detect +#endif + +/* +============ +EntSelectCTFSpawnPoint + +Returns the CTF entity to spawn at + +USES AND SETS GLOBAL g_pLastSpawn +============ +*/ +extern CBaseEntity *g_pLastSpawn; +BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot); +inline int FNullEnt( CBaseEntity *ent ) { return (ent == NULL) || FNullEnt( ent->edict() ); } + + +edict_t *EntSelectCTFSpawnPoint( CBaseEntity *pPlayer ) +{ + CBaseEntity *pSpot; + edict_t *player; + + player = pPlayer->edict(); + CBasePlayer *cbPlayer = (CBasePlayer *)pPlayer; //we need a CBasePlayer + + pSpot = g_pLastSpawn; + // Randomize the start spot + for ( int i = RANDOM_LONG(1,5); i > 0; i-- ) + { + if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM1_NAME)) + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team1" ); + else if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM2_NAME)) + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team2" ); + else + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); + } + if ( FNullEnt( pSpot ) ) // skip over the null point + { + if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM1_NAME)) + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team1" ); + else if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM2_NAME)) + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team2" ); + else + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); + } + + CBaseEntity *pFirstSpot = pSpot; + + do + { + if ( pSpot ) + { + // check if pSpot is valid + if ( IsSpawnPointValid( pPlayer, pSpot ) ) + { + if ( pSpot->pev->origin == Vector( 0, 0, 0 ) ) + { + if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM1_NAME)) + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team1" ); + else if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM2_NAME)) + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team2" ); + else + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); + continue; + } + + // valid pSpot, so it can be returned + goto ReturnSpot; + } + } + // increment pSpot + if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM1_NAME)) + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team1" ); + else if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM2_NAME)) + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team2" ); + else + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); + } while ( pSpot != pFirstSpot ); // loop if we're not back to the start + + // we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there + if ( !FNullEnt( pSpot ) ) + { + CBaseEntity *ent = NULL; + while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL ) + { + // if ent is a client, kill em (unless they are ourselves) + if ( ent->IsPlayer() && !(ent->edict() == player) ) + ent->TakeDamage( VARS(INDEXENT(0)), VARS(INDEXENT(0)), 300, DMG_GENERIC ); + } + goto ReturnSpot; + } + +ReturnSpot: + if ( FNullEnt( pSpot ) ) + { + ALERT(at_error, "PutClientInServer: no info_player_team1,info_player_team2 on level"); + ClientPrint(pPlayer->pev,HUD_PRINTCENTER, "This is not a valid CTF map!" ); + pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); + if (FNullEnt( pSpot )) + return INDEXENT(0); + } + + g_pLastSpawn = pSpot; + return pSpot->edict(); +} + + +class AgCTFSpawn : public CPointEntity +{ + int m_iTeam; +public: + void KeyValue( KeyValueData *pkvd ); + BOOL IsTriggered( CBaseEntity *pEntity ); + void Spawn( void ); + +private: +}; + +void AgCTFSpawn::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "master")) + { + pev->netname = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + //OP4 map compatibility + else if (FStrEq(pkvd->szKeyName, "team_no")) + { + m_iTeam = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + +BOOL AgCTFSpawn::IsTriggered( CBaseEntity *pEntity ) +{ + BOOL master = UTIL_IsMasterTriggered( pev->netname, pEntity ); + + return master; +} + +void AgCTFSpawn :: Spawn( void ) +{ + //CCTF map compatibility + if (FStrEq(STRING(pev->classname), "ctf_bluespawn")) + pev->classname = MAKE_STRING("info_player_team1"); + else if (FStrEq(STRING(pev->classname), "ctf_redspawn")) + pev->classname = MAKE_STRING("info_player_team2"); + //HLE map compatibility + else if (FStrEq(STRING(pev->classname), "info_player_ctf_blue")) + pev->classname = MAKE_STRING("info_player_team1"); + else if (FStrEq(STRING(pev->classname), "info_player_ctf_red")) + pev->classname = MAKE_STRING("info_player_team2"); + //OP4 map compatibility + else if (1 == m_iTeam) + pev->classname = MAKE_STRING("info_player_team1"); + else if (2 == m_iTeam) + pev->classname = MAKE_STRING("info_player_team2"); + pev->solid = SOLID_NOT; + + +} + +#ifndef AG_NO_CLIENT_DLL +LINK_ENTITY_TO_CLASS(info_player_team1,AgCTFSpawn); +LINK_ENTITY_TO_CLASS(ctf_bluespawn,AgCTFSpawn); //CCTF map compatibility +LINK_ENTITY_TO_CLASS(info_player_team2,AgCTFSpawn); +LINK_ENTITY_TO_CLASS(ctf_redspawn,AgCTFSpawn); //CCTF map compatibility +LINK_ENTITY_TO_CLASS(info_ctfspawn,AgCTFSpawn); //OP4 CTF map compatibility +LINK_ENTITY_TO_CLASS(info_player_ctf_blue,AgCTFSpawn); //HLE CTF map compatibility +LINK_ENTITY_TO_CLASS(info_player_ctf_red,AgCTFSpawn); //HLE CTF map compatibility +#endif + + + +#include "vector.h" + +class AgCTFFileItemCache; + + +AgCTFFileItem::AgCTFFileItem() +{ + m_vOrigin = Vector(0,0,0); + m_vAngles = Vector(0,0,0); + m_szName[0] = '\0'; +} + +AgCTFFileItem::~AgCTFFileItem() +{ + +} + +void AgCTFFileItem::Show() +{ + CLaserSpot* pSpot = CLaserSpot::CreateSpot(); + UTIL_SetOrigin( pSpot->pev, m_vOrigin ); + pSpot->LiveForTime(5.0); +} + + + +AgCTFFileItemCache::AgCTFFileItemCache() +{ + m_bInitDone = false; + Load(); +} + +AgCTFFileItemCache::~AgCTFFileItemCache() +{ + //Delete all. + for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + delete *itrFileItems; + m_lstFileItems.clear(); +} + +void AgCTFFileItemCache::Add(const AgString& sFileItem,CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (0 == sFileItem.size()) + return; + + AgCTFFileItem* pFileItem = new AgCTFFileItem; + strcpy(pFileItem->m_szName,sFileItem.c_str()); + pFileItem->m_vOrigin = pPlayer->pev->origin; + pFileItem->m_vAngles = pPlayer->pev->angles; + + m_lstFileItems.push_back(pFileItem); + pFileItem->Show(); + + Save(pPlayer); + + AgConsole(UTIL_VarArgs("Added item %s.",(const char*)sFileItem.c_str()),pPlayer); +} + +void AgCTFFileItemCache::Del(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (0 == m_lstFileItems.size()) + return; + + AgCTFFileItem* pFileItem = m_lstFileItems.back(); + AgConsole(UTIL_VarArgs("Deleted last item - %s.",pFileItem->m_szName,pPlayer)); + m_lstFileItems.pop_back(); + Save(pPlayer); +} + +void AgCTFFileItemCache::List(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + { + AgConsole(UTIL_VarArgs("%s",(const char*)(*itrFileItems)->m_szName),pPlayer); + (*itrFileItems)->Show(); + } +} + +void AgCTFFileItemCache::Load(CBasePlayer* pPlayer) +{ + for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + delete *itrFileItems; + m_lstFileItems.clear(); + + + char szFile[MAX_PATH]; + char szData[20000]; + sprintf(szFile, "%s/ctf/%s.ctf", AgGetDirectory(),STRING(gpGlobals->mapname)); + FILE* pFile = fopen(szFile,"r"); + if (!pFile) + { + // file error + return; + } + + int iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile); + fclose(pFile); + if (0 >= iRead) + return; + szData[iRead] = '\0'; + + char* pszCTFString = strtok( szData, "\n"); + while (pszCTFString != NULL) + { + AgCTFFileItem* pFileItem = new AgCTFFileItem; + sscanf(pszCTFString,"%s %f %f %f %f %f %f\n",pFileItem->m_szName,&pFileItem->m_vOrigin.x,&pFileItem->m_vOrigin.y,&pFileItem->m_vOrigin.z,&pFileItem->m_vAngles.x,&pFileItem->m_vAngles.y,&pFileItem->m_vAngles.z); + m_lstFileItems.push_back(pFileItem); + pszCTFString = strtok( NULL, "\n"); + } +} + +void AgCTFFileItemCache::Save(CBasePlayer* pPlayer) +{ + if (0 == m_lstFileItems.size()) + return; + + char szFile[MAX_PATH]; + sprintf(szFile, "%s/ctf/%s.ctf", AgGetDirectory(),STRING(gpGlobals->mapname)); + FILE* pFile = fopen(szFile,"wb"); + if (!pFile) + { + // file error + AgConsole(UTIL_VarArgs("Couldn't create/save FileItem file %s.",szFile),pPlayer); + return; + } + + //Loop and write the file. + for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + { + //Append. + AgCTFFileItem* pFileItem = *itrFileItems; + fprintf(pFile,"%s %f %f %f %f %f %f\n",pFileItem->m_szName,pFileItem->m_vOrigin.x,pFileItem->m_vOrigin.y,pFileItem->m_vOrigin.z,pFileItem->m_vAngles.x,pFileItem->m_vAngles.y,pFileItem->m_vAngles.z); + } + + fflush(pFile); + fclose(pFile); +} + + +void AgCTFFileItemCache::Init() +{ + if (m_bInitDone) + return; + m_bInitDone = true; + + for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + { + AgCTFFileItem* pFileItem = *itrFileItems; + + if (g_pGameRules->IsAllowedToSpawn(pFileItem->m_szName)) + CBaseEntity::Create(pFileItem->m_szName, pFileItem->m_vOrigin, pFileItem->m_vAngles, INDEXENT(0)); + } +} + +//-- Martin Webrant + diff --git a/dlls/aghl/agctf.h b/dlls/aghl/agctf.h new file mode 100644 index 00000000..3bc80401 --- /dev/null +++ b/dlls/aghl/agctf.h @@ -0,0 +1,133 @@ +// AgCTF.h: interface for the AgCTF class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(__AG_CTF_H__) +#define __AG_CTF_H__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define CTF_TEAM1_NAME "blue" +#define CTF_TEAM2_NAME "red" + + +class AgCTFFileItemCache; +class AgCTFFileItem +{ + char m_szName[32]; + Vector m_vOrigin; + Vector m_vAngles; + +public: + AgCTFFileItem(); + virtual ~AgCTFFileItem(); + + void Show(); + + friend class AgCTFFileItemCache; +}; + +class AgCTFFileItemCache +{ + bool m_bInitDone; + typedef list AgCTFFileItemList; + AgCTFFileItemList m_lstFileItems; + + void Load(CBasePlayer* pPlayer = NULL); + void Save(CBasePlayer* pPlayer = NULL); + +public: + AgCTFFileItemCache(); + virtual ~AgCTFFileItemCache(); + + + void Init(); + + void Add(const AgString& sItem,CBasePlayer* pPlayer); + void Del(CBasePlayer* pPlayer); + void List(CBasePlayer* pPlayer); +}; + + +class AgCTF +{ + int m_iTeam1Captures; + int m_iTeam2Captures; + + int m_iPlayerFlag1; + int m_iPlayerFlag2; + + enum CTFStatus { Waiting, Countdown, Spawning, Playing}; + CTFStatus m_Status; + float m_fNextCountdown; + float m_fMatchStart; + AgString m_sWinner; + +public: + AgCTF(); + virtual ~AgCTF(); + + bool CaptureLimit(); + void ResetCaptures(); + void ResetScore(bool bResetCaptures = true); + void SendCaptures(CBasePlayer* pPlayer); + void Think(); + void RoundBasedThink(); + + void PlayerInitHud(CBasePlayer* pPlayer); + void ClientDisconnected(CBasePlayer* pPlayer); + void ClientConnected(CBasePlayer* pPlayer); + void PlayerKilled(CBasePlayer* pPlayer,entvars_t *pKiller); + void AddPointsForKill(CBasePlayer *pAttacker, CBasePlayer *pKilled); + + void PlayerDropFlag(CBasePlayer* pPlayer, bool bPlayerDrop = false); + + void RoundOver(const char* pszWinner); + + AgCTFFileItemCache m_FileItemCache; +}; + + +class AgCTFFlag : public CBaseEntity +{ +public: + void Spawn( void ); + + float m_fNextTouch; + bool m_bDropped; + char m_szTeamName[64]; + float m_fNextReset; + + static void ResetFlag(const char *pTeamName); + + void ResetFlag(); + +private: + void Precache ( void ); + void Capture(CBasePlayer *pPlayer, const char *pTeamName); + void Materialize( void ); + void FlagTouch( CBaseEntity *pOther ); + BOOL MyTouch( CBasePlayer *pPlayer ); + void Think( void ); +}; + +class AgCTFPlayerFlag : public CBaseEntity +{ +public: + void Spawn( void ); + virtual void UpdateOnRemove( void ); + + CBasePlayer* m_pOwner; + char m_szTeamName[64]; + +private: + void Precache ( void ); + void Think( void ); +}; + + + + +#endif // !defined(__AG_CTF_H__) diff --git a/dlls/aghl/agdom.cpp b/dlls/aghl/agdom.cpp new file mode 100644 index 00000000..17bb9cdb --- /dev/null +++ b/dlls/aghl/agdom.cpp @@ -0,0 +1,640 @@ +//++ muphicks +// AGDomination mode +// Based on the AG CTF code by BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" + +#include "aggamerules.h" +#include "agglobal.h" +#include "agdom.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +// Use the existing CTF message for now since I don't really want +// to have to make client changes at this time.. Once I get the new +// flag model from aljosa@lovercic@siol.net then I will probably +// make a new message if its required and add some new sounds. +extern int gmsgCTFSound; +enum DOMSound +{ + YouHaveFlag = 0, + TeamHaveFlag, + EnemyHaveFlag, + BlueFlagReturned, + RedFlagReturned, + BlueScores, + RedScores, + BlueFlagStolen, + RedFlagStolen, + //not used... + BlueLeads, + RedLeads, + TeamsTied, + SuddenDeath, + Stolen, + Capture, +}; + +extern int gmsgTeamScore; + +FILE_GLOBAL int s_iTeam1Score; +FILE_GLOBAL int s_iTeam2Score; + +AgDOM::AgDOM() +{ + m_iTeam1Score = 0; + m_iTeam2Score = 0; + s_iTeam1Score = 0; + s_iTeam2Score = 0; +} + +AgDOM::~AgDOM() +{ +} + +typedef list boo; + +void AgDOM::PlayerInitHud(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev ); + WRITE_STRING( DOM_TEAM1_NAME); + WRITE_SHORT( m_iTeam1Score ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev ); + WRITE_STRING( DOM_TEAM2_NAME); + WRITE_SHORT( m_iTeam2Score ); + WRITE_SHORT( 0 ); + MESSAGE_END(); +} + + +void AgDOM::SendControlScores(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev ); + WRITE_STRING( DOM_TEAM1_NAME); + WRITE_SHORT( s_iTeam1Score ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev ); + WRITE_STRING( DOM_TEAM2_NAME); + WRITE_SHORT( s_iTeam2Score ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + +} + +bool AgDOM::ScoreLimit(void) +{ + if (ag_dom_scorelimit.value > 1 + && ( s_iTeam1Score >= ag_dom_scorelimit.value + ||s_iTeam2Score >= ag_dom_scorelimit.value)) + return true; + + return false; +} + +void AgDOM::ResetControlPoints(void) +{ + // Looping through entity finds ! + edict_t *pFind; + + // Grab a list of control points + pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "item_dom_controlpoint" ); + + while ( !FNullEnt( pFind ) ) + { + // reset each one back to the NEUTRAL team ie uncaptured state + CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); + AgDOMControlPoint *pControlPoint = (AgDOMControlPoint *)pEnt; + pControlPoint->Reset(); + pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "object_world" ); + } + + // reset scores here?? + m_iTeam1Score = 0; + m_iTeam2Score = 0; + s_iTeam1Score = 0; + s_iTeam2Score = 0; +} + +void AgDOM::Think() +{ + if (!g_pGameRules) + return; + + // Has there been a new capture? Yes then we'd best see if one + // team controls all the capture points or not. + + // Play BLUE/RED TEAM DOMINATE + + // send update of scores + if (m_iTeam1Score != s_iTeam1Score + ||m_iTeam2Score != s_iTeam2Score) + { + m_iTeam1Score = s_iTeam1Score; + + //Send new team score to all clients. + MESSAGE_BEGIN( MSG_ALL, gmsgTeamScore ); + WRITE_STRING( DOM_TEAM1_NAME); + WRITE_SHORT( s_iTeam1Score ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + + m_iTeam2Score = s_iTeam2Score; + + //Send new team score to all clients. + MESSAGE_BEGIN( MSG_ALL, gmsgTeamScore ); + WRITE_STRING( CTF_TEAM2_NAME); + WRITE_SHORT( s_iTeam2Score ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + + // Could check whether a team has all the control points and if so play DOMINATION sound? + } + + + m_FileItemCache.Init(); +} + +void AgDOM::ClientConnected(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; +} + + +void AgDOM::ClientDisconnected(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + // remove player from any active scoring controls + edict_t *pFind; + + // Grab a list of control points + pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "item_dom_controlpoint" ); + + while ( !FNullEnt( pFind ) ) + { + // reset each one back to the NEUTRAL team ie uncaptured state + CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); + AgDOMControlPoint *pControlPoint = (AgDOMControlPoint *)pEnt; + pControlPoint->ClientDisconnected( pPlayer ); + pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "item_dom_controlpoint" ); + } +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// AG DOM Control Point +// +/////////////////////////////////////////////////////////////////////////////////// + +// most of these are not used, but may as well have them for later :) +enum Flag_Animations +{ + ON_GROUND = 0, + NOT_CARRIED, + CARRIED, + WAVE_IDLE, + FLAG_POSITION +}; + +void AgDOMControlPoint::Capture(CBasePlayer *pPlayer, const char *szTeamName) +{ + // if players team already controls this area don't recapture + if (FStrEq(m_szTeamName, szTeamName)) + return; + + ChangeControllingTeam( szTeamName ); + + m_fCaptureTime = gpGlobals->time + ag_dom_mincontroltime.value; + m_iConsecutiveScores = 0; // reset score count + pCapturingPlayer = pPlayer; + + if ( 0 == strcmp(DOM_TEAM1_NAME,szTeamName)) + { + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( RedFlagStolen ); + MESSAGE_END(); + } + else if ( 0 == strcmp(DOM_TEAM2_NAME,szTeamName)) + { + MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound ); + WRITE_BYTE( BlueFlagStolen ); + MESSAGE_END(); + } + + // Inform HLTV of this aweinspiring event :P Since there will be many more captures + // happening in DOM than in CTF don't bother with slow mo for now. + UTIL_SendDirectorMessage( pPlayer->edict(), this->edict(), 10 | DRC_FLAG_DRAMATIC ); + + // Inform all players that zone has been taken control of by playername + // really need identifiers for each control point! + char szText[300]; + sprintf(szText, "%s captures CP at %s!", STRING(pPlayer->pev->netname), m_szLocation); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); +} + +void AgDOMControlPoint::ChangeControllingTeam( const char *szTeamName ) +{ + + if (FStrEq(DOM_TEAM1_NAME, szTeamName)) + pev->skin = 1; + else if (FStrEq(DOM_TEAM2_NAME, szTeamName)) + pev->skin = 2; + else + pev->skin = 3; + + + if (FStrEq(DOM_TEAM1_NAME, szTeamName)) + { + pev->rendercolor.x = 0; + pev->rendercolor.y = 0; + pev->rendercolor.z = 128; + pev->renderamt = 50; + } + else if (FStrEq(DOM_TEAM2_NAME, szTeamName)) + { + pev->rendercolor.x = 128; + pev->rendercolor.y = 0; + pev->rendercolor.z = 0; + pev->renderamt = 50; + } + else if (FStrEq(DOM_NEUTRAL_NAME, szTeamName)) + { + pev->rendercolor.x = 0; // R + pev->rendercolor.y = 128; // G + pev->rendercolor.z = 0; // B + pev->renderamt = 100; + } + + // Change the owner of the control point + strncpy( m_szTeamName, szTeamName, sizeof(m_szTeamName) ); +} + +void AgDOMControlPoint::Spawn ( void ) +{ + m_fNextTouch = 0; + + Precache( ); + SET_MODEL(ENT(pev), "models/flag.mdl"); + + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_TRIGGER; + UTIL_SetOrigin( pev, pev->origin ); + UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); + + SetThink( &AgDOMControlPoint::Think ); + SetTouch( &AgDOMControlPoint::Touch ); + + pev->nextthink = gpGlobals->time + 0.1; + + // spawn by default under no teams control + ChangeControllingTeam( DOM_NEUTRAL_NAME ); + + pev->sequence = NOT_CARRIED; + pev->framerate = 1; + + pev->renderamt = 50; + pev->renderfx = kRenderFxGlowShell; +} + +void AgDOMControlPoint::Reset( void ) +{ + ChangeControllingTeam( DOM_NEUTRAL_NAME ); + m_fCaptureTime = -1; + m_iConsecutiveScores = 0; // reset score count + pCapturingPlayer = NULL; + + // Inform HLTV of this event, although its more exciting than an empty room its not that exciting :( + UTIL_SendDirectorMessage( this->edict(), NULL, 1 ); +} + +void AgDOMControlPoint::Precache( void ) +{ + PRECACHE_MODEL ("models/flag.mdl"); +} + +void AgDOMControlPoint::Think( void ) +{ + // Has the flag been under control long enough to score a team point? + if( !FStrEq( m_szTeamName, DOM_NEUTRAL_NAME )) + if( m_fCaptureTime <= gpGlobals->time ) + { + // Team scores + if (FStrEq( m_szTeamName, DOM_TEAM1_NAME )) + s_iTeam1Score += ag_dom_controlpoints.value; + else if (FStrEq( m_szTeamName, DOM_TEAM2_NAME )) + s_iTeam2Score += ag_dom_controlpoints.value; + + //Give the player the points + if (pCapturingPlayer && FStrEq(pCapturingPlayer->m_szTeamName,m_szTeamName) ) + pCapturingPlayer->AddPoints(ag_dom_controlpoints.value, TRUE); + //pCapturingPlayer->AddPointsToTeam(ag_dom_controlpoints.value, TRUE); // is this required? + else if (pCapturingPlayer) + pCapturingPlayer = NULL; + + // Increase score count + m_iConsecutiveScores++; + + // reset score timer + m_fCaptureTime = gpGlobals->time + ag_dom_mincontroltime.value; + } + + // Have we pased the max capture score limit, if so return control of this flag to + // a neutral state. + if ( m_iConsecutiveScores >= ag_dom_resetscorelimit.value ){ + char szText[201]; + sprintf(szText, "Neutral CP available at %s", m_szLocation); + AgConsole(szText); + UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); + Reset(); + } + + // animate the control point + pev->frame += pev->framerate; + if (pev->frame < 0.0 || pev->frame >= 256.0) + { + pev->frame -= (int)(pev->frame / 256.0) * 256.0; + } + pev->nextthink = gpGlobals->time + 0.1; + +} + +void AgDOMControlPoint::Touch( CBaseEntity *pOther ) +{ + // prevent CP changing owner too quickly + if (m_fNextTouch > gpGlobals->time) + return; + else m_fNextTouch = gpGlobals->time + 0.5; + + // if it's not a player, ignore + if ( !pOther->IsPlayer() ) + return; + + if ( !pOther->IsAlive() ) + return; + + + CBasePlayer *pPlayer = (CBasePlayer *)pOther; + + if (FStrEq(pPlayer->m_szTeamName, DOM_TEAM1_NAME)) + Capture( pPlayer, DOM_TEAM1_NAME ); + else if (FStrEq(pPlayer->m_szTeamName, DOM_TEAM2_NAME)) + Capture( pPlayer, DOM_TEAM2_NAME ); +} + +void AgDOMControlPoint::ClientDisconnected(CBasePlayer* pPlayer) +{ + // Is there a better way to handle this? eg before adding on player score + // checking if player still exists? + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (pPlayer == pCapturingPlayer) + pCapturingPlayer = NULL; +} + + +#ifndef AG_NO_CLIENT_DLL +LINK_ENTITY_TO_CLASS( item_dom_controlpoint, AgDOMControlPoint ); +#endif + + +/////////////////////////////////////////////////////////////////////////////////// +// +// AG Item Cache - Allows maps that are none DOM specific to be used as DOM maps +// +/////////////////////////////////////////////////////////////////////////////////// + + +#include "vector.h" + +class AgDOMFileItemCache; + + +AgDOMFileItem::AgDOMFileItem() +{ + m_vOrigin = Vector(0,0,0); + m_vAngles = Vector(0,0,0); + m_szName[0] = '\0'; + m_szData1[0] = '\0'; +} + +AgDOMFileItem::~AgDOMFileItem() +{ + +} + +void AgDOMFileItem::Show() +{ + CLaserSpot* pSpot = CLaserSpot::CreateSpot(); + UTIL_SetOrigin( pSpot->pev, m_vOrigin ); + pSpot->LiveForTime(5.0); +} + + + +AgDOMFileItemCache::AgDOMFileItemCache() +{ + m_bInitDone = false; + Load(); +} + +AgDOMFileItemCache::~AgDOMFileItemCache() +{ + //Delete all. + for (AgDOMFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + delete *itrFileItems; + m_lstFileItems.clear(); +} + +void AgDOMFileItemCache::Add(const AgString& sFileItem,CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (0 == sFileItem.size()) + return; + + AgDOMFileItem* pFileItem = new AgDOMFileItem; + strcpy(pFileItem->m_szName,sFileItem.c_str()); + pFileItem->m_vOrigin = pPlayer->pev->origin; + pFileItem->m_vAngles = pPlayer->pev->angles; + + m_lstFileItems.push_back(pFileItem); + pFileItem->Show(); + + Save(pPlayer); + + AgConsole(UTIL_VarArgs("Added item %s.",(const char*)sFileItem.c_str()),pPlayer); +} + +void AgDOMFileItemCache::Del(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (0 == m_lstFileItems.size()) + return; + + AgDOMFileItem* pFileItem = m_lstFileItems.back(); + AgConsole(UTIL_VarArgs("Deleted last item - %s.",pFileItem->m_szName,pPlayer)); + m_lstFileItems.pop_back(); + Save(pPlayer); +} + +void AgDOMFileItemCache::List(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + for (AgDOMFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + { + AgConsole(UTIL_VarArgs("%s",(const char*)(*itrFileItems)->m_szName),pPlayer); + (*itrFileItems)->Show(); + } +} + +void AgDOMFileItemCache::Load(CBasePlayer* pPlayer) +{ + for (AgDOMFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + delete *itrFileItems; + m_lstFileItems.clear(); + + + char szFile[MAX_PATH]; + char szData[20000]; + sprintf(szFile, "%s/dom/%s.dom", AgGetDirectory(),STRING(gpGlobals->mapname)); + FILE* pFile = fopen(szFile,"r"); + if (!pFile) + { + // file error + return; + } + + int iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile); + fclose(pFile); + if (0 >= iRead) + return; + szData[iRead] = '\0'; + + char* pszCTFString = strtok( szData, "\n"); + while (pszCTFString != NULL) + { + AgDOMFileItem* pFileItem = new AgDOMFileItem; + sscanf(pszCTFString,"%s %f %f %f %f %f %f %s\n",pFileItem->m_szName,&pFileItem->m_vOrigin.x,&pFileItem->m_vOrigin.y,&pFileItem->m_vOrigin.z, + &pFileItem->m_vAngles.x,&pFileItem->m_vAngles.y,&pFileItem->m_vAngles.z, + pFileItem->m_szData1 ); + m_lstFileItems.push_back(pFileItem); + pszCTFString = strtok( NULL, "\n"); + } +} + +void AgDOMFileItemCache::Save(CBasePlayer* pPlayer) +{ + if (0 == m_lstFileItems.size()) + return; + + char szFile[MAX_PATH]; + sprintf(szFile, "%s/dom/%s.dom", AgGetDirectory(),STRING(gpGlobals->mapname)); + FILE* pFile = fopen(szFile,"wb"); + if (!pFile) + { + // file error + AgConsole(UTIL_VarArgs("Couldn't create/save FileItem file %s.",szFile),pPlayer); + return; + } + + //Loop and write the file. + for (AgDOMFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + { + //Append. + AgDOMFileItem* pFileItem = *itrFileItems; + fprintf(pFile,"%s %f %f %f %f %f %f %s\n",pFileItem->m_szName,pFileItem->m_vOrigin.x,pFileItem->m_vOrigin.y,pFileItem->m_vOrigin.z, + pFileItem->m_vAngles.x,pFileItem->m_vAngles.y,pFileItem->m_vAngles.z, + pFileItem->m_szData1); + } + + fflush(pFile); + fclose(pFile); +} + + +void AgDOMFileItemCache::Init() +{ + if (m_bInitDone) + return; + m_bInitDone = true; + CBaseEntity *pEnt = NULL; + + for (AgDOMFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems) + { + AgDOMFileItem* pFileItem = *itrFileItems; + + if (g_pGameRules->IsAllowedToSpawn(pFileItem->m_szName)) + pEnt = CBaseEntity::Create(pFileItem->m_szName, pFileItem->m_vOrigin, pFileItem->m_vAngles, INDEXENT(0)); + + // In addition to the generic entity creation params we wish to load a location param for ControlPoints, + // we parse this here. Unless you can tell me a better place or more generic method in which case I'll use it :) + // An alternative is to add info_dom_location items with a string name for the location however this would + // still involve parsing the datafile for strings so unless we change the save/load routine there is no point + // EG parse item name then deal with special cases or generic case - May change to this later :P + if (FStrEq( "item_dom_controlpoint", pFileItem->m_szName) && pEnt) + { + AgDOMControlPoint *pCP = (AgDOMControlPoint*)pEnt; + strncpy( pCP->m_szLocation, pFileItem->m_szData1, sizeof(pCP->m_szLocation) ); + } + + } +} \ No newline at end of file diff --git a/dlls/aghl/agdom.h b/dlls/aghl/agdom.h new file mode 100644 index 00000000..a238be2c --- /dev/null +++ b/dlls/aghl/agdom.h @@ -0,0 +1,114 @@ +//++ muphicks +// AGDomination mode header file + +#if !defined(__AG_DOM_H__) +#define __AG_DOM_H__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define DOM_TEAM1_NAME "blue" +#define DOM_TEAM2_NAME "red" +#define DOM_NEUTRAL_NAME "neutral" + + +// This is an exact copy of the CTF itterator. Could inherit but for +// simplicity at this point copying is easier. May tidy this up later :P + +class AgDOMFileItemCache; +class AgDOMFileItem +{ + char m_szName[32]; + Vector m_vOrigin; + Vector m_vAngles; + char m_szData1[64]; + +public: + AgDOMFileItem(); + virtual ~AgDOMFileItem(); + + void Show(); + + friend class AgDOMFileItemCache; +}; + +class AgDOMFileItemCache +{ + bool m_bInitDone; + typedef list AgDOMFileItemList; + AgDOMFileItemList m_lstFileItems; + + void Load(CBasePlayer* pPlayer = NULL); + void Save(CBasePlayer* pPlayer = NULL); + +public: + AgDOMFileItemCache(); + virtual ~AgDOMFileItemCache(); + + + void Init(); + + void Add(const AgString& sItem,CBasePlayer* pPlayer); + void Del(CBasePlayer* pPlayer); + void List(CBasePlayer* pPlayer); +}; + + + +class AgDOMControlPoint : public CBaseEntity +{ +public: + void Spawn( void ); // spawn a control point in the map + void Reset( void ); // reset control point to neutral state + void ClientDisconnected(CBasePlayer* pPlayer); + + char m_szTeamName[64]; // who controls this point? + char m_szLocation[64]; + + float m_fCaptureTime; + float m_fNextTouch; + int m_iConsecutiveScores; // how many times in a row has same team scored + CBasePlayer *pCapturingPlayer; + + +private: + void Precache ( void ); + void Think( void ); + void ChangeControllingTeam( const char *szTeamName ); + void Touch( CBaseEntity *pOther ); + void Capture(CBasePlayer *pPlayer, const char *szTeamName); + + +}; + + + +class AgDOM +{ +private: + int m_iTeam1Score; + int m_iTeam2Score; + +public: + AgDOM(); + virtual ~AgDOM(); + + void Think(); + void ResetControlPoints(); + bool ScoreLimit(void); + + void ClientDisconnected(CBasePlayer* pPlayer); + void ClientConnected(CBasePlayer* pPlayer); + + void PlayerInitHud(CBasePlayer* pPlayer); + void SendControlScores(CBasePlayer* pPlayer); + + AgDOMFileItemCache m_FileItemCache; +}; + + + + + +#endif // !defined(__AG_DOM_H__) diff --git a/dlls/aghl/aggame.cpp b/dlls/aghl/aggame.cpp new file mode 100644 index 00000000..7309ed52 --- /dev/null +++ b/dlls/aghl/aggame.cpp @@ -0,0 +1,34 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "gamerules.h" +#include "aggame.h" +#include "agglobal.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgGame::AgGame() +{ + +} + +AgGame::~AgGame() +{ + +} + +bool AgGame::IsValid() +{ + return (0 != m_sShortname.size() && + 10 > m_sShortname.size() && + 0 != m_sName.size() && + 0 != m_sCfg.size() && + 0 != m_sDescription.size()); +} + +//-- Martin Webrant diff --git a/dlls/aghl/aggame.h b/dlls/aghl/aggame.h new file mode 100644 index 00000000..a34c6888 --- /dev/null +++ b/dlls/aghl/aggame.h @@ -0,0 +1,28 @@ +//++ BulliT + +#if !defined(AFX_AGGAMETYPES_H__B6D8EF5B_9423_4422_B935_1D71B6146DCA__INCLUDED_) +#define AFX_AGGAMETYPES_H__B6D8EF5B_9423_4422_B935_1D71B6146DCA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "agglobal.h" + + +class AgGame +{ +public: + AgGame(); + virtual ~AgGame(); + + AgString m_sShortname; + AgString m_sName; + AgString m_sCfg; + AgString m_sDescription; + + bool IsValid(); +}; + +#endif // !defined(AFX_AGGAMETYPES_H__B6D8EF5B_9423_4422_B935_1D71B6146DCA__INCLUDED_) +//-- Martin Webrant diff --git a/dlls/aghl/aggamemode.cpp b/dlls/aghl/aggamemode.cpp new file mode 100644 index 00000000..526ceb4d --- /dev/null +++ b/dlls/aghl/aggamemode.cpp @@ -0,0 +1,326 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "gamerules.h" +#include "aggamemode.h" +#include "agglobal.h" + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +DLL_GLOBAL AgGameMode GameMode; + +DLL_GLOBAL AgGame* g_pGame = NULL; +DLL_GLOBAL AgString g_sGamemode; +DLL_GLOBAL AgString g_sNextmode; +DLL_GLOBAL BYTE g_GameType = STANDARD; + +void SetupGametype() +{ + AgString sGametype = CVAR_GET_STRING("sv_ag_gametype"); + g_GameType = STANDARD; + if (sGametype == "arena") + g_GameType = ARENA; + else if (sGametype == "arcade") + g_GameType = ARCADE; +#ifndef AG_NO_CLIENT_DLL + else if (sGametype == "ctf") + g_GameType = CTF; + //++ muphicks + else if (sGametype == "dom") + g_GameType = DOM; + //--muphicks +#endif + else if (sGametype == "lms") + g_GameType = LMS; + else if (sGametype == "sgbow") + g_GameType = SGBOW; + else if (sGametype == "instagib") + g_GameType = INSTAGIB; +} + +AgString AgGamename() +{ + if (g_pGame) + return g_pGame->m_sName; + + return "Half-Life"; +} + +AgString AgGamedescription() +{ + if (g_pGame) + return g_pGame->m_sDescription; + + return "Half-Life"; +} + +void gamemode(void) +{ + GameMode.Gamemode(CMD_ARGV(0)); +} + +void nextmode(void) +{ + if (2 == CMD_ARGC()) + GameMode.NextGamemode(CMD_ARGV(1)); + else + AgConsole(g_sNextmode.size() ? g_sNextmode : g_sGamemode, NULL); +} + + +AgGameMode::AgGameMode() +{ + m_fNextCheck = 0; +} + +AgGameMode::~AgGameMode() +{ + for (AgGameMap::iterator itrGames = m_mapGames.begin() ;itrGames != m_mapGames.end(); ++itrGames) + delete (*itrGames).second; + m_mapGames.clear(); +} + +bool AgGameMode::HandleCommand(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return false; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return false; + + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules || 0 == CMD_ARGC()) + return false; + + if (pPlayer->IsAdmin()) + { + if (1 == CMD_ARGC()) + { + if (FStrEq(CMD_ARGV(0), "help")) + { + Help(pPlayer); + return true; + } + + if (!IsAllowedGamemode(CMD_ARGV(0)),pPlayer) + return false; + + Gamemode(CMD_ARGV(0),pPlayer); + return true; + } + else if (2 == CMD_ARGC()) + { + if (FStrEq(CMD_ARGV(0), "agnextmode")) + { + if (!IsAllowedGamemode(CMD_ARGV(1)),pPlayer) + return false; + + NextGamemode(CMD_ARGV(1),pPlayer); + return true; + } + } + } + + if (1 == CMD_ARGC() && FStrEq(CMD_ARGV(0), "agnextmode")) + { + AgConsole(g_sNextmode.size() ? g_sNextmode : g_sGamemode, pPlayer); + return true; + } + + return false; +} + +void AgGameMode::Help(CBasePlayer* pPlayer) +{ + for (AgGameMap::iterator itrGames = m_mapGames.begin() ;itrGames != m_mapGames.end(); ++itrGames) + { + AgConsole(UTIL_VarArgs("%s - %s",(*itrGames).second->m_sShortname.c_str(),(*itrGames).second->m_sDescription.c_str()),pPlayer); + } +} + +void AgGameMode::Think() +{ + if (m_fNextCheck > gpGlobals->time) + return; + m_fNextCheck = gpGlobals->time + 1; //Check every second. + + if (g_sGamemode != CVAR_GET_STRING("sv_ag_gamemode")) + { + //Gamemode has changed. Save the new one and changelevel. The new settings will be set just before allocating the new gamerules. + g_sGamemode = CVAR_GET_STRING("sv_ag_gamemode"); + CVAR_SET_FLOAT("sv_ag_match_running",0); + CVAR_SET_FLOAT("ag_spectalk",1); + CVAR_SET_FLOAT("sv_ag_show_gibs",1); + g_pGameRules->m_Settings.Changelevel(STRING(gpGlobals->mapname)); + } +} + +void AgGameMode::Gamemode(const AgString& sGamemode,CBasePlayer* pPlayer) +{ + if ((IsGamemode(sGamemode) && !pPlayer) || IsAllowedGamemode(sGamemode,pPlayer)) + { + CVAR_SET_STRING("sv_ag_gamemode",sGamemode.c_str()); + AgConsole("Gamemode changed.", pPlayer); + g_sNextmode = ""; + } + else + { + AgConsole("Gamemode not allowed by server admin.",pPlayer); + } +} + +void AgGameMode::NextGamemode(const AgString& sGamemode,CBasePlayer* pPlayer) +{ + if ((IsGamemode(sGamemode) && !pPlayer) || IsAllowedGamemode(sGamemode,pPlayer)) + { + g_sNextmode = sGamemode; + AgConsole("Next Gamemode changed.", pPlayer); + } + else + { + AgConsole("Gamemode not allowed by server admin.",pPlayer); + } +} + +void AgGameMode::ExecConfig() +{ + m_fNextCheck = 0; + + if (g_sNextmode.size()) + { + CVAR_SET_STRING("sv_ag_gamemode",g_sNextmode.c_str()); + g_sNextmode = ""; + } + + AgGameMap::iterator itrGames = m_mapGames.find(CVAR_GET_STRING("sv_ag_gamemode")); + if (itrGames == m_mapGames.end()) + { + //eh? - error in config. + g_pGame = NULL; + AgConsole("Error in server gamemode configuration.\n"); + } + else + { + g_pGame = (*itrGames).second; + SERVER_COMMAND( UTIL_VarArgs("exec gamemodes/%s\n",g_pGame->m_sCfg.c_str() )); + SERVER_EXECUTE( ); + + //So that map does not restart directly. + g_sGamemode = CVAR_GET_STRING("sv_ag_gamemode"); + + //Setup the gametype. + SetupGametype(); + } +} + +bool AgGameMode::IsGamemode(const AgString& sGamemode) +{ + if (0 == sGamemode.size()) + return false; + + AgGameMap::iterator itrGames = m_mapGames.find(sGamemode); + if (itrGames == m_mapGames.end()) + return false; + + return true; +} + +bool AgGameMode::IsAllowedGamemode(const AgString& sGamemode,CBasePlayer* pPlayer) +{ + if (!IsGamemode(sGamemode)) + return false; + + //If empty we allow all. + if (0 == strlen(CVAR_GET_STRING("sv_ag_allowed_gamemodes"))) + return true; + + //Check what gamemodes that are allowed. + return (NULL != strstr(CVAR_GET_STRING("sv_ag_allowed_gamemodes"),sGamemode.c_str())); +} + + +void AgGameMode::Init() +{ + //Set this initially, so server dont restart map right away. + g_sGamemode = CVAR_GET_STRING("sv_ag_gamemode"); + + LoadGames(); + + for (AgGameMap::iterator itrGames = m_mapGames.begin() ;itrGames != m_mapGames.end(); ++itrGames) + { + ADD_SERVER_COMMAND((char*)(*itrGames).second->m_sShortname.c_str(),gamemode); + } + ADD_SERVER_COMMAND("agnextmode",nextmode); +} + +void AgGameMode::LoadGames() +{ + if (0 != m_mapGames.size()) + return; //Already loaded. + + char szDir[MAX_PATH]; + sprintf(szDir, "%s/gamemodes", AgGetDirectory()); + + AgStringSet setFiles; + AgDirList(szDir,setFiles); + + for (AgStringSet::iterator itrFiles = setFiles.begin() ;itrFiles != setFiles.end(); ++itrFiles) + { + AgString sFile = AgString(szDir) + "/" + *itrFiles; + + //AgConsole(UTIL_VarArgs("Found gamemode file %s",sFile.c_str())); + + if (!strstr(sFile.c_str(),".cfg")) + continue; + + //Read the description lines. + FILE* pFile = fopen(sFile.c_str(),"r"); + if (!pFile) + continue; + + char szData[4096]; + int iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile); + fclose(pFile); + if (0 >= iRead) + continue; + szData[iRead] = '\0'; + + AgGame* pGame = new AgGame; + char* pszParse = NULL; + pszParse = strtok(szData, "\n"); + if (pszParse) + { + pGame->m_sCfg = *itrFiles; + pGame->m_sShortname = pGame->m_sCfg.substr(0,pGame->m_sCfg.size() - 4); + pGame->m_sName = pszParse; + pGame->m_sName = pGame->m_sName.substr(2); + + pszParse = strtok(NULL, "\n"); + if (pszParse) + { + pGame->m_sDescription = pszParse; + pGame->m_sDescription = pGame->m_sDescription.substr(2); + } + + if (pGame->IsValid()) + { + AgTrim(pGame->m_sShortname); + AgTrim(pGame->m_sDescription); + AgTrim(pGame->m_sName); + AgTrim(pGame->m_sCfg); + m_mapGames.insert(AgGameMap::value_type(pGame->m_sShortname,pGame)); + AgConsole(UTIL_VarArgs("Added gamemode %s",pGame->m_sShortname.c_str())); + } + else + delete pGame; + } + } +} + +//-- Martin Webrant diff --git a/dlls/aghl/aggamemode.h b/dlls/aghl/aggamemode.h new file mode 100644 index 00000000..74aa7f1d --- /dev/null +++ b/dlls/aghl/aggamemode.h @@ -0,0 +1,53 @@ +//++ BulliT + +#if !defined(AFX_AGGAMEMODES_H__B6D8EF5B_9423_4422_B935_1D71B6146DCA__INCLUDED_) +#define AFX_AGGAMEMODES_H__B6D8EF5B_9423_4422_B935_1D71B6146DCA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "agglobal.h" +#include "aggame.h" + +class AgGameMode +{ + typedef map > AgGameMap; + AgGameMap m_mapGames; + void LoadGames(); + AgGame* pCurrent; + float m_fNextCheck; + +public: + AgGameMode(); + virtual ~AgGameMode(); + + void Init(); + void Think(); + + void ExecConfig(); + void Help(CBasePlayer* pPlayer = NULL); + bool HandleCommand(CBasePlayer* pPlayer); + + void Gamemode(const AgString& sGamemode,CBasePlayer* pPlayer = NULL); + bool IsGamemode(const AgString& sGamemode); + bool IsAllowedGamemode(const AgString& sGamemode,CBasePlayer* pPlayer = NULL); + + void NextGamemode(const AgString& sGamemode,CBasePlayer* pPlayer = NULL); +}; + +extern DLL_GLOBAL AgGameMode GameMode; +AgString AgGamename(); +AgString AgGamedescription(); + +//++ muphicks +enum enumGameType { STANDARD = 0, ARENA = 1, LMS = 2, CTF = 3, ARCADE = 4, SGBOW = 5, INSTAGIB = 6, DOM = 7}; +//-- muphicks +extern DLL_GLOBAL BYTE g_GameType; +inline BYTE AgGametype() +{ + return g_GameType; +}; + +#endif // !defined(AFX_AGGAMEMODES_H__B6D8EF5B_9423_4422_B935_1D71B6146DCA__INCLUDED_) +//-- Martin Webrant diff --git a/dlls/aghl/aggamerules.cpp b/dlls/aghl/aggamerules.cpp new file mode 100644 index 00000000..705e597a --- /dev/null +++ b/dlls/aghl/aggamerules.cpp @@ -0,0 +1,1256 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "gamerules.h" +#include "player.h" +#include "weapons.h" +#include "skill.h" +#include "agglobal.h" +#include "agcommand.h" +#include "agvote.h" +#include "agclient.h" +#include "aggamerules.h" +#ifdef AGSTATS +#include "agstats.h" +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +extern int gmsgTeamInfo; +extern int gmsgScoreInfo; +extern int gmsgAllowSpec; +extern int gmsgServerName; +extern int gmsgSpikeCheck; +extern int gmsgGametype; +extern int g_teamplay; +extern int gmsgGameMode; +extern int gmsgAuthID; +extern int gmsgMapList; + +AgGameRules::AgGameRules() +{ + g_bPaused = false; + m_bProxyConnected = false; + g_bUseTeamColors = CVAR_GET_FLOAT( "mp_teamplay" ) > 0; + m_sHostname = CVAR_GET_STRING("hostname"); + AdminCache.Load(); +#ifdef AG_NO_CLIENT_DLL + m_LocationCache.Load(); +#endif +#ifdef AGSTATS + Stats.Reset(); +#endif +} + +AgGameRules::~AgGameRules() +{ + AdminCache.Save(); +} + +bool AgGameRules::AgThink() +{ + //Check if gamerules are correct. + if (!m_Settings.Think()) + //Dont do anything more. + return false; + + //Check if game over. + if (g_fGameOver) + return true; + + //Update HUD timer and effective time. + m_Timer.Think(); + + //Update vote status. + //Handled globally m_Vote.Think(); + + if (CTF == AgGametype()) + m_CTF.Think(); + //++ muphicks + else if (DOM == AgGametype()) + m_DOM.Think(); + //-- muphicks + + if (LMS == AgGametype()) + { + //Arena status. + m_LMS.Think(); + } + else if (ARENA == AgGametype()) + { + //Arena status. + m_Arena.Think(); + } + else + { + //Update match status. + m_Match.Think(); + //Scorelog + m_ScoreLog.Think(); + } + + //Init intermission spots. + m_InfoInterMission.Think(); + + //Check gamemode + GameMode.Think(); + return true; +} + +BOOL AgGameRules::ClientCommand(CBasePlayer* pPlayer, const char *pcmd) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return FALSE; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return FALSE; + + //First check if its a client command. weaponswith,say etc. + if (m_Client.HandleCommand(pPlayer)) + return TRUE; + + //Server command? + if (Command.HandleCommand(pPlayer)) + return TRUE; + + //Gamemode? + if (GameMode.HandleCommand(pPlayer)) + return TRUE; + + //Vote? + if (m_Vote.HandleCommand(pPlayer)) + return TRUE; + +#ifdef AGSTATS + if (Stats.HandleCommand(pPlayer)) + return TRUE; +#endif + + //We didn't handle it + return FALSE; +} + +void AgGameRules::Start(const AgString& sSpawn) +{ + if (ARENA != AgGametype() && LMS != AgGametype()) + m_Match.Start(sSpawn); +} + + +int AgGameRules::DeadPlayerWeapons( CBasePlayer *pPlayer ) +{ + if (ARENA == AgGametype() || ARCADE == AgGametype()) + return GR_PLR_DROP_GUN_NO; + else + return GR_PLR_DROP_GUN_ACTIVE; +} + +int AgGameRules::DeadPlayerAmmo( CBasePlayer *pPlayer ) +{ + if (ARENA == AgGametype() || ARCADE == AgGametype()) + return GR_PLR_DROP_AMMO_NO; + else + return GR_PLR_DROP_AMMO_ACTIVE; +} + +BOOL AgGameRules::FPlayerCanRespawn(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return FALSE; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return FALSE; + + return pPlayer->IsIngame(); +} + + +void AgGameRules::PlayerSpawn(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (!FPlayerCanRespawn(pPlayer) && !pPlayer->IsProxy()) + { + if (!pPlayer->m_bDoneFirstSpawn) + { + pPlayer->m_bDoneFirstSpawn = true; + } + + if (!pPlayer->IsSpectator()) + { + //Check if we boot him. + int iSpectators = 0; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayer != pPlayerLoop ) + { + if (pPlayerLoop->IsSpectator()) + iSpectators++; + } + } + + if (iSpectators >= ag_max_spectators.value && ARENA != AgGametype() && LMS != AgGametype() && !pPlayer->IsAdmin()) + { + //He has to go. + AgConsole("To many spectators, kicking him."); + char szCommand[128]; + sprintf(szCommand,"kick \"%s\"\n",(const char*)pPlayer->GetName()); + SERVER_COMMAND( szCommand ); + return; + } + + //Go specmode + pPlayer->Spectate_Start(true); + } + ClientPrint(pPlayer->pev,HUD_PRINTCENTER,"Match is running, you are not allowed to enter the game.\n"); + return; + } + + if (pPlayer->IsProxy() || pPlayer->pev->flags & FL_FAKECLIENT) + pPlayer->m_bDoneFirstSpawn = true; + //if (1 == pPlayer->pev->iuser3) + //pPlayer->m_bDoneFirstSpawn = true; + if (!pPlayer->m_bDoneFirstSpawn) + { + pPlayer->m_bDoneFirstSpawn = true; + pPlayer->pev->takedamage = DAMAGE_NO; + pPlayer->pev->flags |= FL_SPECTATOR; + pPlayer->pev->flags |= FL_NOTARGET; + pPlayer->pev->effects |= EF_NODRAW; + pPlayer->pev->solid = SOLID_NOT; + pPlayer->pev->movetype = MOVETYPE_NOCLIP; + pPlayer->pev->modelindex = 0; + pPlayer->m_pGoalEnt = NULL; + + //Move player to info intermission spot + edict_t* pSpot = m_InfoInterMission.GetRandomSpot(); + ASSERT(NULL != pSpot); + if (pSpot) + pPlayer->MoveToInfoIntermission(pSpot); + + //Display Gamemode + pPlayer->SetDisplayGamemode(5); + + //Display greeting message + AgDisplayGreetingMessage(pPlayer->GetAuthID()); + + return; + } + + BOOL addDefault; + CBaseEntity *pWeaponEntity = NULL; + + pPlayer->pev->weapons |= (1<Touch( pPlayer ); + addDefault = FALSE; + } + + pPlayer->m_bInSpawn = true; + + if ( addDefault ) + { + if (pPlayer->GetSpawnFull()) + { + //American spawn mode... Start with full load of everything. + pPlayer->SetSpawnFull(false); + + pPlayer->pev->health = MAX_NORMAL_BATTERY; + pPlayer->pev->armorvalue = MAX_NORMAL_BATTERY; + + if (1 > ag_ban_longjump.value) + { + pPlayer->m_fLongJump = TRUE; + g_engfuncs.pfnSetPhysicsKeyValue( pPlayer->edict(), "slj", "1" ); + pPlayer->OnPickupLongjump(); + } + if (1 > ag_ban_glock.value) + pPlayer->GiveNamedItem( "weapon_9mmhandgun" ); + if (1 > ag_ban_crowbar.value) + pPlayer->GiveNamedItem( "weapon_crowbar" ); + if (1 > ag_ban_shotgun.value) + pPlayer->GiveNamedItem( "weapon_shotgun" ); + if (1 > ag_ban_mp5.value) + pPlayer->GiveNamedItem( "weapon_9mmAR" ); + if (1 > ag_ban_gauss.value) + pPlayer->GiveNamedItem( "weapon_gauss" ); + if (1 > ag_ban_hgrenade.value) + pPlayer->GiveNamedItem( "weapon_handgrenade" ); + if (1 > ag_ban_tripmine.value) + pPlayer->GiveNamedItem( "weapon_tripmine" ); + if (1 > ag_ban_egon.value) + pPlayer->GiveNamedItem( "weapon_egon" ); + if (1 > ag_ban_crossbow.value) + pPlayer->GiveNamedItem( "weapon_crossbow" ); + if (1 > ag_ban_357.value) + pPlayer->GiveNamedItem( "weapon_357" ); + if (1 > ag_ban_rpg.value) + pPlayer->GiveNamedItem( "weapon_rpg" ); + if (1 > ag_ban_satchel.value) + pPlayer->GiveNamedItem( "weapon_satchel" ); + if (1 > ag_ban_snark.value) + pPlayer->GiveNamedItem( "weapon_snark" ); + if (1 > ag_ban_hornet.value) + pPlayer->GiveNamedItem( "weapon_hornetgun" ); + + if (1 > ag_ban_hgrenade.value) + pPlayer->GiveAmmo( HANDGRENADE_MAX_CARRY, "Hand Grenade", HANDGRENADE_MAX_CARRY ); + if (1 > ag_ban_satchel.value) + pPlayer->GiveAmmo( SATCHEL_MAX_CARRY, "Satchel Charge", SATCHEL_MAX_CARRY ); + if (1 > ag_ban_tripmine.value) + pPlayer->GiveAmmo( TRIPMINE_MAX_CARRY, "Trip Mine", TRIPMINE_MAX_CARRY ); + if (1 > ag_ban_snark.value) + pPlayer->GiveAmmo( SNARK_MAX_CARRY, "Snarks", SNARK_MAX_CARRY ); + if (1 > ag_ban_hornet.value) + pPlayer->GiveAmmo( HORNET_MAX_CARRY, "Hornets", HORNET_MAX_CARRY ); + if (1 > ag_ban_m203.value) + pPlayer->GiveAmmo( M203_GRENADE_MAX_CARRY, "ARgrenades", M203_GRENADE_MAX_CARRY ); + if (1 > ag_ban_egon.value && 1 > ag_ban_gauss.value) + pPlayer->GiveAmmo( URANIUM_MAX_CARRY, "uranium", URANIUM_MAX_CARRY ); + if (1 > ag_ban_glock.value && 1 > ag_ban_9mmar.value) + pPlayer->GiveAmmo( _9MM_MAX_CARRY, "9mm", _9MM_MAX_CARRY ); + if (1 > ag_ban_357.value) + pPlayer->GiveAmmo( _357_MAX_CARRY, "357", _357_MAX_CARRY ); + if (1 > ag_ban_shotgun.value) + pPlayer->GiveAmmo( BUCKSHOT_MAX_CARRY, "buckshot", BUCKSHOT_MAX_CARRY ); + if (1 > ag_ban_crossbow.value) + pPlayer->GiveAmmo( BOLT_MAX_CARRY, "bolts", BOLT_MAX_CARRY ); + if (1 > ag_ban_rpg.value) + pPlayer->GiveAmmo( ROCKET_MAX_CARRY, "rockets", ROCKET_MAX_CARRY ); + } + else + { + //Normal spawn. + pPlayer->pev->health = ag_start_health.value; + pPlayer->pev->armorvalue = ag_start_armour.value; + + if (0 < ag_start_longjump.value) + { + pPlayer->m_fLongJump = TRUE; + g_engfuncs.pfnSetPhysicsKeyValue( pPlayer->edict(), "slj", "1" ); + pPlayer->OnPickupLongjump(); + } + if (0 < ag_start_glock.value) + pPlayer->GiveNamedItem( "weapon_9mmhandgun" ); + if (0 < ag_start_crowbar.value) + pPlayer->GiveNamedItem( "weapon_crowbar" ); + if (0 < ag_start_shotgun.value) + pPlayer->GiveNamedItem( "weapon_shotgun" ); + if (0 < ag_start_mp5.value) + pPlayer->GiveNamedItem( "weapon_9mmAR" ); + if (0 < ag_start_gauss.value) + pPlayer->GiveNamedItem( "weapon_gauss" ); + if (0 < ag_start_hgrenade.value) + pPlayer->GiveNamedItem( "weapon_handgrenade" ); + if (0 < ag_start_tripmine.value) + pPlayer->GiveNamedItem( "weapon_tripmine" ); + if (0 < ag_start_egon.value) + pPlayer->GiveNamedItem( "weapon_egon" ); + if (0 < ag_start_crossbow.value) + pPlayer->GiveNamedItem( "weapon_crossbow" ); + if (0 < ag_start_357.value) + pPlayer->GiveNamedItem( "weapon_357" ); + if (0 < ag_start_rpg.value) + pPlayer->GiveNamedItem( "weapon_rpg" ); + if (0 < ag_start_satchel.value) + pPlayer->GiveNamedItem( "weapon_satchel" ); + if (0 < ag_start_snark.value) + pPlayer->GiveNamedItem( "weapon_snark" ); + if (0 < ag_start_hornet.value) + pPlayer->GiveNamedItem( "weapon_hornetgun" ); + + if (0 < ag_start_hgrenade.value) + pPlayer->GiveAmmo( ag_start_hgrenade.value, "Hand Grenade", HANDGRENADE_MAX_CARRY ); + if (0 < ag_start_satchel.value) + pPlayer->GiveAmmo( ag_start_satchel.value, "Satchel Charge", SATCHEL_MAX_CARRY ); + if (0 < ag_start_tripmine.value) + pPlayer->GiveAmmo( ag_start_tripmine.value, "Trip Mine", TRIPMINE_MAX_CARRY ); + if (0 < ag_start_snark.value) + pPlayer->GiveAmmo( ag_start_snark.value, "Snarks", SNARK_MAX_CARRY ); + if (0 < ag_start_hornet.value) + pPlayer->GiveAmmo( ag_start_hornet.value, "Hornets", HORNET_MAX_CARRY ); + if (0 < ag_start_m203.value) + pPlayer->GiveAmmo( ag_start_m203.value, "ARgrenades", M203_GRENADE_MAX_CARRY ); + if (0 < ag_start_uranium.value) + pPlayer->GiveAmmo( ag_start_uranium.value, "uranium", URANIUM_MAX_CARRY ); + if (0 < ag_start_9mmar.value) + pPlayer->GiveAmmo( ag_start_9mmar.value, "9mm", _9MM_MAX_CARRY ); + if (0 < ag_start_357ammo.value) + pPlayer->GiveAmmo( ag_start_357ammo.value, "357", _357_MAX_CARRY ); + if (0 < ag_start_bockshot.value) + pPlayer->GiveAmmo( ag_start_bockshot.value, "buckshot", BUCKSHOT_MAX_CARRY ); + if (0 < ag_start_bolts.value) + pPlayer->GiveAmmo( ag_start_bolts.value, "bolts", BOLT_MAX_CARRY ); + if (0 < ag_start_rockets.value) + pPlayer->GiveAmmo( ag_start_rockets.value, "rockets", ROCKET_MAX_CARRY ); + } + } + pPlayer->m_bInSpawn = false; + + /* + //Quake1 teleport splash around him. + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_TELEPORT ); + WRITE_COORD(pPlayer->pev->origin.x); + WRITE_COORD(pPlayer->pev->origin.y); + WRITE_COORD(pPlayer->pev->origin.z); + MESSAGE_END(); + */ +} + +BOOL AgGameRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return FALSE; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return FALSE; + + ASSERT(NULL != pWeapon); + if (!pWeapon) + return FALSE; + + if ( !pWeapon->CanDeploy() ) + { + // that weapon can't deploy anyway. + return FALSE; + } + + if ( !pPlayer->m_pActiveItem ) + { + // player doesn't have an active item! + return TRUE; + } + + if ( !pPlayer->m_pActiveItem->CanHolster() ) + { + // can't put away the active item. + return FALSE; + } + + if (pPlayer->ShouldWeaponSwitch() && (pPlayer->GetWeaponWeight(pWeapon) > pPlayer->GetWeaponWeight(pPlayer->m_pActiveItem))) + { + return TRUE; + } + return FALSE; +} + + +BOOL AgGameRules::GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return FALSE; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return FALSE; + + ASSERT(NULL != pCurrentWeapon); + if (!pCurrentWeapon) + return FALSE; + + + CBasePlayerItem *pCheck; + CBasePlayerItem *pBest;// this will be used in the event that we don't find a weapon in the same category. + int iBestWeight; + int i; + + iBestWeight = -1;// no weapon lower than -1 can be autoswitched to + pBest = NULL; + + if ( !pCurrentWeapon->CanHolster() ) + { + // can't put this gun away right now, so can't switch. + return FALSE; + } + + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + pCheck = pPlayer->m_rgpPlayerItems[ i ]; + + while ( pCheck ) + { + if ( pPlayer->GetWeaponWeight(pCheck) > -1 && pPlayer->GetWeaponWeight(pCheck) == pPlayer->GetWeaponWeight(pCurrentWeapon) && pCheck != pCurrentWeapon ) + { + // this weapon is from the same category. + if ( pCheck->CanDeploy() ) + { + if ( pPlayer->SwitchWeapon( pCheck ) ) + { + return TRUE; + } + } + } + else if ( pPlayer->GetWeaponWeight(pCheck) > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of + { + //ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) ); + // we keep updating the 'best' weapon just in case we can't find a weapon of the same weight + // that the player was using. This will end up leaving the player with his heaviest-weighted + // weapon. + if ( pCheck->CanDeploy() ) + { + // if this weapon is useable, flag it as the best + iBestWeight = pPlayer->GetWeaponWeight(pCheck); + pBest = pCheck; + } + } + + pCheck = pCheck->m_pNext; + } + } + + // if we make it here, we've checked all the weapons and found no useable + // weapon in the same catagory as the current weapon. + + // if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always + // at least get the crowbar, but ya never know. + if ( !pBest ) + { + return FALSE; + } + + pPlayer->SwitchWeapon( pBest ); + + return TRUE; +} + +const char* AgGameRules::GetIPAddress(edict_t *pEntity) +{ + if (0 == m_mapIPAddress.size()) + return ""; + AgIPAddress::iterator itrIPAddress = m_mapIPAddress.find(ENTINDEX(pEntity)); + if (itrIPAddress != m_mapIPAddress.end()) + return (*itrIPAddress).second.c_str(); + return ""; + +} + +BOOL AgGameRules :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) +{ + if (0 != strcmp("127.0.0.1", pszAddress)) + { + if (0 == m_mapIPAddress.size()) + { + m_mapIPAddress.insert(AgIPAddress::value_type(ENTINDEX(pEntity), pszAddress)); + return TRUE; + } + + AgIPAddress::iterator itrIPAddress = m_mapIPAddress.find(ENTINDEX(pEntity)); + if (itrIPAddress == m_mapIPAddress.end()) + m_mapIPAddress.insert(AgIPAddress::value_type(ENTINDEX(pEntity), pszAddress)); + else + (*itrIPAddress).second = ENTINDEX(pEntity); + } + return TRUE; +} + +void AgGameRules::ClientDisconnected( edict_t *pClient ) +{ + ASSERT(NULL != pClient); + if ( pClient ) + { + CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); + ASSERT(NULL != pPlayer); + if (pPlayer) + { + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + UTIL_LogPrintf("\"%s<%d><%s><%s>\" disconnected (score \"%.0f\")\n", + pPlayer->GetName(), GETPLAYERUSERID( pPlayer->edict() ), GETPLAYERAUTHID( pPlayer->edict() ), pPlayer->TeamID(), + pPlayer->pev->frags ); + + // Tell all clients this player isn't a spectator anymore + MESSAGE_BEGIN( MSG_ALL, gmsgSpectator ); + WRITE_BYTE( ENTINDEX(pPlayer->edict()) ); + WRITE_BYTE( 0 ); + MESSAGE_END(); + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayer != pPlayerLoop ) + { + //Send score to others. + ClientPrint(pPlayerLoop->pev, HUD_PRINTNOTIFY, UTIL_VarArgs("%s left with score %.0f\n",pPlayer->GetName(),pPlayer->pev->frags)); + + if ((CBaseEntity*)pPlayerLoop->m_hSpectateTarget == pPlayer) + { + //Move to next player. + pPlayerLoop->Spectate_Nextplayer(false); + } + } + } + + if (ARENA == AgGametype()) + m_Arena.ClientDisconnected(pPlayer); + else if (LMS == AgGametype()) + m_LMS.ClientDisconnected(pPlayer); + else if (CTF == AgGametype()) + m_CTF.ClientDisconnected(pPlayer); + //++ muphicks + else if (DOM == AgGametype()) + m_DOM.ClientDisconnected(pPlayer); + //-- muphicks + } + } +} + + + +int AgGameRules::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) +{ + ASSERT(NULL != pAttacker); + ASSERT(NULL != pKilled); + if (!pAttacker || !pKilled) + return 1; + + if (ARCADE == AgGametype() || INSTAGIB == AgGametype()) + { + if (pAttacker && pKilled && pAttacker != pKilled && pAttacker->IsAlive() && pAttacker->pev) + { + //As a reward for your kill you get full health and ammo. + pAttacker->pev->armorvalue = MAX_NORMAL_BATTERY; + pAttacker->pev->health = MAX_NORMAL_BATTERY; + + //Fill clip in all weapons weapon + for (int i = 0 ; i < MAX_ITEM_TYPES; i++) + { + if (pAttacker->m_rgpPlayerItems[i]) + { + CBasePlayerItem* pPlayerItem = pAttacker->m_rgpPlayerItems[i]; + while (pPlayerItem) + { + CBasePlayerWeapon* pWeapon = (CBasePlayerWeapon*)pPlayerItem->GetWeaponPtr(); + if (pWeapon) + pWeapon->m_iClip = pWeapon->iMaxClip(); + pPlayerItem = pPlayerItem->m_pNext; + } + } + } + + if (0 < ag_start_hgrenade.value) + pAttacker->GiveAmmo( ag_start_hgrenade.value, "Hand Grenade", HANDGRENADE_MAX_CARRY ); + if (0 < ag_start_satchel.value) + pAttacker->GiveAmmo( ag_start_satchel.value, "Satchel Charge", SATCHEL_MAX_CARRY ); + if (0 < ag_start_tripmine.value) + pAttacker->GiveAmmo( ag_start_tripmine.value, "Trip Mine", TRIPMINE_MAX_CARRY ); + if (0 < ag_start_snark.value) + pAttacker->GiveAmmo( ag_start_snark.value, "Snarks", SNARK_MAX_CARRY ); + if (0 < ag_start_hornet.value) + pAttacker->GiveAmmo( ag_start_hornet.value, "Hornets", HORNET_MAX_CARRY ); + if (0 < ag_start_m203.value) + pAttacker->GiveAmmo( ag_start_m203.value, "ARgrenades", M203_GRENADE_MAX_CARRY ); + if (0 < ag_start_uranium.value) + pAttacker->GiveAmmo( ag_start_uranium.value, "uranium", URANIUM_MAX_CARRY ); + if (0 < ag_start_9mmar.value) + pAttacker->GiveAmmo( ag_start_9mmar.value, "9mm", _9MM_MAX_CARRY ); + if (0 < ag_start_357ammo.value) + pAttacker->GiveAmmo( ag_start_357ammo.value, "357", _357_MAX_CARRY ); + if (0 < ag_start_bockshot.value) + pAttacker->GiveAmmo( ag_start_bockshot.value, "buckshot", BUCKSHOT_MAX_CARRY ); + if (0 < ag_start_bolts.value) + pAttacker->GiveAmmo( ag_start_bolts.value, "bolts", BOLT_MAX_CARRY ); + if (0 < ag_start_rockets.value) + pAttacker->GiveAmmo( ag_start_rockets.value, "rockets", ROCKET_MAX_CARRY ); + } + } + + return 1; +} + +void AgGameRules::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor) +{ + if (!pVictim || !pKiller || !pInflictor) + return; + + CBaseEntity* pKillerBE = CBaseEntity::Instance(pKiller); + CBasePlayer* pKillerPlayer = NULL; + if (pKillerBE && CLASS_PLAYER == pKillerBE->Classify()) + pKillerPlayer = ((CBasePlayer*)pKillerBE); + +#ifdef AGSTATS + if (pKillerPlayer && pVictim) + Stats.PlayerKilled(pKillerPlayer, pVictim); +#endif + + //Update the score cache. + m_ScoreCache.UpdateScore(pVictim); + if (pKillerPlayer && pVictim != pKillerPlayer ) + m_ScoreCache.UpdateScore(pKillerPlayer); +} + + +struct BANWEAPON +{ + char szWeapon[20]; + cvar_t* pBan; +}; +FILE_GLOBAL BANWEAPON s_Bans[] = +{ + "weapon_crowbar",&ag_ban_crowbar, + "weapon_9mmhandgun",&ag_ban_glock, + "weapon_shotgun",&ag_ban_357, + "weapon_9mmAR",&ag_ban_mp5, + "weapon_shotgun",&ag_ban_shotgun, + "weapon_crossbow",&ag_ban_crossbow, + "weapon_357",&ag_ban_357, + "weapon_rpg",&ag_ban_rpg, + "weapon_gauss",&ag_ban_gauss, + "weapon_egon",&ag_ban_egon, + "weapon_hornetgun",&ag_ban_hornet, + "weapon_handgrenade",&ag_ban_hgrenade, + "weapon_satchel",&ag_ban_satchel, + "weapon_tripmine",&ag_ban_tripmine, + "weapon_snark",&ag_ban_snark, + "item_longjump",&ag_ban_longjump, + "ammo_ARgrenades",&ag_ban_m203, + "ammo_9mmclip",&ag_ban_9mmar, + "ammo_9mmAR",&ag_ban_9mmar, + "ammo_mp5clip",&ag_ban_9mmar, + "ammo_9mmbox",&ag_ban_9mmar, + "ammo_buckshot",&ag_ban_bockshot, + "ammo_gaussclip",&ag_ban_uranium, + "ammo_crossbow",&ag_ban_bolts, + "ammo_rpgclip",&ag_ban_rockets, + "ammo_357",&ag_ban_357ammo, + "item_battery",&ag_ban_armour, + "item_healthkit",&ag_ban_health, +}; + + +BOOL AgGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem ) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return FALSE; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return FALSE; + ASSERT(NULL != pItem); + if (!pItem) + return FALSE; + if (!pPlayer->IsAlive()) + return FALSE; + + if (ARENA == AgGametype() && m_Arena.CanHaveItem()) + return TRUE; + + const char* pszClass = STRING(pItem->pev->classname); + if (0 == strncmp( pszClass, "weapon_", 7 ) || + 0 == strncmp( pszClass, "ammo_", 5 ) || + 0 == strncmp( pszClass, "item_", 5 ) ) + { + int iCount = sizeof(s_Bans)/sizeof(s_Bans[0]); + for (int i = 0; i < iCount; i++) + { + if (FStrEq(pszClass,s_Bans[i].szWeapon)) + { + if (1 > s_Bans[i].pBan->value) + return CGameRules::CanHavePlayerItem(pPlayer,pItem); + else + return FALSE; + } + } + } + + return CGameRules::CanHavePlayerItem(pPlayer,pItem); +} + +BOOL AgGameRules::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return FALSE; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return FALSE; + ASSERT(NULL != pItem); + if (!pItem) + return FALSE; + if (!pPlayer->IsAlive()) + return FALSE; + + if (ARENA == AgGametype() && m_Arena.CanHaveItem()) + return TRUE; + + const char* pszClass = STRING(pItem->pev->classname); + if (0 == strncmp( pszClass, "item_", 5 ) ) + { + int iCount = sizeof(s_Bans)/sizeof(s_Bans[0]); + for (int i = 0; i < iCount; i++) + { + if (FStrEq(pszClass,s_Bans[i].szWeapon)) + return 1 > s_Bans[i].pBan->value; + } + } + return TRUE; +} + +BOOL AgGameRules::IsAllowedToSpawn( const char* pszClass ) +{ + //Check if item is banned. + if (0 == strncmp( pszClass, "weapon_", 7 ) || + 0 == strncmp( pszClass, "ammo_", 5 ) || + 0 == strncmp( pszClass, "item_", 5 ) ) + { + int iCount = sizeof(s_Bans)/sizeof(s_Bans[0]); + for (int i = 0; i < iCount; i++) + { + if (FStrEq(pszClass,s_Bans[i].szWeapon)) + return 1 > s_Bans[i].pBan->value; + } + } + + return TRUE; +} + +BOOL AgGameRules::IsAllowedToSpawn( CBaseEntity *pEntity ) +{ + ASSERT(NULL != pEntity); + if (!pEntity) + return FALSE; + + if (ARENA == AgGametype() && m_Arena.CanHaveItem()) + return TRUE; + + return IsAllowedToSpawn(STRING(pEntity->pev->classname)); +} + + +void AgGameRules::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) +{ +} + +void AgGameRules::ClientUserInfoChanged(CBasePlayer *pPlayer, char *infobuffer ) +{ +#ifdef AG_USE_CHEATPROTECTION + const char* pszModel = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); + if (pszModel && strlen(pszModel) && 0 != strcmp(pPlayer->m_szModel,pszModel)) + { + strncpy(pPlayer->m_szModel, pszModel, sizeof(pPlayer->m_szModel) - 1); + pPlayer->m_szModel[sizeof(pPlayer->m_szModel) - 1] = '\0'; + + MESSAGE_BEGIN( MSG_ALL, gmsgSpikeCheck); + WRITE_STRING(pszModel); + MESSAGE_END(); + } +#endif //AG_USE_CHEATPROTECTION + + char* pszAutoWepSwitch = g_engfuncs.pfnInfoKeyValue( infobuffer, "cl_autowepswitch"); + if (strlen(pszAutoWepSwitch)) + pPlayer->m_iAutoWepSwitch = atoi(pszAutoWepSwitch); + + char* pszDisableSpecs = g_engfuncs.pfnInfoKeyValue( infobuffer, "cl_disablespecs"); + if (strlen(pszDisableSpecs)) + pPlayer->m_iDisableSpecs = atoi(pszDisableSpecs); + + /* + char* pszWeaponWeights = g_engfuncs.pfnInfoKeyValue( infobuffer, "cl_weaponweights" ); + if (strlen(pszWeaponWeights)) + pPlayer->SetWeaponWeights(pszWeaponWeights); + */ +} + +void AgGameRules::InitHUD( CBasePlayer *pPlayer ) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + //Send server name. + MESSAGE_BEGIN( MSG_ONE, gmsgServerName, NULL, pPlayer->edict() ); + WRITE_STRING( m_sHostname.substr(0,30).c_str() ); + MESSAGE_END(); + +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_ONE, gmsgGametype, NULL, pPlayer->edict() ); + WRITE_BYTE( AgGametype()); + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_ALL, gmsgAuthID); + WRITE_BYTE( pPlayer->entindex() ); + WRITE_STRING(pPlayer->GetAuthID()); + MESSAGE_END(); +#endif + +#ifdef AG_USE_CHEATPROTECTION + const char* pszModel = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); + if (pszModel && strlen(pszModel)) + { + MESSAGE_BEGIN( MSG_ALL, gmsgSpikeCheck); + WRITE_STRING(pszModel); + MESSAGE_END(); + } +#endif //AG_USE_CHEATPROTECTION +} + +void AgGameRules::GoToIntermission() +{ + //Log scores + if (ARENA != AgGametype() && LMS != AgGametype()) + { + m_ScoreLog.End(); + CVAR_SET_FLOAT("sv_ag_match_running",0); + CVAR_SET_FLOAT("sv_ag_show_gibs",1); + CVAR_SET_FLOAT("ag_spectalk",1); + } +} + +BOOL AgGameRules::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return FALSE; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return FALSE; + + if (!g_bPaused && INSTAGIB == AgGametype()) + { + ASSERT(NULL != pAttacker); + if (!pAttacker) + return FALSE; + ASSERT(NULL != pAttacker->pev); + if (!pAttacker->pev) + return FALSE; + + if (CLASS_PLAYER == pAttacker->Classify()) + { + //This dude is instant dead! + pPlayer->pev->health = -200; + pPlayer->Killed(pAttacker->pev, GIB_NEVER); + return FALSE; + } + } + + if (ARENA == AgGametype()) + return (m_Arena.CanTakeDamage() && !g_bPaused); + else if (LMS == AgGametype()) + return (m_LMS.CanTakeDamage() && !g_bPaused); + + return !g_bPaused; +} + +void AgGameRules::ChangeNextLevel() +{ + m_Settings.ChangeNextLevel(); +} + +void AgGameRules::ResendScoreBoard() +{ + if (g_pGameRules->IsTeamplay()) + { + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* plr = AgPlayerByIndex( i ); + if ( plr ) + { + //Team + if ( plr && g_pGameRules->IsValidTeam( plr->TeamID() ) ) + { + MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + WRITE_BYTE( plr->entindex() ); + WRITE_STRING( plr->TeamID() ); + MESSAGE_END(); + } + } + } + } + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* plr = AgPlayerByIndex( i ); + if ( plr ) + { + //Score + MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); + WRITE_BYTE( ENTINDEX(plr->edict()) ); + WRITE_SHORT( plr->pev->frags ); + WRITE_SHORT( plr->m_iDeaths ); + //++ BulliT + WRITE_SHORT( g_teamplay ); + WRITE_SHORT( g_pGameRules->GetTeamIndex( plr->m_szTeamName ) + 1 ); + //-- Martin Webrant + MESSAGE_END(); + + //Spectator + MESSAGE_BEGIN(MSG_ALL,gmsgSpectator); + WRITE_BYTE(ENTINDEX(plr->edict())); + WRITE_BYTE(plr->IsSpectator() ? 1 : 0); + MESSAGE_END(); + } + } +} + +void AgGameRules::RefreshSkillData( void ) +{ + // load all default values + CGameRules::RefreshSkillData(); + +// override some values for multiplay. + // suitcharger + gSkillData.suitchargerCapacity = 30; + + // Crowbar whack + gSkillData.plrDmgCrowbar = ag_dmg_crowbar.value; + + // Glock Round + gSkillData.plrDmg9MM = ag_dmg_glock.value; + + // 357 Round + gSkillData.plrDmg357 = ag_dmg_357.value; + + // MP5 Round + gSkillData.plrDmgMP5 = ag_dmg_mp5.value; + + // M203 grenade + gSkillData.plrDmgM203Grenade = ag_dmg_m203.value; + + // Shotgun buckshot + gSkillData.plrDmgBuckshot = ag_dmg_shotgun.value; + + // Crossbow + gSkillData.plrDmgCrossbowClient = ag_dmg_crossbow.value; + gSkillData.plrDmgCrossbowMonster = ag_dmg_bolts.value; + + // RPG + gSkillData.plrDmgRPG = ag_dmg_rpg.value; + + // Egon + gSkillData.plrDmgEgonWide = ag_dmg_egon_wide.value; + gSkillData.plrDmgEgonNarrow = ag_dmg_egon_narrow.value; + + // Hand Grendade + gSkillData.plrDmgHandGrenade = ag_dmg_hgrenade.value; + + // Satchel Charge + gSkillData.plrDmgSatchel = ag_dmg_satchel.value; + + // Tripmine + gSkillData.plrDmgTripmine = ag_dmg_tripmine.value; + + // hornet + gSkillData.plrDmgHornet = ag_dmg_hornet.value; + + // Head + gSkillData.plrHead = ag_headshot.value; +} + + +void AgGameRules::HLTV_ResendScoreBoard() +{ + if (!m_bProxyConnected) + return; + + if (g_pGameRules->IsTeamplay()) + { + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* plr = AgPlayerByIndex( i ); + if ( plr ) + { + //Team + if ( plr && g_pGameRules->IsValidTeam( plr->TeamID() ) ) + { + MESSAGE_BEGIN( MSG_SPEC, gmsgTeamInfo ); + WRITE_BYTE( plr->entindex() ); + WRITE_STRING( plr->TeamID() ); + MESSAGE_END(); + } + } + } + } + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* plr = AgPlayerByIndex( i ); + if ( plr ) + { + //Score + MESSAGE_BEGIN( MSG_SPEC, gmsgScoreInfo ); + WRITE_BYTE( ENTINDEX(plr->edict()) ); + WRITE_SHORT( plr->pev->frags ); + WRITE_SHORT( plr->m_iDeaths ); + //++ BulliT + WRITE_SHORT( g_teamplay ); + WRITE_SHORT( g_pGameRules->GetTeamIndex( plr->m_szTeamName ) + 1 ); + //-- Martin Webrant + MESSAGE_END(); + + //Spectator + MESSAGE_BEGIN(MSG_SPEC,gmsgSpectator); + WRITE_BYTE(ENTINDEX(plr->edict())); + WRITE_BYTE(plr->IsSpectator() ? 1 : 0); + MESSAGE_END(); + } + } + + MESSAGE_BEGIN(MSG_SPEC,gmsgGameMode); + WRITE_BYTE(g_teamplay); + MESSAGE_END(); +} + +/* +class AgTeam +{ +public: + AgTeam(const char* pszTeam) + { + m_strName = pszTeam; + m_iCount = 0; + } + + AgString m_strName; + + int m_iCount; +}; + +struct lessagteam : binary_function { + bool operator()(const AgTeam& x, const AgTeam& y) const + { + if (x.m_strName.compare(y.m_strName) < 0) + return true; + else + return false; + } +}; + +AgString CHalfLifeTeamplay::GetTeamWithFewestPlayers() +{ +//++ BulliT + if (CTF == AgGametype()) + { + if (GetTeamIndex(CTF_TEAM1_NAME) == -1) + return CTF_TEAM1_NAME; + else if (GetTeamIndex(CTF_TEAM2_NAME) == -1) + return CTF_TEAM2_NAME; + } +//-- Martin Webrant + + char *pName; + char szTeamList[TEAMPLAY_TEAMLISTLENGTH]; + typedef set AgTeamSet; + + AgTeamSet setTeams; + + // Copy all of the teams from the teamlist + // make a copy because strtok is destructive + strcpy( szTeamList, m_szTeamList ); + pName = szTeamList; + pName = strtok( pName, ";" ); + while ( pName != NULL && *pName ) + { + setTeams.insert(AgTeam(pName)); + pName = strtok( NULL, ";" ); + } + + int i; + int minPlayers = MAX_TEAMS; + int teamCount[ MAX_TEAMS ]; + char *pTeamName = NULL; + + memset( teamCount, 0, MAX_TEAMS * sizeof(int) ); + + // loop through all clients, count number of players on each team + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + AgTeamSet::iterator itrTeams = setTeams.find(pPlayerLoop->m_szTeamName); + (*itrTeams).m_iCount++; + } + } + + AgTeamSet::iterator itrTeams; + int iMinPlayers = MAX_TEAMS; + AgString strTeam; + for (itrTeams = setTeams.begin() ;itrTeams != setTeams.end(); ++itrTeams) + { + if ((*itrTeams).m_iCount < iMinPlayers) + { + iMinPlayers = (*itrTeams).m_iCount; + strTeam = (*itrTeams).m_strName; + } + } + + return strTeam; +} +*/ + +#define MAX_MAPLIST_CHUNK 190 + +AgString g_sMapList; +void AgGameRules::SendMapListToClient(CBasePlayer* pPlayer, bool bStart) +{ + if (-1 == pPlayer->m_iMapListSent) + { + if (bStart) + pPlayer->m_iMapListSent = 0; + else + return; + } + + if (0 == g_sMapList.size()) + { + char szDirAG[MAX_PATH]; + char szDirVALVE[MAX_PATH]; + sprintf(szDirAG, "%s/maps", AgGetDirectory()); + sprintf(szDirVALVE, "%s/maps", AgGetDirectoryValve()); + + AgStringSet setFiles; + AgStringSet::iterator itrFiles; + + AgDirList(szDirAG,setFiles); + AgDirList(szDirVALVE,setFiles); + + for (itrFiles = setFiles.begin() ;itrFiles != setFiles.end(); ++itrFiles) + { + AgString sFile = *itrFiles; + AgToLower(sFile); + if (!strstr(sFile.c_str(),".bsp")) + continue; + sFile = sFile.substr(0,sFile.size()-4); + AgTrim(sFile); + g_sMapList += sFile + "#"; + } + + } + + //Send it over in chunks. + int iDataToSend = min((int)g_sMapList.size()-pPlayer->m_iMapListSent,MAX_MAPLIST_CHUNK); + AgString sChunk = g_sMapList.substr(pPlayer->m_iMapListSent,iDataToSend); + pPlayer->m_iMapListSent += iDataToSend; + MESSAGE_BEGIN( MSG_ONE, gmsgMapList, NULL, pPlayer->edict() ); + WRITE_BYTE( pPlayer->m_iMapListSent < (int)g_sMapList.size() ); + WRITE_STRING( sChunk.c_str() ); + MESSAGE_END(); + + if (pPlayer->m_iMapListSent >= (int)g_sMapList.size()) + pPlayer->m_iMapListSent = -1; +} + + +//-- Martin Webrant + diff --git a/dlls/aghl/aggamerules.h b/dlls/aghl/aggamerules.h new file mode 100644 index 00000000..f01030a3 --- /dev/null +++ b/dlls/aghl/aggamerules.h @@ -0,0 +1,111 @@ +//++ BulliT + +#if !defined(AFX_AGGAMERULES_H__5F634943_35DD_4A80_922F_A0A82C815D99__INCLUDED_) +#define AFX_AGGAMERULES_H__5F634943_35DD_4A80_922F_A0A82C815D99__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "agscorecache.h" +#include "agadmincache.h" +#include "agglobal.h" +#include "agsettings.h" +#include "agtimer.h" +#include "agmatch.h" +#include "agscorelog.h" +#include "agvote.h" +#include "agclient.h" +#include "agarena.h" +#include "aglms.h" +#include "agctf.h" +#include "agdom.h" +#include "aginfointermission.h" +#include "agsuddendeath.h" +#include "agtimeout.h" +#include "aggamemode.h" +#ifdef AG_NO_CLIENT_DLL +#include "aglocationcache.h" +#endif + +class AgGameRules : public CGameRules +{ +protected: + AgString m_sHostname; + typedef map > AgIPAddress; + AgIPAddress m_mapIPAddress; + +public: + AgGameRules(); + virtual ~AgGameRules(); + + //Overidden + virtual BOOL ClientCommand(CBasePlayer* pPlayer, const char *pcmd); + + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); + + virtual BOOL FPlayerCanRespawn(CBasePlayer* pPlayer); + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// should the player switch to this weapon? + virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); + + virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); + virtual void ClientDisconnected( edict_t *pClient );// a client just disconnected from the server + + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); + virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? + virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor );// Called each time a player dies + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + + virtual void ClientUserInfoChanged(CBasePlayer *pPlayer, char *infobuffer); + virtual void InitHUD( CBasePlayer *pl ); + + virtual void GoToIntermission(); + + virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); + + virtual void RefreshSkillData( void ); + + virtual const char *GetGameDescription( void ) { return AgGamename().c_str(); } // this is the game name that gets seen in the server browser + //New + bool AgThink(); + void Start(const AgString& sSpawn); + void ChangeNextLevel(); + void ResendScoreBoard(); + void HLTV_ResendScoreBoard(); + //AgString GetTeamWithFewestPlayers(); + virtual BOOL IsAllowedToSpawn( const char* pszClass ); + + void SendMapListToClient(CBasePlayer* pPlayer, bool bStart); + + const char* GetIPAddress(edict_t *pEntity); + bool m_bProxyConnected; + //Helper classes + AgScoreCache m_ScoreCache; + AgSettings m_Settings; + AgTimer m_Timer; + AgMatch m_Match; + AgScoreLog m_ScoreLog; + AgVote m_Vote; + AgClient m_Client; + AgArena m_Arena; + AgLMS m_LMS; + AgCTF m_CTF; + AgDOM m_DOM; + AgInfoIntermission m_InfoInterMission; + AgSuddenDeath m_SuddenDeath; + AgTimeout m_Timeout; +#ifdef AG_NO_CLIENT_DLL + AgLocationCache m_LocationCache; +#endif +}; + + + + +#endif // !defined(AFX_AGGAMERULES_H__5F634943_35DD_4A80_922F_A0A82C815D99__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agglobal.cpp b/dlls/aghl/agglobal.cpp new file mode 100644 index 00000000..aeeb53d9 --- /dev/null +++ b/dlls/aghl/agglobal.cpp @@ -0,0 +1,1096 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "trains.h" +#include "nodes.h" +#include "weapons.h" +#include "soundent.h" +#include "monsters.h" +#include "../engine/shake.h" +#include "agglobal.h" +#include "agcommand.h" +#include "agwallhack.h" +#include "gamerules.h" +#include +#ifndef _WIN32 +#include +#include +#include +#endif + + +void AgInitTimer(); + +#ifdef AG_NO_CLIENT_DLL +DLL_GLOBAL cvar_t ag_version = {"sv_ag_version","6.6mini", FCVAR_SERVER }; +#else +DLL_GLOBAL cvar_t ag_version = {"sv_ag_version","6.6", FCVAR_SERVER }; +#endif + +DLL_GLOBAL cvar_t ag_gamemode = {"sv_ag_gamemode","ffa", FCVAR_SERVER }; //The current gamemode +DLL_GLOBAL cvar_t ag_allowed_gamemodes = {"sv_ag_allowed_gamemodes",""}; + +DLL_GLOBAL cvar_t ag_pure = {"sv_ag_pure","0",FCVAR_SERVER }; //Default off. + +DLL_GLOBAL cvar_t ag_match_running = {"sv_ag_match_running","0",FCVAR_SERVER|FCVAR_UNLOGGED}; //Default not match. Protects players from wondering into the server. + +DLL_GLOBAL cvar_t ag_oldphysics = {"sv_ag_oldphysics","1"}; + +DLL_GLOBAL cvar_t ag_allow_timeout = {"sv_ag_allow_timeout","1"}; //Allow timeout. + +DLL_GLOBAL cvar_t ag_allow_vote = {"sv_ag_allow_vote","1", FCVAR_SERVER|FCVAR_UNLOGGED}; //Voting is enabled by default. +DLL_GLOBAL cvar_t ag_vote_start = {"sv_ag_vote_start","1", FCVAR_SERVER|FCVAR_UNLOGGED}; //Start voting enabled by default +DLL_GLOBAL cvar_t ag_vote_setting = {"sv_ag_vote_setting","1"}; //Setting voting enabled by default +DLL_GLOBAL cvar_t ag_vote_gamemode = {"sv_ag_vote_gamemode","1", FCVAR_SERVER|FCVAR_UNLOGGED}; //Gamemode voting is enabled by default. +DLL_GLOBAL cvar_t ag_vote_kick = {"sv_ag_vote_kick","0"}; //Kick voting is disabled by default. +DLL_GLOBAL cvar_t ag_vote_allow = {"sv_ag_vote_allow","1"}; //All voting is enabled by default. +DLL_GLOBAL cvar_t ag_vote_admin = {"sv_ag_vote_admin","0"}; //Admin voting is disabled by default. +DLL_GLOBAL cvar_t ag_vote_map = {"sv_ag_vote_map","1", FCVAR_SERVER|FCVAR_UNLOGGED}; //Map voting is enabled by default. +DLL_GLOBAL cvar_t ag_vote_failed_time = {"sv_ag_vote_failed_time","30"}; + +DLL_GLOBAL cvar_t ag_start_minplayers = {"sv_ag_start_minplayers","2"}; + +DLL_GLOBAL cvar_t ag_vote_mp_timelimit_low = {"sv_ag_vote_mp_timelimit_low","10"}; +DLL_GLOBAL cvar_t ag_vote_mp_timelimit_high = {"sv_ag_vote_mp_timelimit_high","40"}; +DLL_GLOBAL cvar_t ag_vote_mp_fraglimit_low = {"sv_ag_vote_mp_fraglimit_low","0"}; +DLL_GLOBAL cvar_t ag_vote_mp_fraglimit_high = {"sv_ag_vote_mp_fraglimit_high","100"}; + +DLL_GLOBAL cvar_t ag_floodmsgs = {"sv_ag_floodmsgs","4"}; +DLL_GLOBAL cvar_t ag_floodpersecond = {"sv_ag_floodpersecond","4"}; +DLL_GLOBAL cvar_t ag_floodwaitdelay = {"sv_ag_floodwaitdelay","10"}; + +DLL_GLOBAL cvar_t ag_player_id = {"sv_ag_player_id","5"}; //Default 5 seconds. +DLL_GLOBAL cvar_t ag_auto_admin = {"sv_ag_auto_admin","1"}; //Default 1 = Autoauthenticate admins based on won id. + +DLL_GLOBAL cvar_t ag_lj_timer = {"sv_ag_lj_timer","0"}; //Default 0 = turned off. + +DLL_GLOBAL cvar_t ag_wallgauss = {"sv_ag_wallgauss","1"}; //Default 1 = Lame wallgauss on. +DLL_GLOBAL cvar_t ag_headshot = {"sv_ag_headshot","3"}; //Default 3 = 3 times damage +DLL_GLOBAL cvar_t ag_blastradius = {"sv_ag_blastradius","1"}; //Default 1 = Standard radius + + +DLL_GLOBAL cvar_t ag_ban_crowbar = {"sv_ag_ban_crowbar","0"}; +DLL_GLOBAL cvar_t ag_ban_glock = {"sv_ag_ban_glock","0"}; +DLL_GLOBAL cvar_t ag_ban_357 = {"sv_ag_ban_357","0"}; +DLL_GLOBAL cvar_t ag_ban_mp5 = {"sv_ag_ban_mp5","0"}; +DLL_GLOBAL cvar_t ag_ban_shotgun = {"sv_ag_ban_shotgun", "0"}; +DLL_GLOBAL cvar_t ag_ban_crossbow = {"sv_ag_ban_crossbow", "0"}; +DLL_GLOBAL cvar_t ag_ban_rpg = {"sv_ag_ban_rpg","0"}; +DLL_GLOBAL cvar_t ag_ban_gauss = {"sv_ag_ban_gauss","0"}; +DLL_GLOBAL cvar_t ag_ban_egon = {"sv_ag_ban_egon","0"}; +DLL_GLOBAL cvar_t ag_ban_hornet = {"sv_ag_ban_hornet","0"}; + +DLL_GLOBAL cvar_t ag_ban_hgrenade = {"sv_ag_ban_hgrenade","0"}; +DLL_GLOBAL cvar_t ag_ban_satchel = {"sv_ag_ban_satchel","0"}; +DLL_GLOBAL cvar_t ag_ban_tripmine = {"sv_ag_ban_tripmine","0"}; +DLL_GLOBAL cvar_t ag_ban_snark = {"sv_ag_ban_snark","0"}; +DLL_GLOBAL cvar_t ag_ban_longjump = {"sv_ag_ban_longjump","0"}; +DLL_GLOBAL cvar_t ag_ban_m203 = {"sv_ag_ban_m203","0"}; +DLL_GLOBAL cvar_t ag_ban_9mmar = {"sv_ag_ban_9mmar","0"}; +DLL_GLOBAL cvar_t ag_ban_bockshot = {"sv_ag_ban_bockshot","0"}; +DLL_GLOBAL cvar_t ag_ban_uranium = {"sv_ag_ban_uranium","0"}; +DLL_GLOBAL cvar_t ag_ban_bolts = {"sv_ag_ban_bolts","0"}; +DLL_GLOBAL cvar_t ag_ban_rockets = {"sv_ag_ban_rockets","0"}; +DLL_GLOBAL cvar_t ag_ban_357ammo = {"sv_ag_ban_357ammo","0"}; + +DLL_GLOBAL cvar_t ag_ban_armour = {"sv_ag_ban_armour","0"}; +DLL_GLOBAL cvar_t ag_ban_health = {"sv_ag_ban_health","0"}; +DLL_GLOBAL cvar_t ag_ban_recharg = {"sv_ag_ban_recharg","0"}; + +DLL_GLOBAL cvar_t ag_start_crowbar = {"sv_ag_start_crowbar","1"}; +DLL_GLOBAL cvar_t ag_start_glock = {"sv_ag_start_glock","1"}; +DLL_GLOBAL cvar_t ag_start_357 = {"sv_ag_start_357","0"}; +DLL_GLOBAL cvar_t ag_start_mp5 = {"sv_ag_start_mp5","0"}; +DLL_GLOBAL cvar_t ag_start_shotgun = {"sv_ag_start_shotgun", "0"}; +DLL_GLOBAL cvar_t ag_start_crossbow = {"sv_ag_start_crossbow", "0"}; +DLL_GLOBAL cvar_t ag_start_rpg = {"sv_ag_start_rpg","0"}; +DLL_GLOBAL cvar_t ag_start_gauss = {"sv_ag_start_gauss","0"}; +DLL_GLOBAL cvar_t ag_start_egon = {"sv_ag_start_egon","0"}; +DLL_GLOBAL cvar_t ag_start_hornet = {"sv_ag_start_hornet","0"}; + +DLL_GLOBAL cvar_t ag_start_hgrenade = {"sv_ag_start_hgrenade","0"}; +DLL_GLOBAL cvar_t ag_start_satchel = {"sv_ag_start_satchel","0"}; +DLL_GLOBAL cvar_t ag_start_tripmine = {"sv_ag_start_tripmine","0"}; +DLL_GLOBAL cvar_t ag_start_snark = {"sv_ag_start_snark","0"}; +DLL_GLOBAL cvar_t ag_start_longjump = {"sv_ag_start_longjump","0"}; +DLL_GLOBAL cvar_t ag_start_m203 = {"sv_ag_start_m203","0"}; +DLL_GLOBAL cvar_t ag_start_9mmar = {"sv_ag_start_9mmar","68"}; +DLL_GLOBAL cvar_t ag_start_bockshot = {"sv_ag_start_bockshot","0"}; +DLL_GLOBAL cvar_t ag_start_uranium = {"sv_ag_start_uranium","0"}; +DLL_GLOBAL cvar_t ag_start_bolts = {"sv_ag_start_bolts","0"}; +DLL_GLOBAL cvar_t ag_start_rockets = {"sv_ag_start_rockets","0"}; +DLL_GLOBAL cvar_t ag_start_357ammo = {"sv_ag_start_357ammo","0"}; +DLL_GLOBAL cvar_t ag_start_armour = {"sv_ag_start_armour","0"}; +DLL_GLOBAL cvar_t ag_start_health = {"sv_ag_start_health","100"}; + +DLL_GLOBAL cvar_t ag_dmg_crowbar = {"sv_ag_dmg_crowbar","25"}; +DLL_GLOBAL cvar_t ag_dmg_glock = {"sv_ag_dmg_glock","12"}; +DLL_GLOBAL cvar_t ag_dmg_357 = {"sv_ag_dmg_357","40"}; +DLL_GLOBAL cvar_t ag_dmg_mp5 = {"sv_ag_dmg_mp5","12"}; +DLL_GLOBAL cvar_t ag_dmg_shotgun = {"sv_ag_dmg_shotgun", "20"}; +DLL_GLOBAL cvar_t ag_dmg_crossbow = {"sv_ag_dmg_crossbow", "20"}; +DLL_GLOBAL cvar_t ag_dmg_bolts = {"sv_ag_dmg_bolts","50"}; +DLL_GLOBAL cvar_t ag_dmg_rpg = {"sv_ag_dmg_rpg","120"}; +DLL_GLOBAL cvar_t ag_dmg_gauss = {"sv_ag_dmg_gauss","20"}; +DLL_GLOBAL cvar_t ag_dmg_egon_wide = {"sv_ag_dmg_egon_wide","20"}; +DLL_GLOBAL cvar_t ag_dmg_egon_narrow= {"sv_ag_dmg_egon_narrow","10"}; +DLL_GLOBAL cvar_t ag_dmg_hornet = {"sv_ag_dmg_hornet","10"}; +DLL_GLOBAL cvar_t ag_dmg_hgrenade = {"sv_ag_dmg_hgrenade","100"}; +DLL_GLOBAL cvar_t ag_dmg_satchel = {"sv_ag_dmg_satchel","120"}; +DLL_GLOBAL cvar_t ag_dmg_tripmine = {"sv_ag_dmg_tripmine","150"}; +DLL_GLOBAL cvar_t ag_dmg_m203 = {"sv_ag_dmg_m203","100"}; + + +DLL_GLOBAL cvar_t ag_max_spectators = {"sv_ag_max_spectators","5"}; +DLL_GLOBAL cvar_t ag_spec_enable_disable = {"sv_ag_spec_enable_disable","0"}; +DLL_GLOBAL cvar_t ag_spectalk = {"ag_spectalk","1"}; + +DLL_GLOBAL cvar_t ag_spawn_volume = {"sv_ag_spawn_volume","1"}; +DLL_GLOBAL cvar_t ag_show_gibs = {"sv_ag_show_gibs","1"}; + +DLL_GLOBAL cvar_t ag_gametype = {"sv_ag_gametype",""}; + +DLL_GLOBAL cvar_t ag_ctf_flag_resettime = {"sv_ag_ctf_flag_resettime","30"}; //the time that a dropped flag lays in the world before respawning +DLL_GLOBAL cvar_t ag_ctf_capture_limit = {"sv_ag_ctf_capturelimit","10", FCVAR_SERVER}; //the number of captures before map ends. +DLL_GLOBAL cvar_t ag_ctf_teamcapturepoints = {"sv_ag_ctf_teamcapturepoints","1"}; //the ammount of points his teammates get +DLL_GLOBAL cvar_t ag_ctf_capturepoints = {"sv_ag_ctf_capturepoints","4"}; //the amount of points the capturer gets +DLL_GLOBAL cvar_t ag_ctf_returnpoints = {"sv_ag_ctf_returnpoints","1"}; //the amount of points the returner gets. +DLL_GLOBAL cvar_t ag_ctf_carrierkillpoints = {"sv_ag_ctf_carrierkillpoints","1"}; //the amount of points the killer gets. +DLL_GLOBAL cvar_t ag_ctf_stealpoints = {"sv_ag_ctf_stealpoints","1"}; //the amount of points the stealer gets. +DLL_GLOBAL cvar_t ag_ctf_defendpoints = {"sv_ag_ctf_defendpoints","1"}; //the amount of points the defender gets. +DLL_GLOBAL cvar_t ag_ctf_roundbased = {"sv_ag_ctf_roundbased","0"}; //1 for roundbased CTF game. + +//++ muphicks +DLL_GLOBAL cvar_t ag_dom_mincontroltime = {"sv_ag_dom_mincontroltime","5"}; // number of seconds team must control point to score +DLL_GLOBAL cvar_t ag_dom_controlpoints = {"sv_ag_dom_controlpoints", "1"}; // number of points scored when under teams control +DLL_GLOBAL cvar_t ag_dom_resetscorelimit = {"sv_ag_dom_resetscorelimit", "6"}; // max time under 1 teams control 5*6 = 30 seconds +DLL_GLOBAL cvar_t ag_dom_scorelimit = {"sv_ag_dom_scorelimit", "200"}; // max points a team needs to get to win the game +//-- muphicks + +DLL_GLOBAL cvar_t ag_gauss_fix = {"ag_gauss_fix","0"}; //Default 0 - no fix. +DLL_GLOBAL cvar_t ag_rpg_fix = {"ag_rpg_fix","0"}; //Default 0 - no fix. + +DLL_GLOBAL cvar_t mm_agsay = {"mm_agsay","1", FCVAR_SERVER }; + + +DLL_GLOBAL bool g_bLangame = false; +DLL_GLOBAL bool g_bUseTeamColors = false; +extern AgString g_sGamemode; + +void LoadGreetingMessages(); + +void AgInitGame() +{ + AgInitTimer(); + + CVAR_REGISTER ( &ag_version); + CVAR_REGISTER ( &ag_gamemode); + CVAR_REGISTER ( &ag_allowed_gamemodes); + + CVAR_REGISTER ( &ag_allow_vote); + CVAR_REGISTER ( &ag_pure); + CVAR_REGISTER ( &ag_match_running); + + CVAR_REGISTER ( &ag_oldphysics); + + CVAR_REGISTER ( &ag_player_id); + CVAR_REGISTER ( &ag_lj_timer); + + CVAR_REGISTER ( &ag_auto_admin); + CVAR_REGISTER ( &ag_wallgauss); + CVAR_REGISTER ( &ag_headshot); + CVAR_REGISTER ( &ag_blastradius); + + CVAR_REGISTER ( &ag_ban_crowbar); + CVAR_REGISTER ( &ag_ban_glock); + CVAR_REGISTER ( &ag_ban_357); + CVAR_REGISTER ( &ag_ban_mp5); + CVAR_REGISTER ( &ag_ban_shotgun); + CVAR_REGISTER ( &ag_ban_crossbow); + CVAR_REGISTER ( &ag_ban_rpg); + CVAR_REGISTER ( &ag_ban_gauss); + CVAR_REGISTER ( &ag_ban_egon); + CVAR_REGISTER ( &ag_ban_hornet); + + CVAR_REGISTER ( &ag_ban_hgrenade); + CVAR_REGISTER ( &ag_ban_satchel); + CVAR_REGISTER ( &ag_ban_tripmine); + CVAR_REGISTER ( &ag_ban_snark); + CVAR_REGISTER ( &ag_ban_m203); + CVAR_REGISTER ( &ag_ban_longjump); + CVAR_REGISTER ( &ag_ban_9mmar); + CVAR_REGISTER ( &ag_ban_bockshot); + CVAR_REGISTER ( &ag_ban_uranium); + CVAR_REGISTER ( &ag_ban_bolts); + CVAR_REGISTER ( &ag_ban_rockets); + CVAR_REGISTER ( &ag_ban_357ammo); + + CVAR_REGISTER ( &ag_ban_armour); + CVAR_REGISTER ( &ag_ban_health); + CVAR_REGISTER ( &ag_ban_recharg); + + CVAR_REGISTER ( &ag_start_crowbar); + CVAR_REGISTER ( &ag_start_glock); + CVAR_REGISTER ( &ag_start_357); + CVAR_REGISTER ( &ag_start_mp5); + CVAR_REGISTER ( &ag_start_shotgun); + CVAR_REGISTER ( &ag_start_crossbow); + CVAR_REGISTER ( &ag_start_rpg); + CVAR_REGISTER ( &ag_start_gauss); + CVAR_REGISTER ( &ag_start_egon); + CVAR_REGISTER ( &ag_start_hornet); + + CVAR_REGISTER ( &ag_start_hgrenade); + CVAR_REGISTER ( &ag_start_satchel); + CVAR_REGISTER ( &ag_start_tripmine); + CVAR_REGISTER ( &ag_start_snark); + CVAR_REGISTER ( &ag_start_m203); + CVAR_REGISTER ( &ag_start_longjump); + CVAR_REGISTER ( &ag_start_9mmar); + CVAR_REGISTER ( &ag_start_bockshot); + CVAR_REGISTER ( &ag_start_uranium); + CVAR_REGISTER ( &ag_start_bolts); + CVAR_REGISTER ( &ag_start_rockets); + CVAR_REGISTER ( &ag_start_357ammo); + + CVAR_REGISTER ( &ag_start_armour); + CVAR_REGISTER ( &ag_start_health); + + CVAR_REGISTER ( &ag_dmg_crowbar); + CVAR_REGISTER ( &ag_dmg_glock); + CVAR_REGISTER ( &ag_dmg_357); + CVAR_REGISTER ( &ag_dmg_mp5); + CVAR_REGISTER ( &ag_dmg_shotgun); + CVAR_REGISTER ( &ag_dmg_crossbow); + CVAR_REGISTER ( &ag_dmg_bolts); + CVAR_REGISTER ( &ag_dmg_rpg); + CVAR_REGISTER ( &ag_dmg_gauss); + CVAR_REGISTER ( &ag_dmg_egon_wide); + CVAR_REGISTER ( &ag_dmg_egon_narrow); + CVAR_REGISTER ( &ag_dmg_hornet); + CVAR_REGISTER ( &ag_dmg_hgrenade); + CVAR_REGISTER ( &ag_dmg_satchel); + CVAR_REGISTER ( &ag_dmg_tripmine); + CVAR_REGISTER ( &ag_dmg_m203); + + CVAR_REGISTER ( &ag_allow_timeout); + + CVAR_REGISTER ( &ag_vote_start); + CVAR_REGISTER ( &ag_vote_setting); + CVAR_REGISTER ( &ag_vote_gamemode); + CVAR_REGISTER ( &ag_vote_kick); + CVAR_REGISTER ( &ag_vote_allow); + CVAR_REGISTER ( &ag_vote_admin); + CVAR_REGISTER ( &ag_vote_map); + CVAR_REGISTER ( &ag_vote_failed_time); + + CVAR_REGISTER ( &ag_start_minplayers); + + CVAR_REGISTER ( &ag_vote_mp_timelimit_low); + CVAR_REGISTER ( &ag_vote_mp_timelimit_high); + CVAR_REGISTER ( &ag_vote_mp_fraglimit_low); + CVAR_REGISTER ( &ag_vote_mp_fraglimit_high); + + CVAR_REGISTER ( &ag_floodmsgs); + CVAR_REGISTER ( &ag_floodpersecond); + CVAR_REGISTER ( &ag_floodwaitdelay); + + CVAR_REGISTER ( &ag_max_spectators); + CVAR_REGISTER ( &ag_spec_enable_disable); + CVAR_REGISTER ( &ag_spectalk); + + CVAR_REGISTER ( &ag_spawn_volume); + CVAR_REGISTER ( &ag_show_gibs); + + CVAR_REGISTER ( &ag_gametype); + + CVAR_REGISTER ( &ag_ctf_flag_resettime); + CVAR_REGISTER ( &ag_ctf_capturepoints); + CVAR_REGISTER ( &ag_ctf_teamcapturepoints); + CVAR_REGISTER ( &ag_ctf_capture_limit); + CVAR_REGISTER ( &ag_ctf_returnpoints); + CVAR_REGISTER ( &ag_ctf_carrierkillpoints); + CVAR_REGISTER ( &ag_ctf_stealpoints); + CVAR_REGISTER ( &ag_ctf_defendpoints); + CVAR_REGISTER ( &ag_ctf_roundbased); + + //++ muphicks + CVAR_REGISTER ( &ag_dom_mincontroltime); + CVAR_REGISTER ( &ag_dom_controlpoints); + CVAR_REGISTER ( &ag_dom_resetscorelimit); + CVAR_REGISTER ( &ag_dom_scorelimit ); + //-- muphicks + + CVAR_REGISTER ( &ag_gauss_fix); + CVAR_REGISTER ( &ag_rpg_fix); + + CVAR_REGISTER ( &mm_agsay); + + Command.Init(); + + //Set up initial settings. Add "startup_" before + char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); + + if ( servercfgfile && servercfgfile[0] ) + { + char szCommand[256]; + + ALERT( at_console, "Executing dedicated server startup config file\n" ); + sprintf( szCommand, "exec startup_%s\n", servercfgfile ); + SERVER_COMMAND( szCommand ); + SERVER_EXECUTE(); + } + + g_bLangame = 0 < CVAR_GET_FLOAT("sv_lan"); + + GameMode.Init(); + Wallhack.Init(); + LoadGreetingMessages(); +} + + +//TITLES FOR HALF-LIFE +// Position command $position x y +// x & y are from 0 to 1 to be screen resolution independent +// -1 means center in each dimension +// Effect command $effect +// effect 0 is fade in/fade out +// effect 1 is flickery credits +// effect 2 is write out (training room) +// Text color r g b command $color +// fadein time fadeout time / hold time +// $fadein (message fade in time - per character in effect 2) +// $fadeout (message fade out time) +// $holdtime (stay on the screen for this long) + + +void AgSay(CBasePlayer* pPlayer,const AgString& sText, float* pfFloodProtected, float fHoldTime, float x, float y, int iChannel) +{ + if (g_fGameOver) + return; + + if (pfFloodProtected) + { + if (*pfFloodProtected > gpGlobals->time) + return; + + *pfFloodProtected = gpGlobals->time + fHoldTime; + } + + + hudtextparms_t hText; + memset(&hText, 0, sizeof(hText)); + hText.channel = iChannel; + // These X and Y coordinates are just above + // the health meter. + hText.x = x; + hText.y = y; + + hText.r1 = hText.g1 = hText.b1 = 180; + hText.a1 = 0; + + hText.r2 = hText.g2 = hText.b2 = 0; + hText.a2 = 0; + + hText.holdTime = fHoldTime - 0.30; + + hText.effect = 2; // Fade in/out + hText.fadeinTime = 0.01; + hText.fadeoutTime = fHoldTime/5; + hText.fxTime = 0.25; + + if (pPlayer) + { + UTIL_HudMessage(pPlayer,hText, sText.c_str()); + } + else + { + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + UTIL_HudMessage(pPlayerLoop,hText, sText.c_str()); + } + } +} + + +CBasePlayer* AgPlayerByIndex(int iPlayerIndex ) +{ + CBasePlayer* pPlayer = NULL; + + if ( iPlayerIndex > 0 && iPlayerIndex <= gpGlobals->maxClients ) + { + edict_t *pPlayerEdict = INDEXENT( iPlayerIndex ); + if ( pPlayerEdict && !pPlayerEdict->free && pPlayerEdict->pvPrivateData) + { + CBaseEntity* pEnt = (CBaseEntity *)CBaseEntity::Instance( pPlayerEdict ); + if (pEnt && pEnt->pev && CLASS_PLAYER == pEnt->Classify()) + { + if (pEnt->pev->netname && 0 != STRING(pEnt->pev->netname)[0]) + { + pPlayer = (CBasePlayer*)pEnt; + } + } + } + } + + return pPlayer; +} + + +CBasePlayer* AgPlayerByName(const AgString& sNameOrPlayerNumber) +{ + if (0 == sNameOrPlayerNumber.size()) + return NULL; + + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + if ( 0 == stricmp(pPlayerLoop->GetName(),sNameOrPlayerNumber.c_str()) || + "#" == sNameOrPlayerNumber.substr(0,1) && + GETPLAYERUSERID(pPlayerLoop->edict()) == atoi(sNameOrPlayerNumber.substr(1).c_str()) + ) + return pPlayerLoop; + } + return NULL; +} + +void AgChangelevel(const AgString& sLevelname) +{ + if (32 < sLevelname.size() || 0 == sLevelname.size()) + return; + + char szTemp[64]; + strcpy(szTemp,sLevelname.c_str()); + + //Check if it exists. + if (IS_MAP_VALID(szTemp)) + //Change the level + CHANGE_LEVEL(szTemp,NULL); +} + +void AgConsole(const AgString& sText, CBasePlayer* pPlayer) +{ + if (pPlayer && pPlayer->pev) + { + ClientPrint(pPlayer->pev, HUD_PRINTCONSOLE, UTIL_VarArgs("%s\n", sText.c_str())); + } + else + { + g_engfuncs.pfnServerPrint(UTIL_VarArgs("%s\n", sText.c_str())); + } +} + +void AgResetMap() +{ + CBaseEntity* pEntity = NULL; + + edict_t* pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) + { + pEntity = CBaseEntity::Instance( pEdict ); + if (pEntity && pEntity->pev) + { + const char* pszClass = STRING(pEntity->pev->classname); + + if (pszClass && '\0' != pszClass[0]) + { + if (0 == strncmp( pszClass, "weapon_", 7 ) || + 0 == strncmp( pszClass, "ammo_", 5 ) || + 0 == strncmp( pszClass, "item_", 5 ) ) + { + pEntity->pev->nextthink = gpGlobals->time; + } + } + } + } + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "weaponbox" )) != NULL) + UTIL_Remove(pEntity); + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "monster_satchel" )) != NULL) + UTIL_Remove(pEntity); + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "monster_tripmine" )) != NULL) + UTIL_Remove(pEntity); + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "monster_snark" )) != NULL) + UTIL_Remove(pEntity); + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "beam" )) != NULL) + UTIL_Remove(pEntity); + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "func_healthcharger" )) != NULL) + ((CBaseToggle *)pEntity)->Reset(); + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "func_recharge" )) != NULL) + ((CBaseToggle *)pEntity)->Reset(); + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "rpg_rocket" )) != NULL) + pEntity->pev->dmg = 0; + + pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "grenade" )) != NULL) + pEntity->pev->dmg = 0; +} + +char* AgStringToLower(char* pszString) +{ + if (NULL == pszString) + return pszString; + + char* pszTemp = pszString; + while ('\0' != pszTemp[0]) + { + *pszTemp = tolower(*pszTemp); + pszTemp++; + } + return pszString; +} + +void AgToLower(AgString& strLower) +{ + size_t i = 0; + while (i < strLower.size()) + { + strLower[i] = tolower(strLower[i]); + i++; + } +} + +void AgTrim(AgString& sTrim) +{ + if (0 == sTrim.size()) + return; + + int b = sTrim.find_first_not_of(" \t\r\n"); + int e = sTrim.find_last_not_of(" \t\r\n"); + if(b == -1) // No non-whitespaces + sTrim = ""; + else + sTrim = string(sTrim, b, e - b + 1); +} + +void AgLog(const char* pszLog) +{ + char szFile[MAX_PATH]; + sprintf(szFile, "%s/agslog.txt", AgGetDirectory()); + FILE* pFile = fopen(szFile,"a+"); + if (!pFile) + { + g_engfuncs.pfnServerPrint(UTIL_VarArgs("Couldn't create/save %s.",szFile)); + return; + } + + time_t clock; + time( &clock ); + fprintf(pFile,"%s : %s",pszLog,asctime(localtime(&clock))); + fflush(pFile); + fclose(pFile); + g_engfuncs.pfnServerPrint(pszLog); +} + +#ifndef WIN32 + #include +#endif + +/* +float AgTime() +{ +#ifdef WIN32 + return ((float)clock()) / ((float)CLOCKS_PER_SEC); +#else + static tms t; + return ((float)times(&t)) / 100.0; //Should be CLK_TCK defined in limits.h. +#endif +} +*/ + +void AgDirList(const AgString& sDir, AgStringSet& setFiles) +{ +#ifdef _WIN32 + WIN32_FIND_DATA FindData; + char szSearchDirectory[_MAX_PATH]; + sprintf(szSearchDirectory,"%s/*.*",sDir.c_str()); + HANDLE hFind = FindFirstFile(szSearchDirectory, &FindData); + + if (INVALID_HANDLE_VALUE != hFind) + { + do + { + if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + AgString sFile; + sFile = FindData.cFileName; + setFiles.insert(sFile); + } + } + while (FindNextFile(hFind, &FindData)); + FindClose(hFind); + } +#else + DIR* pDirectory = opendir(sDir.c_str()); + if (pDirectory) + { + struct dirent* pFile = NULL; + + while (NULL != (pFile = readdir(pDirectory))) + { + AgString sFile; + sFile = pFile->d_name; + setFiles.insert(sFile); + } + closedir(pDirectory); + } +#endif +} + +void AgStripColors(char* pszString) +{ + char* pszIt = pszString; + while ('\0' != *pszIt) + { + if ('^' == *pszIt) + { + ++pszIt; + if (*pszIt >= '0' && *pszIt <= '9') + { + --pszIt; + memmove(pszIt,pszIt+2,strlen(pszIt+2)+1); + } + } + else + ++pszIt; + } +} + +void AgGetDetails(char* pszDetails, int iMaxSize, int* piSize) +{ + int iBytes = 0; + char* pszBuffer = pszDetails; + + //Write Match running + iBytes += sprintf(&pszBuffer[iBytes],"match\\%d",ag_match_running.value > 0); + pszBuffer[iBytes] = '\0'; + + *piSize = iBytes; +} + +void AgGetPlayerInfo(char* pszDetails, int iMaxSize, int* piSize) +{ + int iBytes = 0; + char* pszBuffer = pszDetails; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + if (iBytes + 100 > iMaxSize) + break; + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + if (!pPlayerLoop->IsSpectator()) + { + iBytes += sprintf(&pszBuffer[iBytes],"%s ",pPlayerLoop->GetName()); + pszBuffer[iBytes] = '\0'; + + iBytes += sprintf(&pszBuffer[iBytes],"\t%s ",pPlayerLoop->TeamID()); + pszBuffer[iBytes] = '\0'; + + iBytes += sprintf(&pszBuffer[iBytes],"\t%d ",(int)pPlayerLoop->pev->frags); + pszBuffer[iBytes] = '\0'; + + iBytes += sprintf(&pszBuffer[iBytes],"\t%d ",(int)pPlayerLoop->m_iDeaths); + pszBuffer[iBytes] = '\0'; + + iBytes += sprintf(&pszBuffer[iBytes],"\t%s ",pPlayerLoop->GetAuthID()); + pszBuffer[iBytes] = '\0'; + + iBytes++; + } + } + } + + *piSize = iBytes; +} + +#ifndef _WIN32 +#include +#endif + +char* AgOSVersion() +{ +#ifdef _WIN32 + static char verbuf[256]; +#else + static char verbuf[4*SYS_NMLN + 4]; +#endif + +#ifdef _WIN32 + OSVERSIONINFO VersionInfo; + + VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo); + if(GetVersionEx(&VersionInfo)) +{ + if(strlen(VersionInfo.szCSDVersion) > 200) + VersionInfo.szCSDVersion[100] = 0; + sprintf(verbuf, "Windows %d.%d build%d PlatformId %d SP=\"%s\"\n", + VersionInfo.dwMajorVersion, + VersionInfo.dwMinorVersion, + VersionInfo.dwBuildNumber, + VersionInfo.dwPlatformId, + VersionInfo.szCSDVersion); + } + else +{ + strcpy(verbuf, "WINDOWS UNKNOWN\n"); + } +#else + struct utsname ubuf; + + if(uname(&ubuf)) +{ + strcpy(verbuf, "LINUX UNKNOWN\n"); + } + else +{ + sprintf(verbuf,"%s %s %s %s\n", + ubuf.sysname, + ubuf.release, + ubuf.version, + ubuf.machine); + } +#endif + return verbuf; +} + + +#ifdef _WIN32 +static LARGE_INTEGER liTimerFreq; +void AgInitTimer() +{ + QueryPerformanceFrequency(&liTimerFreq); +} +double AgTime() +{ + LARGE_INTEGER liTime; + QueryPerformanceCounter(&liTime); + return ((double)liTime.QuadPart) / ((double)liTimerFreq.QuadPart); +} +#else +#include +#include +#include +static double dClockTicsPerSecond; +void AgInitTimer() +{ + dClockTicsPerSecond = sysconf(_SC_CLK_TCK); +} +double AgTime() +{ + tms t; + clock_t time = times(&t); + if (((clock_t)-1) == time) + { + struct timeval tod; + gettimeofday(&tod,NULL); + return tod.tv_sec + tod.tv_usec * 0.000001; + } + return ((double)time) / dClockTicsPerSecond; +} +#endif + +AgString AgReadFile(const char* pszFile) +{ + AgString sData; + + char szFile[MAX_PATH]; + char szData[4096]; + sprintf(szFile, "%s/%s", AgGetDirectory(),pszFile); + FILE* pFile = fopen(szFile,"r"); + if (!pFile) + return ""; + + int iRead = 0; + while (0 != (iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile))) + { + szData[iRead] = '\0'; + sData += szData; + szData[0] = '\0'; + } + fclose(pFile); + + return sData; +} + +typedef map > AgAuthIDToGreeting; +static AgAuthIDToGreeting s_mapGreeting; +void LoadGreetingMessages() +{ + AgString sGreetingMessages = AgReadFile("greeting.txt"); + + int iPosNewLine = sGreetingMessages.find_first_of("\n"); + while (-1 != iPosNewLine) + { + AgString sAuthID, sGreeting; + int iPosGreeting = sGreetingMessages.find_first_of(" \t"); + sAuthID = sGreetingMessages.substr(0,iPosGreeting); + sGreeting = sGreetingMessages.substr(iPosGreeting+1,iPosNewLine-iPosGreeting-1); + AgTrim(sGreeting); + AgTrim(sAuthID); + sGreeting += "\n"; + s_mapGreeting.insert(AgAuthIDToGreeting::value_type(sAuthID, sGreeting)); + + sGreetingMessages = sGreetingMessages.substr(iPosNewLine+1); + iPosNewLine = sGreetingMessages.find_first_of("\n"); + } +} + +void AgDisplayGreetingMessage(const char* pszAuthID) +{ + AgAuthIDToGreeting::iterator itrGreeting = s_mapGreeting.find(pszAuthID); + if (itrGreeting != s_mapGreeting.end()) + UTIL_ClientPrintAll(HUD_PRINTNOTIFY, (*itrGreeting).second.c_str()); +} + + + + + + + + + +bool AgIsCTFMap(const char* pszMap) +{ + #define LUMP_ENTITIES 0 + #define HEADER_LUMPS 15 + #define MAX_MAP_ENTSTRING (128*1024) + + typedef struct + { + int fileofs, filelen; + } lump_t; + + typedef struct + { + int version; + lump_t lumps[HEADER_LUMPS]; + } dheader_t; + + if (0 == strncmp(pszMap,"agctf_",6)) + return true; + else if (0 == strncmp(pszMap,"hlectf_",6)) + return true; + + char szMapFile[MAX_PATH]; + int iMapLength = 0; + sprintf(szMapFile,"maps/%s.bsp",STRING(gpGlobals->mapname)); + byte* pMapData = LOAD_FILE_FOR_ME(szMapFile,&iMapLength); + if (!pMapData) + return false; + + AgString sMapEntityData; + dheader_t* pHeader = (dheader_t*)pMapData; + if (pHeader->version == 29 || pHeader->version == 30) + { + int iMapDataLength = pHeader->lumps[LUMP_ENTITIES].filelen; + int iMapDataOffset = pHeader->lumps[LUMP_ENTITIES].fileofs; + pMapData[iMapDataLength] = '\0'; + if (NULL != strstr((const char*)&pMapData[iMapDataOffset],"info_hmctfdetect") + || NULL != strstr((const char*)&pMapData[iMapDataOffset],"info_ctfdetect")) + { + FREE_FILE(pMapData); + return true; + } + } + FREE_FILE(pMapData); + return false; +} + + +//++ muphicks +// Check to see if we have a DOM map +bool AgIsDOMMap(const char* pszMap) +{ + #define LUMP_ENTITIES 0 + #define HEADER_LUMPS 15 + #define MAX_MAP_ENTSTRING (128*1024) + + typedef struct + { + int fileofs, filelen; + } lump_t; + + typedef struct + { + int version; + lump_t lumps[HEADER_LUMPS]; + } dheader_t; + + if (0 == strncmp(pszMap,"agdom_",6)) + return true; + + char szMapFile[MAX_PATH]; + int iMapLength = 0; + sprintf(szMapFile,"maps/%s.bsp",STRING(gpGlobals->mapname)); + byte* pMapData = LOAD_FILE_FOR_ME(szMapFile,&iMapLength); + if (!pMapData) + return false; + + AgString sMapEntityData; + dheader_t* pHeader = (dheader_t*)pMapData; + if (pHeader->version == 29 || pHeader->version == 30) + { + int iMapDataLength = pHeader->lumps[LUMP_ENTITIES].filelen; + int iMapDataOffset = pHeader->lumps[LUMP_ENTITIES].fileofs; + pMapData[iMapDataLength] = '\0'; + if (NULL != strstr((const char*)&pMapData[iMapDataOffset],"info_hmdomdetect") + || NULL != strstr((const char*)&pMapData[iMapDataOffset],"info_domdetect")) + { + FREE_FILE(pMapData); + return true; + } + } + FREE_FILE(pMapData); + return false; +} +//--muphicks + +void AgSound(CBasePlayer* pPlayer, const char* pszWave) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + if (!pPlayer->edict() || 0 == strlen(pszWave)) + return; + + CLIENT_COMMAND(pPlayer->edict(), "play %s\n", pszWave); +} + +void AgPlayCountdown(CBasePlayer* pPlayer, int iSeconds) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (0 == iSeconds) + { + AgSound(pPlayer,"barney/ba_bring.wav"); + } + else + { + + if (!g_bLangame) + { + AgSound(pPlayer,"fvox/beep.wav"); + } + else + { + if (1 == iSeconds) + AgSound(pPlayer,"fvox/one.wav"); + else if (2 == iSeconds) + AgSound(pPlayer,"fvox/two.wav"); + else if (3 == iSeconds) + AgSound(pPlayer,"fvox/three.wav"); + else if (4 == iSeconds) + AgSound(pPlayer,"fvox/four.wav"); + else if (5 == iSeconds) + AgSound(pPlayer,"fvox/five.wav"); + else if (6 == iSeconds) + AgSound(pPlayer,"fvox/six.wav"); + else if (7 == iSeconds) + AgSound(pPlayer,"fvox/seven.wav"); + else if (8 == iSeconds) + AgSound(pPlayer,"fvox/eight.wav"); + else if (9 == iSeconds) + AgSound(pPlayer,"fvox/nine.wav"); + else if (10 == iSeconds) + AgSound(pPlayer,"fvox/ten.wav"); + } + } +} + +bool AgIsLocalServer() +{ + return !(IS_DEDICATED_SERVER() && 0 == CVAR_GET_FLOAT("sv_lan")); +} + + +const char* AgGetGame() +{ + static char szGame[MAX_PATH]; + GET_GAME_DIR(szGame); + char* pszGameDir = strrchr(szGame, '/'); + if (pszGameDir) + return pszGameDir + 1; + return szGame; +} + +const char* AgGetDirectory() +{ + static char szGame[MAX_PATH]; + GET_GAME_DIR(szGame); + char* pszGameDir = strrchr(szGame, '/'); + if (pszGameDir) + { + return szGame; + } + else + { + static char szDirectory[MAX_PATH] = ""; + if (strlen(szDirectory)) + return szDirectory; + +#ifndef _WIN32 + getcwd(szDirectory, MAX_PATH); +#else + ::GetCurrentDirectory(MAX_PATH, szDirectory); +#endif + + strcat(szDirectory, "/"); + strcat(szDirectory, szGame); + return szDirectory; + } +} + +const char* AgGetDirectoryValve() +{ + static char szDirectory[MAX_PATH] = ""; + if (szDirectory[0] != '\0') + return szDirectory; + + strcpy(szDirectory, AgGetDirectory()); + int iStart = strlen(szDirectory)-1; + while ('/' != szDirectory[iStart]) + { + szDirectory[iStart] = '\0'; + iStart--; + if (iStart == 0) + { + break; + } + } + szDirectory[iStart] = '\0'; + return szDirectory; +} + +//-- Martin Webrant diff --git a/dlls/aghl/agglobal.h b/dlls/aghl/agglobal.h new file mode 100644 index 00000000..f309850a --- /dev/null +++ b/dlls/aghl/agglobal.h @@ -0,0 +1,223 @@ +//++ BulliT + +#if !defined(_AG_GLOBAL_H_) +#define _AG_GLOBAL_H_ + +#pragma warning(disable:4786) +#pragma warning(disable:4530) + +#include "hltv.h" + + +#define _bool_h 1 +#include +#include +#include +#include +#include +#include +#include + +typedef string AgString; + +typedef string AgString; +typedef list AgStringList; +typedef set > AgStringSet; + +#define ADD_SERVER_COMMAND ( *g_engfuncs.pfnAddServerCommand ) +extern DLL_GLOBAL BOOL g_fGameOver; +extern cvar_t timelimit; + + + +extern cvar_t ag_gamemode; + +extern cvar_t ag_spectalk; +extern cvar_t ag_max_spectators; +extern cvar_t ag_spec_enable_disable; + +extern cvar_t ag_pure; +extern cvar_t ag_allow_vote; +extern cvar_t ag_match_running; +extern cvar_t ag_player_id; +extern cvar_t ag_lj_timer; +extern cvar_t ag_auto_admin; + +extern cvar_t ag_wallgauss; +extern cvar_t ag_headshot; +extern cvar_t ag_blastradius; + +extern cvar_t ag_ban_crowbar; +extern cvar_t ag_ban_glock; +extern cvar_t ag_ban_357; +extern cvar_t ag_ban_mp5; +extern cvar_t ag_ban_shotgun; +extern cvar_t ag_ban_crossbow; +extern cvar_t ag_ban_rpg; +extern cvar_t ag_ban_gauss; +extern cvar_t ag_ban_egon; +extern cvar_t ag_ban_hornet; + +extern cvar_t ag_ban_hgrenade; +extern cvar_t ag_ban_satchel; +extern cvar_t ag_ban_tripmine; +extern cvar_t ag_ban_snark; +extern cvar_t ag_ban_m203; +extern cvar_t ag_ban_longjump; +extern cvar_t ag_ban_9mmar; +extern cvar_t ag_ban_bockshot; +extern cvar_t ag_ban_uranium; +extern cvar_t ag_ban_bolts; +extern cvar_t ag_ban_rockets; +extern cvar_t ag_ban_357ammo; + +extern cvar_t ag_ban_armour; +extern cvar_t ag_ban_health; + +extern cvar_t ag_ban_recharg; + +extern cvar_t ag_start_crowbar; +extern cvar_t ag_start_glock; +extern cvar_t ag_start_357; +extern cvar_t ag_start_mp5; +extern cvar_t ag_start_shotgun; +extern cvar_t ag_start_crossbow; +extern cvar_t ag_start_rpg; +extern cvar_t ag_start_gauss; +extern cvar_t ag_start_egon; +extern cvar_t ag_start_hornet; + +extern cvar_t ag_start_hgrenade; +extern cvar_t ag_start_satchel; +extern cvar_t ag_start_tripmine; +extern cvar_t ag_start_snark; +extern cvar_t ag_start_m203; +extern cvar_t ag_start_longjump; +extern cvar_t ag_start_9mmar; +extern cvar_t ag_start_bockshot; +extern cvar_t ag_start_uranium; +extern cvar_t ag_start_bolts; +extern cvar_t ag_start_rockets; +extern cvar_t ag_start_357ammo; + +extern cvar_t ag_start_armour; +extern cvar_t ag_start_health; + +extern cvar_t ag_dmg_crowbar; +extern cvar_t ag_dmg_glock; +extern cvar_t ag_dmg_357; +extern cvar_t ag_dmg_mp5; +extern cvar_t ag_dmg_shotgun; +extern cvar_t ag_dmg_crossbow; +extern cvar_t ag_dmg_bolts; +extern cvar_t ag_dmg_rpg; +extern cvar_t ag_dmg_gauss; +extern cvar_t ag_dmg_egon_wide; +extern cvar_t ag_dmg_egon_narrow; +extern cvar_t ag_dmg_hornet; +extern cvar_t ag_dmg_hgrenade; +extern cvar_t ag_dmg_satchel; +extern cvar_t ag_dmg_tripmine; +extern cvar_t ag_dmg_m203; + +extern cvar_t ag_spawn_volume; +extern cvar_t ag_show_gibs; + +extern cvar_t ag_allow_timeout; + +extern cvar_t ag_vote_start; +extern cvar_t ag_vote_setting; +extern cvar_t ag_vote_gamemode; +extern cvar_t ag_vote_kick; +extern cvar_t ag_vote_admin; +extern cvar_t ag_vote_allow; +extern cvar_t ag_vote_map; +extern cvar_t ag_vote_failed_time; + +extern cvar_t ag_start_minplayers; + +extern cvar_t ag_vote_mp_timelimit_low; +extern cvar_t ag_vote_mp_timelimit_high; +extern cvar_t ag_vote_mp_fraglimit_low; +extern cvar_t ag_vote_mp_fraglimit_high; + +extern cvar_t ag_floodmsgs; +extern cvar_t ag_floodpersecond; +extern cvar_t ag_floodwaitdelay; + +extern cvar_t ag_ctf_flag_resettime; +extern cvar_t ag_ctf_capturepoints; +extern cvar_t ag_ctf_teamcapturepoints; +extern cvar_t ag_ctf_capture_limit; +extern cvar_t ag_ctf_returnpoints; +extern cvar_t ag_ctf_carrierkillpoints; +extern cvar_t ag_ctf_stealpoints; +extern cvar_t ag_ctf_defendpoints; +extern cvar_t ag_ctf_roundbased; + +//++ muphicks +extern cvar_t ag_dom_mincontroltime; +extern cvar_t ag_dom_controlpoints; +extern cvar_t ag_dom_resetscorelimit; +extern cvar_t ag_dom_scorelimit; +//-- muphicks + +extern cvar_t ag_gauss_fix; +extern cvar_t ag_rpg_fix; + +extern bool g_bLangame; +extern bool g_bUseTeamColors; + +void AgInitGame(); +CBasePlayer* AgPlayerByIndex(int iPlayerIndex); +CBasePlayer* AgPlayerByName(const AgString& sNameOrPlayerNumber); + +void AgChangelevel(const AgString& sLevelname); + +void AgSay(CBasePlayer* pPlayer, const AgString& sText, float* pfFloodProtected = NULL, float fHoldTime = 3.5, float x = -1, float y = -1, int iChannel = 5); +void AgConsole(const AgString& sText, CBasePlayer* pPlayer = NULL); + +void AgResetMap(); + +char* AgStringToLower(char* pszString); +void AgToLower(AgString& strLower); +void AgTrim(AgString& sTrim); + + +void AgLog(const char* pszLog); + +double AgTime(); + +void AgDirList(const AgString& sDir, AgStringSet& setFiles); + +void AgSendDirectorMessage( CBaseEntity *ent1, CBaseEntity *ent2, int priority ); + +void AgStripColors(char* pszString); + + +void AgGetDetails(char* pszDetails, int iMaxSize, int* piSize); +void AgGetPlayerInfo(char* pszPlayerInfo, int iMaxSize, int* piSize); + +char* AgOSVersion(); + +AgString AgReadFile(const char* pszFile); + +void AgDisplayGreetingMessage(const char* pszAuthID); + +bool AgIsCTFMap(const char* pszMap); +//++ muphicks +bool AgIsDOMMap(const char* pszMap); +//-- muphicks + +void AgSound(CBasePlayer* pPlayer, const char* pszWave); +void AgPlayCountdown(CBasePlayer* pPlayer, int iSeconds); + +bool AgIsLocalServer(); + +const char* AgGetGame(); +const char* AgGetDirectory(); +const char* AgGetDirectoryValve(); + +#endif // !defined(_AG_GLOBAL_H_) + +//-- Martin Webrant diff --git a/dlls/aghl/aginfointermission.cpp b/dlls/aghl/aginfointermission.cpp new file mode 100644 index 00000000..50b40b19 --- /dev/null +++ b/dlls/aghl/aginfointermission.cpp @@ -0,0 +1,68 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "gamerules.h" +#include "agglobal.h" +#include "aginfointermission.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgInfoIntermission::AgInfoIntermission() +{ + m_bInitialized = false; +} + +AgInfoIntermission::~AgInfoIntermission() +{ + m_arrInfoIntermission.clear(); +} + +void AgInfoIntermission::Think() +{ + if (!m_bInitialized) + { + //Doing a check for two good tommyD maps that he has failed to put valid intermission points on. + if (0 != strnicmp(STRING(gpGlobals->mapname),"stalkx",6) + &&0 != strnicmp(STRING(gpGlobals->mapname),"boot_campx",10)) + { + //Check for intermission points. + edict_t* pentFind = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission" ); + while ( !FNullEnt( pentFind ) ) + { + m_arrInfoIntermission.push_back(pentFind); + pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "info_intermission" ); + } + } + + //If no intermission points where found, use spawn points. + if (0 == m_arrInfoIntermission.size()) + { + edict_t* pentFind = FIND_ENTITY_BY_CLASSNAME( NULL, "info_player_deathmatch" ); + while ( !FNullEnt( pentFind ) ) + { + m_arrInfoIntermission.push_back(pentFind); + pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "info_player_deathmatch" ); + } + } + + //If no intermission points where found, use spawn points. + if (0 == m_arrInfoIntermission.size()) + { + edict_t* pentFind = FIND_ENTITY_BY_CLASSNAME( NULL, "info_player_start" ); + while ( !FNullEnt( pentFind ) ) + { + m_arrInfoIntermission.push_back(pentFind); + pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "info_player_start" ); + } + } + + m_bInitialized = true; + } +} + +//-- Martin Webrant diff --git a/dlls/aghl/aginfointermission.h b/dlls/aghl/aginfointermission.h new file mode 100644 index 00000000..338d33a9 --- /dev/null +++ b/dlls/aghl/aginfointermission.h @@ -0,0 +1,50 @@ +//++ BulliT + +#if !defined(AFX_AGINFOINTERMISSION_H__92743C98_BDED_4776_ABE6_7FDAA798F87E__INCLUDED_) +#define AFX_AGINFOINTERMISSION_H__92743C98_BDED_4776_ABE6_7FDAA798F87E__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgInfoIntermission +{ + typedef vector AgEdictArray; + AgEdictArray m_arrInfoIntermission; + bool m_bInitialized; + +public: + AgInfoIntermission(); + virtual ~AgInfoIntermission(); + + void Think(); + + int GetCount(); + edict_t* GetSpot(int iSpot); + edict_t* GetRandomSpot(); +}; + +inline int AgInfoIntermission::GetCount() +{ + return m_arrInfoIntermission.size(); +} + +inline edict_t* AgInfoIntermission::GetSpot(int iSpot) +{ + if (iSpot >= 0 && iSpot < (int)m_arrInfoIntermission.size()) + return m_arrInfoIntermission[iSpot]; + return NULL; +} + +inline edict_t* AgInfoIntermission::GetRandomSpot() +{ + if (0 == m_arrInfoIntermission.size()) + return NULL; + + return GetSpot(RANDOM_LONG(0, GetCount()-1)); +} + +#endif // !defined(AFX_AGINFOINTERMISSION_H__92743C98_BDED_4776_ABE6_7FDAA798F87E__INCLUDED_) + + +//-- Martin Webrant diff --git a/dlls/aghl/aglms.cpp b/dlls/aghl/aglms.cpp new file mode 100644 index 00000000..2838eb05 --- /dev/null +++ b/dlls/aghl/aglms.cpp @@ -0,0 +1,297 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" + +#include "aggamerules.h" +#include "agglobal.h" +#include "aglms.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +extern int gmsgCountdown; + +AgLMS::AgLMS() +{ + m_fMatchStart = 0.0; + m_fNextCountdown = 0.0; + m_Status = Waiting; +} + +AgLMS::~AgLMS() +{ + +} + + +void AgLMS::Think() +{ + if (!g_pGameRules) + return; + + if (Playing == m_Status) + { + if (m_fNextCountdown > gpGlobals->time) + return; + m_fNextCountdown = gpGlobals->time + 0.5; + + if (g_pGameRules->IsTeamplay()) + { + //Teams. + AgStringSet setTeams; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + if (!pPlayerLoop->IsAlive()) + { + pPlayerLoop->SetIngame(false); //Cant respawn + if(!pPlayerLoop->IsSpectator()) + { + //Quake1 teleport splash around him. + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_TELEPORT ); + WRITE_COORD(pPlayerLoop->pev->origin.x); + WRITE_COORD(pPlayerLoop->pev->origin.y); + WRITE_COORD(pPlayerLoop->pev->origin.z); + MESSAGE_END(); + + pPlayerLoop->Spectate_Start(false); + pPlayerLoop->Spectate_SetMode(OBS_IN_EYE); + } + } + else + { + setTeams.insert(pPlayerLoop->m_szTeamName); + } + } + } + + if (!(setTeams.size() > 1)) + { + m_sWinner = ""; + AgStringSet::iterator itrTeams = setTeams.begin(); + if (itrTeams != setTeams.end()) + { + m_sWinner = *itrTeams; + } + m_Status = Waiting; + } + } + else + { + int iPlayersAlive = 0; + CBasePlayer* pPlayer = NULL; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + if (!pPlayerLoop->IsAlive()) + { + pPlayerLoop->SetIngame(false); //Cant respawn + if(!pPlayerLoop->IsSpectator()) + { + //Quake1 teleport splash around him. + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_TELEPORT ); + WRITE_COORD(pPlayerLoop->pev->origin.x); + WRITE_COORD(pPlayerLoop->pev->origin.y); + WRITE_COORD(pPlayerLoop->pev->origin.z); + MESSAGE_END(); + + pPlayerLoop->Spectate_Start(false); + pPlayerLoop->Spectate_SetMode(OBS_IN_EYE); + } + } + else + { + iPlayersAlive++; + pPlayer = pPlayerLoop; + } + } + } + + if (!(iPlayersAlive > 1)) + { + m_sWinner = ""; + if (pPlayer) + m_sWinner = pPlayer->GetName(); + m_Status = Waiting; + } + } + } + else + { + //We only update status once every second. + if (m_fNextCountdown > gpGlobals->time) + return; + m_fNextCountdown = gpGlobals->time + 1.0; + + //Handle the status + if (Waiting == m_Status) + { + if (g_pGameRules->IsTeamplay()) + { + //Teams. + AgStringSet setTeams; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayerLoop->m_bReady) + { + setTeams.insert(pPlayerLoop->m_szTeamName); + } + } + + if (setTeams.size() > 1) + { + m_Status = Countdown; + m_fMatchStart = gpGlobals->time + 8.0; + m_fNextCountdown = gpGlobals->time + 3.0; + } + } + else + { + int iPlayers = 0; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayerLoop->m_bReady) + { + iPlayers++; + } + } + if (iPlayers > 1) + { + m_Status = Countdown; + m_fMatchStart = gpGlobals->time + 8.0; + m_fNextCountdown = gpGlobals->time + 3.0; + } + } + + //Write waiting message +#ifdef AG_NO_CLIENT_DLL + if (0 != m_sWinner.size()) + { + AgString s; + s = "Last match won by " + m_sWinner; + AgSay(NULL,s.c_str(),NULL,10,0.4,0.1,2); + m_sWinner = ""; + } + AgSay(NULL,"Waiting for players to get ready!\n",&m_fNextSay,2,0.4,0.5); +#else + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( 50 ); + WRITE_BYTE( 1 ); + WRITE_STRING( m_sWinner.c_str() ); + WRITE_STRING( "" ); + MESSAGE_END(); +#endif + } + else if (Countdown == m_Status) + { + if (m_fMatchStart < gpGlobals->time) + { + //Clear out the map + AgResetMap(); + + int i = 1; + + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayerLoop->m_bReady) + { + pPlayerLoop->SetIngame(true); + g_pGameRules->m_ScoreCache.UpdateScore(pPlayerLoop); + } + } + + m_Status = Spawning; + m_sWinner = ""; + + //Time to start playing. + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayerLoop->m_bReady) + { + if (pPlayerLoop->IsSpectator()) + { + pPlayerLoop->Spectate_Stop(); + } + else + pPlayerLoop->RespawnMatch(); + } + } + + m_Status = Playing; + + //Stop countdown +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( -1 ); + WRITE_BYTE( 0 ); + WRITE_STRING( "" ); + WRITE_STRING( "" ); + MESSAGE_END(); +#endif + } + else + { + //Write countdown message. +#ifdef AG_NO_CLIENT_DLL + char szMatchStart[128]; + sprintf(szMatchStart,"Match will begin in %d seconds!\n",(int)(m_fMatchStart - gpGlobals->time)); + AgSay(NULL,szMatchStart,&m_fNextSay,1,0.3,0.5); +#else + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( (int)(m_fMatchStart - gpGlobals->time) ); + WRITE_BYTE( 1 ); + WRITE_STRING( "" ); + WRITE_STRING( "" ); + MESSAGE_END(); +#endif + } + } + } +} + +void AgLMS::ClientConnected(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + //Set status + pPlayer->SetIngame(false); +} + + +void AgLMS::ClientDisconnected(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + //Set status + pPlayer->SetIngame(false); +} + +//-- Martin Webrant + diff --git a/dlls/aghl/aglms.h b/dlls/aghl/aglms.h new file mode 100644 index 00000000..fc0e6131 --- /dev/null +++ b/dlls/aghl/aglms.h @@ -0,0 +1,39 @@ +// aglms.h: interface for the AgLMS class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(__AG_LMS_H__) +#define __AG_LMS_H__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgLMS +{ + enum LMSStatus { Waiting, Countdown, Spawning, Playing}; + LMSStatus m_Status; + float m_fNextCountdown; + float m_fMatchStart; + float m_fNextSay; + AgString m_sWinner; + +public: + AgLMS(); + virtual ~AgLMS(); + + void Think(); + + void ClientDisconnected(CBasePlayer* pPlayer); + void ClientConnected(CBasePlayer* pPlayer); + + bool CanTakeDamage(); +}; + +inline bool AgLMS::CanTakeDamage() +{ + return Playing == m_Status; +} + + +#endif // !defined(__AG_LMS_H__) diff --git a/dlls/aghl/aglocation.cpp b/dlls/aghl/aglocation.cpp new file mode 100644 index 00000000..55b5c80d --- /dev/null +++ b/dlls/aghl/aglocation.cpp @@ -0,0 +1,27 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "aglocation.h" + +#ifdef AG_NO_CLIENT_DLL + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgLocation::AgLocation() +{ + m_vPosition = Vector(0,0,0); +} + +AgLocation::~AgLocation() +{ + +} + +#endif + +//-- Martin Webrant + + diff --git a/dlls/aghl/aglocation.h b/dlls/aghl/aglocation.h new file mode 100644 index 00000000..46fa0822 --- /dev/null +++ b/dlls/aghl/aglocation.h @@ -0,0 +1,24 @@ +//++ BulliT + +#if !defined(_AG_LOCATION_) +#define _AG_LOCATION_ + +#include "agglobal.h" + +#ifdef AG_NO_CLIENT_DLL + +class AgLocation +{ +public: + AgLocation(); + virtual ~AgLocation(); + + AgString m_sLocation; + Vector m_vPosition; +}; + +#endif + +#endif //_AG_LOCATION_ + +//-- Martin Webrant diff --git a/dlls/aghl/aglocationcache.cpp b/dlls/aghl/aglocationcache.cpp new file mode 100644 index 00000000..2be6cb30 --- /dev/null +++ b/dlls/aghl/aglocationcache.cpp @@ -0,0 +1,131 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "gamerules.h" + +#ifdef AG_NO_CLIENT_DLL + +#include "aglocationcache.h" + +AgLocationCache::AgLocationCache() +{ +}; + +AgLocationCache::~AgLocationCache() +{ + //Delete all. + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + delete *itrLocations; + m_lstLocations.clear(); +} + + +bool AgLocationCache::NearestLocation(const Vector& vPosition, AgLocation*& pLocation, float& fNearestdistance) +{ + fNearestdistance = -1; + pLocation = NULL; + + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + { + float fDistance = (vPosition - (*itrLocations)->m_vPosition).Length(); + + if (fDistance < fNearestdistance || -1 == fNearestdistance) + { + fNearestdistance = fDistance; + pLocation = *itrLocations; + } + } + + return NULL != pLocation; +} + +AgString AgLocationCache::Location(const Vector& vLocation) +{ + AgString sLocation; + if (2 > m_lstLocations.size()) + return sLocation; + + AgLocation* pLocation = NULL; + float fNearestDistance = 0; + + if (NearestLocation(vLocation, pLocation, fNearestDistance)) + { + if (pLocation) + { + sLocation = pLocation->m_sLocation; + } + } + + return sLocation; +} + +void AgLocationCache::Load() +{ + for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations) + delete *itrLocations; + m_lstLocations.clear(); + + char szData[8196]; + + char szFile[MAX_PATH]; + sprintf(szFile,"%s/locs/%s.loc",AgGetDirectory(),STRING(gpGlobals->mapname)); + FILE* pFile = fopen(szFile,"r"); + if (!pFile) + { + // file error + char szMsg[128]; + sprintf(szMsg,"Couldn't open location file %s.",szFile); + AgConsole(szMsg); + return; + } + + enum enumParseState { Location, X, Y, Z }; + enumParseState ParseState = Location; + AgLocation* pLocation = new AgLocation; + int iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile); + if (0 >= iRead) + return; + szData[iRead] = '\0'; + + char* pszParse = NULL; + pszParse = strtok(szData, "#"); + if (pszParse) + { + while (pszParse) + { + if (Location == ParseState) + { + pLocation->m_sLocation = pszParse; + ParseState = X; + } + else if (X == ParseState) + { + pLocation->m_vPosition.x = atof(pszParse); + ParseState = Y; + } + else if (Y == ParseState) + { + pLocation->m_vPosition.y = atof(pszParse); + ParseState = Z; + } + else if (Z == ParseState) + { + pLocation->m_vPosition.z = atof(pszParse); + m_lstLocations.push_back(pLocation); + pLocation = new AgLocation; + ParseState = Location; + } + pszParse = strtok(NULL, "#"); + } + } + delete pLocation; + + fclose(pFile); +} + +#endif + +//-- Martin Webrant diff --git a/dlls/aghl/aglocationcache.h b/dlls/aghl/aglocationcache.h new file mode 100644 index 00000000..0ad71e37 --- /dev/null +++ b/dlls/aghl/aglocationcache.h @@ -0,0 +1,29 @@ +//++ BulliT + +#if !defined(_AG_LOCATION_HUD_) +#define _AG_LOCATION_HUD_ + +#ifdef AG_NO_CLIENT_DLL + +#include "aglocation.h" + +class AgLocationCache +{ + typedef list AgLocationList; + AgLocationList m_lstLocations; + bool NearestLocation(const Vector& vPosition, AgLocation*& pLocation, float& fNearest); + +public: + AgLocationCache(); + virtual ~AgLocationCache(); + + void Load(); + + AgString Location(const Vector& vPosition); +}; + +#endif //AG_NO_CLIENT_DLL + +#endif //_AG_LOCATION_HUD_ + +//-- Martin Webrant diff --git a/dlls/aghl/agmatch.cpp b/dlls/aghl/agmatch.cpp new file mode 100644 index 00000000..c5362f98 --- /dev/null +++ b/dlls/aghl/agmatch.cpp @@ -0,0 +1,265 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "game.h" +#include "agglobal.h" +#include "player.h" +#include "gamerules.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +extern int gmsgCountdown; +extern int gmsgCheatCheck; + +AgMatch::AgMatch() +{ + m_fMatchStart = 0.0; + m_fNextSay = 0.0; + m_fNextHLTV = 0.0; + CVAR_SET_FLOAT("sv_ag_match_running",0); + CVAR_SET_FLOAT("ag_spectalk",1); + CVAR_SET_FLOAT("sv_ag_show_gibs",1); +} + +AgMatch::~AgMatch() +{ + +} + + +void AgMatch::Think() +{ + if (m_fMatchStart > 0 ) + { + if (m_fMatchStart < gpGlobals->time) + { + //Start it + MatchStart(); + } + else + { + //Countdown + if (m_fNextSay < gpGlobals->time) + { +#ifdef AG_NO_CLIENT_DLL + //Play countdown beeb + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && !pPlayerLoop->IsSpectator()) + AgPlayCountdown(pPlayerLoop,(int)(m_fMatchStart - gpGlobals->time)); + } + char szMatchStart[16]; + sprintf(szMatchStart,"%d",(int)(m_fMatchStart - gpGlobals->time)); + AgSay(NULL,szMatchStart,&m_fNextSay,1,0.5,0.45); +#else + //Play countdown beeb + MESSAGE_BEGIN( MSG_BROADCAST, gmsgCountdown); + WRITE_BYTE( (int)(m_fMatchStart - gpGlobals->time) ); + WRITE_BYTE( 1 ); + WRITE_STRING( "" ); + WRITE_STRING( "" ); + MESSAGE_END(); + m_fNextSay = gpGlobals->time + 1.0; +#endif + } + } + } + /* + else if (g_bPaused) + { + AgSay(NULL,"Game is paused!\n",&m_fNextSay,5,0.4); + } + */ + else if (0 == timelimit.value && 0 == fraglimit.value) + { + //Stop the match since it could go on forever. + Abort(); + } + + if (m_fNextHLTV < gpGlobals->time) + { + //Send again in one minute. + m_fNextHLTV = gpGlobals->time + 60.0; + //Spectator scoreboards + g_pGameRules->HLTV_ResendScoreBoard(); + } +} + + +void AgMatch::Start(const AgString& sSpawn) +{ + if (m_fMatchStart > 0 || 0 == timelimit.value && 0 == fraglimit.value) + return; + + //Count players + int iPlayers = 0; + int i = 0; + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && !pPlayerLoop->IsSpectator()) + iPlayers++; + } + + if (iPlayers < (int)ag_start_minplayers.value) + { + UTIL_ClientPrintAll(HUD_PRINTCENTER, UTIL_VarArgs("You need %d players to start a game on this server.",(int)ag_start_minplayers.value)); + return; + } + + //Set match flag. (All entered after matchstart will go into specmode and they cant respawn.) + CVAR_SET_FLOAT("sv_ag_match_running",1); + CVAR_SET_FLOAT("ag_spectalk",0); + CVAR_SET_FLOAT("sv_ag_show_gibs",0); + + //Set match start time. + m_fMatchStart = gpGlobals->time + 10.0; + + m_sSpawnFlag = sSpawn; + + //Pause the game + g_bPaused = true; +} + + +void AgMatch::MatchStart() +{ + m_fMatchStart = -1; + + //Reset score cache. + g_pGameRules->m_ScoreCache.Reset(); + + //Reset available timeouts. + g_pGameRules->m_Timeout.Reset(); + + //Reset map. + AgResetMap(); + + //Reset CTF score + g_pGameRules->m_CTF.ResetScore(); + //++ muphicks + if (DOM == AgGametype()) + g_pGameRules->m_DOM.ResetControlPoints(); + //-- muphicks + + //Loop through all active players, reset Score and respawn. + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + if (pPlayerLoop->IsSpectator()) + { + //Regular spectators aint spawned when match is restarted. + pPlayerLoop->ResetScore(); //Reset the score. + if (strstr(m_sSpawnFlag.c_str(),"nolock")) + pPlayerLoop->SetIngame(true); + else + pPlayerLoop->SetIngame(false); //Player is not allowed to enter the game if he dropped. + + pPlayerLoop->SetDisplayGamemode(2); //Show settings. + g_pGameRules->m_ScoreCache.UpdateScore(pPlayerLoop); + continue; + } + else + { + if (strstr(m_sSpawnFlag.c_str(),"full")) + pPlayerLoop->SetSpawnFull(true); + else + pPlayerLoop->SetSpawnFull(false); + pPlayerLoop->SetIngame(true); //Player is allowed to enter the game if he dropped. + pPlayerLoop->ResetScore(); //Reset the score. + pPlayerLoop->RespawnMatch(); //Now spawn the sucker :-) + pPlayerLoop->SetDisplayGamemode(2); //Show settings. + + g_pGameRules->m_ScoreCache.UpdateScore(pPlayerLoop); + } + } + } + +#ifndef AG_NO_CLIENT_DLL + //Stop countdown + MESSAGE_BEGIN( MSG_ALL, gmsgCountdown); + WRITE_BYTE( -1 ); + WRITE_BYTE( 0 ); + WRITE_STRING( "" ); + WRITE_STRING( "" ); + MESSAGE_END(); +#endif + + //Reset spawn full variable. + m_sSpawnFlag = ""; + + //Remove pause. + g_bPaused = false; + + //Reset timer. + g_pGameRules->m_Timer.Reset(); + + //Score log + g_pGameRules->m_ScoreLog.Start(); + + //Spectator scoreboards + g_pGameRules->HLTV_ResendScoreBoard(); +} + +void AgMatch::Abort() +{ + //Turn off match + CVAR_SET_FLOAT("sv_ag_match_running",0); + CVAR_SET_FLOAT("sv_ag_show_gibs",1); + CVAR_SET_FLOAT("ag_spectalk",1); + + m_fMatchStart = -1; + + //Score log off + g_pGameRules->m_ScoreLog.End(); + + //Remove pause. + g_bPaused = false; + + //Loop through all active players. + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + if (pPlayerLoop->IsSpectator()) + { + //Regular spectators aint spawned when match is restarted. + pPlayerLoop->ResetScore(); //Reset the score. + pPlayerLoop->SetIngame(true); + pPlayerLoop->Spectate_Stop(true); + } + pPlayerLoop->SetDisplayGamemode(2); //Show settings. + } + } +} + +void AgMatch::Allow(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + pPlayer->SetIngame(true); + g_pGameRules->m_ScoreCache.UpdateScore(pPlayer); + if (pPlayer->IsSpectator()) + { + pPlayer->Spectate_Stop(true); + } + + AgString sText; + sText = UTIL_VarArgs("\"%s\" is now allowed to enter the game",pPlayer->GetName()); + AgSay(NULL,sText); + AgConsole(sText); +} + +//-- Martin Webrant diff --git a/dlls/aghl/agmatch.h b/dlls/aghl/agmatch.h new file mode 100644 index 00000000..200e68bb --- /dev/null +++ b/dlls/aghl/agmatch.h @@ -0,0 +1,31 @@ +//++ BulliT + +#if !defined(AFX_AGMATCH_H__AD3BF401_1118_465A_9BF2_699D72665B5C__INCLUDED_) +#define AFX_AGMATCH_H__AD3BF401_1118_465A_9BF2_699D72665B5C__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgMatch +{ + float m_fMatchStart; + float m_fNextSay; + float m_fNextHLTV; + AgString m_sSpawnFlag; + void MatchStart(); + +public: + AgMatch(); + virtual ~AgMatch(); + + void Think(); + + void Start(const AgString& sSpawn); + void Abort(); + void Allow(CBasePlayer* pPlayer); +}; + +#endif // !defined(AFX_AGMATCH_H__AD3BF401_1118_465A_9BF2_699D72665B5C__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agmsgstat.cpp b/dlls/aghl/agmsgstat.cpp new file mode 100644 index 00000000..86559335 --- /dev/null +++ b/dlls/aghl/agmsgstat.cpp @@ -0,0 +1,189 @@ +// agmsgstat.cpp: implementation of the agmsgstat class. +// +////////////////////////////////////////////////////////////////////// +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "gamerules.h" +#include "player.h" +#include "game.h" +#include "agglobal.h" +#include "agmsgstat.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +#ifdef AGMSGSTAT + + +DLL_GLOBAL AgMsgStat g_MsgStat; + +class AgMsgStats +{ +public: + AgMsgStats(const AgString& sName, int iSize) + { + m_iSize = iSize; + m_sName = sName; + m_iBytes = 0; + memset(&m_iarrDest,0,sizeof(m_iarrDest)); + } + AgString m_sName; + int m_iSize; + int m_iarrDest[10]; + int m_iBytes; + /* +#define MSG_BROADCAST 0 // unreliable to all +#define MSG_ONE 1 // reliable to one (msg_entity) +#define MSG_ALL 2 // reliable to all +#define MSG_INIT 3 // write to the init string +#define MSG_PVS 4 // Ents in PVS of org +#define MSG_PAS 5 // Ents in PAS of org +#define MSG_PVS_R 6 // Reliable to PVS +#define MSG_PAS_R 7 // Reliable to PAS +#define MSG_ONE_UNRELIABLE 8 // Send to one client, but don't put in reliable stream, put in unreliable datagram ( could be dropped ) +#define MSG_SPEC 9 // Sends to all spectator proxies + */ +}; +typedef map > AgMsgMap; +static AgMsgMap s_mapMsgs; +static AgMsgStats* s_pCurrentMsg = NULL; +static int s_iStartMsg; + +AgMsgStat::AgMsgStat() +{ + s_iStartMsg = 0; + +} + +AgMsgStat::~AgMsgStat() +{ + +} + +int AgMsgStat::RegUserMsg(const char *pszName, int iSize) +{ + int iMsg = (*g_engfuncs.pfnRegUserMsg)(pszName, iSize); + + if (0 == strcmp("MsgInfo",pszName)) + s_iStartMsg = iMsg; //I just wanna log AG's messages too see if I've done anything stupid + + if (iMsg >= s_iStartMsg) + s_mapMsgs.insert(AgMsgMap::value_type(iMsg, new AgMsgStats(pszName, iSize))); + return iMsg; +} + +void AgMsgStat::MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +{ + //note what type was sent. + AgMsgMap::iterator itrMsgs = s_mapMsgs.find(msg_type); + if (itrMsgs != s_mapMsgs.end() /*&& msg_type != 77 && msg_type != 65*/ && msg_type != 105) + { + (*itrMsgs).second->m_iarrDest[msg_dest]++; + AgConsole((*itrMsgs).second->m_sName); + s_pCurrentMsg = (*itrMsgs).second; + } + (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed); +} + +void AgMsgStat::WriteByte(int iValue) +{ + (*g_engfuncs.pfnWriteByte)(iValue); + if (s_pCurrentMsg) + s_pCurrentMsg->m_iBytes += sizeof(BYTE); +} + +void AgMsgStat::WriteChar(int iValue) +{ + (*g_engfuncs.pfnWriteChar)(iValue); + if (s_pCurrentMsg) + s_pCurrentMsg->m_iBytes += sizeof(char); +} + +void AgMsgStat::WriteShort(int iValue) +{ + (*g_engfuncs.pfnWriteShort)(iValue); + if (s_pCurrentMsg) + s_pCurrentMsg->m_iBytes += sizeof(short); +} + +void AgMsgStat::WriteLong(int iValue) +{ + (*g_engfuncs.pfnWriteLong)(iValue); + if (s_pCurrentMsg) + s_pCurrentMsg->m_iBytes += sizeof(int); +} + +void AgMsgStat::WriteAngle(float flValue) +{ + (*g_engfuncs.pfnWriteAngle)(flValue); + if (s_pCurrentMsg) + s_pCurrentMsg->m_iBytes += sizeof(float); +} + +void AgMsgStat::WriteCoord(float flValue) +{ + (*g_engfuncs.pfnWriteCoord)(flValue); + if (s_pCurrentMsg) + s_pCurrentMsg->m_iBytes += sizeof(float); +} + + +void AgMsgStat::WriteString(const char *sz) +{ + (*g_engfuncs.pfnWriteString)(sz); + if (s_pCurrentMsg) + s_pCurrentMsg->m_iBytes += strlen(sz); +} + +void AgMsgStat::WriteEntity(int iValue) +{ + (*g_engfuncs.pfnWriteEntity)(iValue); + if (s_pCurrentMsg) + s_pCurrentMsg->m_iBytes += sizeof(int); +} + +void AgMsgStat::MessageEnd(void) +{ + (*g_engfuncs.pfnMessageEnd)(); + s_pCurrentMsg = NULL; +} + +void AgMsgStat::DumpStats() +{ + char szFile[MAX_PATH]; + sprintf(szFile,"%s/msgstat.txt",AgGetDirectory()); + FILE* pFile = fopen(szFile,"wb"); + if (!pFile) + return; + + //Dump it. + for (AgMsgMap::iterator itrMsgs = s_mapMsgs.begin() ;itrMsgs != s_mapMsgs.end(); ++itrMsgs) + { + AgMsgStats* pMsg = (*itrMsgs).second; + + int iTotalSent = 0; //Total number of messages sent. + char szDest[128]; + int iPos = 0; + + for (int i = 0; i < (sizeof(pMsg->m_iarrDest) / sizeof(pMsg->m_iarrDest[0])); i++) + { + iTotalSent += pMsg->m_iarrDest[i]; + iPos += sprintf(&szDest[iPos], "%d\t", pMsg->m_iarrDest[i]); + } + szDest[iPos-1] = '\0'; + + //Msg - totalsent - totalsize - sizepermsg - per msgdest + fprintf(pFile, "%s\t%d\t%d\t%d\t%d\t%s\n", pMsg->m_sName.c_str(), (*itrMsgs).first, iTotalSent, pMsg->m_iBytes, pMsg->m_iSize, szDest); + AgConsole(UTIL_VarArgs("%s\t%d\t%d\t%d\t%d\t%s", pMsg->m_sName.c_str(), (*itrMsgs).first, iTotalSent, pMsg->m_iBytes, pMsg->m_iSize, szDest)); + + // delete (*itrMsgs).second; + } + + fflush(pFile); + fclose(pFile); + +// s_mapMsgs.clear(); +} + +#endif \ No newline at end of file diff --git a/dlls/aghl/agmsgstat.h b/dlls/aghl/agmsgstat.h new file mode 100644 index 00000000..b8ed4657 --- /dev/null +++ b/dlls/aghl/agmsgstat.h @@ -0,0 +1,80 @@ +// agmsgstat.h: interface for the agmsgstat class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_AGMSGSTAT_H__B7E22ED8_5544_445A_9AE5_24DCD9413FF2__INCLUDED_) +#define AFX_AGMSGSTAT_H__B7E22ED8_5544_445A_9AE5_24DCD9413FF2__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef AGMSGSTAT +class AgMsgStat +{ +public: + AgMsgStat(); + virtual ~AgMsgStat(); + + int RegUserMsg(const char *pszName, int iSize); + void MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); + void MessageEnd(void); + + void WriteByte(int iValue); + void WriteChar(int iValue); + void WriteShort(int iValue); + void WriteLong(int iValue); + void WriteAngle(float flValue); + void WriteCoord(float flValue); + void WriteString(const char *sz); + void WriteEntity(int iValue); + + void DumpStats(); +}; + +extern AgMsgStat g_MsgStat; + +#undef REG_USER_MSG +#define REG_USER_MSG (g_MsgStat.RegUserMsg) + +inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t *ed = NULL ) +{ + g_MsgStat.MessageBegin(msg_dest, msg_type, pOrigin, ed); +} + +inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ) +{ + g_MsgStat.MessageBegin(msg_dest, msg_type, pOrigin, ENT(ent)); +} + +#undef MESSAGE_END +#define MESSAGE_END (g_MsgStat.MessageEnd) + +#undef WRITE_BYTE +#define WRITE_BYTE (g_MsgStat.WriteByte) + +#undef WRITE_CHAR +#define WRITE_CHAR (g_MsgStat.WriteChar) + +#undef WRITE_SHORT +#define WRITE_SHORT (g_MsgStat.WriteShort) + +#undef WRITE_LONG +#define WRITE_LONG (g_MsgStat.WriteLong) + +#undef WRITE_ANGLE +#define WRITE_ANGLE (g_MsgStat.WriteAngle) + +#undef WRITE_COORD +#define WRITE_COORD (g_MsgStat.WriteCoord) + +#undef WRITE_STRING +#define WRITE_STRING (g_MsgStat.WriteString) + +#undef WRITE_ENTITY +#define WRITE_ENTITY (g_MsgStat.WriteEntity) + + +#endif AGMSGSTAT + +#endif // !defined(AFX_AGMSGSTAT_H__B7E22ED8_5544_445A_9AE5_24DCD9413FF2__INCLUDED_) diff --git a/dlls/aghl/agrunt.cpp b/dlls/aghl/agrunt.cpp new file mode 100644 index 00000000..b1022694 --- /dev/null +++ b/dlls/aghl/agrunt.cpp @@ -0,0 +1,1186 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Agrunt - Dominant, warlike alien grunt monster +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "squadmonster.h" +#include "weapons.h" +#include "soundent.h" +#include "hornet.h" + +//========================================================= +// monster-specific schedule types +//========================================================= +enum +{ + SCHED_AGRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, + SCHED_AGRUNT_THREAT_DISPLAY, +}; + +//========================================================= +// monster-specific tasks +//========================================================= +enum +{ + TASK_AGRUNT_SETUP_HIDE_ATTACK = LAST_COMMON_TASK + 1, + TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, +}; + +int iAgruntMuzzleFlash; + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define AGRUNT_AE_HORNET1 ( 1 ) +#define AGRUNT_AE_HORNET2 ( 2 ) +#define AGRUNT_AE_HORNET3 ( 3 ) +#define AGRUNT_AE_HORNET4 ( 4 ) +#define AGRUNT_AE_HORNET5 ( 5 ) +// some events are set up in the QC file that aren't recognized by the code yet. +#define AGRUNT_AE_PUNCH ( 6 ) +#define AGRUNT_AE_BITE ( 7 ) + +#define AGRUNT_AE_LEFT_FOOT ( 10 ) +#define AGRUNT_AE_RIGHT_FOOT ( 11 ) + +#define AGRUNT_AE_LEFT_PUNCH ( 12 ) +#define AGRUNT_AE_RIGHT_PUNCH ( 13 ) + + + +#define AGRUNT_MELEE_DIST 100 + +class CAGrunt : public CSquadMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed ( void ); + int Classify ( void ); + int ISoundMask ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector( -32, -32, 0 ); + pev->absmax = pev->origin + Vector( 32, 32, 85 ); + } + + Schedule_t* GetSchedule ( void ); + Schedule_t* GetScheduleOfType ( int Type ); + BOOL FCanCheckAttacks ( void ); + BOOL CheckMeleeAttack1 ( float flDot, float flDist ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + void StartTask ( Task_t *pTask ); + void AlertSound( void ); + void DeathSound ( void ); + void PainSound ( void ); + void AttackSound ( void ); + void PrescheduleThink ( void ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + int IRelationship( CBaseEntity *pTarget ); + void StopTalking ( void ); + BOOL ShouldSpeak( void ); + CUSTOM_SCHEDULES; + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + static const char *pAttackHitSounds[]; + static const char *pAttackMissSounds[]; + static const char *pAttackSounds[]; + static const char *pDieSounds[]; + static const char *pPainSounds[]; + static const char *pIdleSounds[]; + static const char *pAlertSounds[]; + + BOOL m_fCanHornetAttack; + float m_flNextHornetAttackCheck; + + float m_flNextPainTime; + + // three hacky fields for speech stuff. These don't really need to be saved. + float m_flNextSpeakTime; + float m_flNextWordTime; + int m_iLastWord; +}; +LINK_ENTITY_TO_CLASS( monster_alien_grunt, CAGrunt ); + +TYPEDESCRIPTION CAGrunt::m_SaveData[] = +{ + DEFINE_FIELD( CAGrunt, m_fCanHornetAttack, FIELD_BOOLEAN ), + DEFINE_FIELD( CAGrunt, m_flNextHornetAttackCheck, FIELD_TIME ), + DEFINE_FIELD( CAGrunt, m_flNextPainTime, FIELD_TIME ), + DEFINE_FIELD( CAGrunt, m_flNextSpeakTime, FIELD_TIME ), + DEFINE_FIELD( CAGrunt, m_flNextWordTime, FIELD_TIME ), + DEFINE_FIELD( CAGrunt, m_iLastWord, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CAGrunt, CSquadMonster ); + +const char *CAGrunt::pAttackHitSounds[] = +{ + "zombie/claw_strike1.wav", + "zombie/claw_strike2.wav", + "zombie/claw_strike3.wav", +}; + +const char *CAGrunt::pAttackMissSounds[] = +{ + "zombie/claw_miss1.wav", + "zombie/claw_miss2.wav", +}; + +const char *CAGrunt::pAttackSounds[] = +{ + "agrunt/ag_attack1.wav", + "agrunt/ag_attack2.wav", + "agrunt/ag_attack3.wav", +}; + +const char *CAGrunt::pDieSounds[] = +{ + "agrunt/ag_die1.wav", + "agrunt/ag_die4.wav", + "agrunt/ag_die5.wav", +}; + +const char *CAGrunt::pPainSounds[] = +{ + "agrunt/ag_pain1.wav", + "agrunt/ag_pain2.wav", + "agrunt/ag_pain3.wav", + "agrunt/ag_pain4.wav", + "agrunt/ag_pain5.wav", +}; + +const char *CAGrunt::pIdleSounds[] = +{ + "agrunt/ag_idle1.wav", + "agrunt/ag_idle2.wav", + "agrunt/ag_idle3.wav", + "agrunt/ag_idle4.wav", +}; + +const char *CAGrunt::pAlertSounds[] = +{ + "agrunt/ag_alert1.wav", + "agrunt/ag_alert3.wav", + "agrunt/ag_alert4.wav", + "agrunt/ag_alert5.wav", +}; + +//========================================================= +// IRelationship - overridden because Human Grunts are +// Alien Grunt's nemesis. +//========================================================= +int CAGrunt::IRelationship ( CBaseEntity *pTarget ) +{ + if ( FClassnameIs( pTarget->pev, "monster_human_grunt" ) ) + { + return R_NM; + } + + return CSquadMonster :: IRelationship( pTarget ); +} + +//========================================================= +// ISoundMask +//========================================================= +int CAGrunt :: ISoundMask ( void ) +{ + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_PLAYER | + bits_SOUND_DANGER; +} + +//========================================================= +// TraceAttack +//========================================================= +void CAGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + if ( ptr->iHitgroup == 10 && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))) + { + // hit armor + if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) + { + UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); + pev->dmgtime = gpGlobals->time; + } + + if ( RANDOM_LONG( 0, 1 ) == 0 ) + { + Vector vecTracerDir = vecDir; + + vecTracerDir.x += RANDOM_FLOAT( -0.3, 0.3 ); + vecTracerDir.y += RANDOM_FLOAT( -0.3, 0.3 ); + vecTracerDir.z += RANDOM_FLOAT( -0.3, 0.3 ); + + vecTracerDir = vecTracerDir * -512; + + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, ptr->vecEndPos ); + WRITE_BYTE( TE_TRACER ); + WRITE_COORD( ptr->vecEndPos.x ); + WRITE_COORD( ptr->vecEndPos.y ); + WRITE_COORD( ptr->vecEndPos.z ); + + WRITE_COORD( vecTracerDir.x ); + WRITE_COORD( vecTracerDir.y ); + WRITE_COORD( vecTracerDir.z ); + MESSAGE_END(); + } + + flDamage -= 20; + if (flDamage <= 0) + flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated + } + else + { + SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. + TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); + } + + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); +} + +//========================================================= +// StopTalking - won't speak again for 10-20 seconds. +//========================================================= +void CAGrunt::StopTalking( void ) +{ + m_flNextWordTime = m_flNextSpeakTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); +} + +//========================================================= +// ShouldSpeak - Should this agrunt be talking? +//========================================================= +BOOL CAGrunt::ShouldSpeak( void ) +{ + if ( m_flNextSpeakTime > gpGlobals->time ) + { + // my time to talk is still in the future. + return FALSE; + } + + if ( pev->spawnflags & SF_MONSTER_GAG ) + { + if ( m_MonsterState != MONSTERSTATE_COMBAT ) + { + // if gagged, don't talk outside of combat. + // if not going to talk because of this, put the talk time + // into the future a bit, so we don't talk immediately after + // going into combat + m_flNextSpeakTime = gpGlobals->time + 3; + return FALSE; + } + } + + return TRUE; +} + +//========================================================= +// PrescheduleThink +//========================================================= +void CAGrunt :: PrescheduleThink ( void ) +{ + if ( ShouldSpeak() ) + { + if ( m_flNextWordTime < gpGlobals->time ) + { + int num = -1; + + do + { + num = RANDOM_LONG(0,ARRAYSIZE(pIdleSounds)-1); + } while( num == m_iLastWord ); + + m_iLastWord = num; + + // play a new sound + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pIdleSounds[ num ], 1.0, ATTN_NORM ); + + // is this word our last? + if ( RANDOM_LONG( 1, 10 ) <= 1 ) + { + // stop talking. + StopTalking(); + } + else + { + m_flNextWordTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 1 ); + } + } + } +} + +//========================================================= +// DieSound +//========================================================= +void CAGrunt :: DeathSound ( void ) +{ + StopTalking(); + + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pDieSounds[RANDOM_LONG(0,ARRAYSIZE(pDieSounds)-1)], 1.0, ATTN_NORM ); +} + +//========================================================= +// AlertSound +//========================================================= +void CAGrunt :: AlertSound ( void ) +{ + StopTalking(); + + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAlertSounds[RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1)], 1.0, ATTN_NORM ); +} + +//========================================================= +// AttackSound +//========================================================= +void CAGrunt :: AttackSound ( void ) +{ + StopTalking(); + + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAttackSounds[RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1)], 1.0, ATTN_NORM ); +} + +//========================================================= +// PainSound +//========================================================= +void CAGrunt :: PainSound ( void ) +{ + if ( m_flNextPainTime > gpGlobals->time ) + { + return; + } + + m_flNextPainTime = gpGlobals->time + 0.6; + + StopTalking(); + + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pPainSounds[RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1)], 1.0, ATTN_NORM ); +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CAGrunt :: Classify ( void ) +{ + return CLASS_ALIEN_MILITARY; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CAGrunt :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_TURN_LEFT: + case ACT_TURN_RIGHT: + ys = 110; + break; + default: ys = 100; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +// +// Returns number of events handled, 0 if none. +//========================================================= +void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case AGRUNT_AE_HORNET1: + case AGRUNT_AE_HORNET2: + case AGRUNT_AE_HORNET3: + case AGRUNT_AE_HORNET4: + case AGRUNT_AE_HORNET5: + { + // m_vecEnemyLKP should be center of enemy body + Vector vecArmPos, vecArmDir; + Vector vecDirToEnemy; + Vector angDir; + + if (HasConditions( bits_COND_SEE_ENEMY)) + { + vecDirToEnemy = ( ( m_vecEnemyLKP ) - pev->origin ); + angDir = UTIL_VecToAngles( vecDirToEnemy ); + vecDirToEnemy = vecDirToEnemy.Normalize(); + } + else + { + angDir = pev->angles; + UTIL_MakeAimVectors( angDir ); + vecDirToEnemy = gpGlobals->v_forward; + } + + pev->effects = EF_MUZZLEFLASH; + + // make angles +-180 + if (angDir.x > 180) + { + angDir.x = angDir.x - 360; + } + + SetBlending( 0, angDir.x ); + GetAttachment( 0, vecArmPos, vecArmDir ); + + vecArmPos = vecArmPos + vecDirToEnemy * 32; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecArmPos ); + WRITE_BYTE( TE_SPRITE ); + WRITE_COORD( vecArmPos.x ); // pos + WRITE_COORD( vecArmPos.y ); + WRITE_COORD( vecArmPos.z ); + WRITE_SHORT( iAgruntMuzzleFlash ); // model + WRITE_BYTE( 6 ); // size * 10 + WRITE_BYTE( 128 ); // brightness + MESSAGE_END(); + + CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, UTIL_VecToAngles( vecDirToEnemy ), edict() ); + UTIL_MakeVectors ( pHornet->pev->angles ); + pHornet->pev->velocity = gpGlobals->v_forward * 300; + + + + switch ( RANDOM_LONG ( 0 , 2 ) ) + { + case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, "agrunt/ag_fire1.wav", 1.0, ATTN_NORM, 0, 100 ); break; + case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, "agrunt/ag_fire2.wav", 1.0, ATTN_NORM, 0, 100 ); break; + case 2: EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, "agrunt/ag_fire3.wav", 1.0, ATTN_NORM, 0, 100 ); break; + } + + CBaseMonster *pHornetMonster = pHornet->MyMonsterPointer(); + + if ( pHornetMonster ) + { + pHornetMonster->m_hEnemy = m_hEnemy; + } + } + break; + + case AGRUNT_AE_LEFT_FOOT: + switch (RANDOM_LONG(0,1)) + { + // left foot + case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder2.wav", 1, ATTN_NORM, 0, 70 ); break; + case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder4.wav", 1, ATTN_NORM, 0, 70 ); break; + } + break; + case AGRUNT_AE_RIGHT_FOOT: + // right foot + switch (RANDOM_LONG(0,1)) + { + case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder1.wav", 1, ATTN_NORM, 0, 70 ); break; + case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder3.wav", 1, ATTN_NORM, 0 ,70); break; + } + break; + + case AGRUNT_AE_LEFT_PUNCH: + { + CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); + + if ( pHurt ) + { + pHurt->pev->punchangle.y = -25; + pHurt->pev->punchangle.x = 8; + + // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. + if ( pHurt->IsPlayer() ) + { + // this is a player. Knock him around. + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 250; + } + + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + + Vector vecArmPos, vecArmAng; + GetAttachment( 0, vecArmPos, vecArmAng ); + SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. + } + else + { + // Play a random attack miss sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + } + } + break; + + case AGRUNT_AE_RIGHT_PUNCH: + { + CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); + + if ( pHurt ) + { + pHurt->pev->punchangle.y = 25; + pHurt->pev->punchangle.x = 8; + + // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. + if ( pHurt->IsPlayer() ) + { + // this is a player. Knock him around. + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * -250; + } + + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + + Vector vecArmPos, vecArmAng; + GetAttachment( 0, vecArmPos, vecArmAng ); + SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. + } + else + { + // Play a random attack miss sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + } + } + break; + + default: + CSquadMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CAGrunt :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/agrunt.mdl"); + UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->effects = 0; + pev->health = gSkillData.agruntHealth; + m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + m_afCapability = 0; + m_afCapability |= bits_CAP_SQUAD; + + m_HackedGunPos = Vector( 24, 64, 48 ); + + m_flNextSpeakTime = m_flNextWordTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); + + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CAGrunt :: Precache() +{ + int i; + + PRECACHE_MODEL("models/agrunt.mdl"); + + for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackHitSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackMissSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) + PRECACHE_SOUND((char *)pIdleSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pDieSounds ); i++ ) + PRECACHE_SOUND((char *)pDieSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) + PRECACHE_SOUND((char *)pPainSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) + PRECACHE_SOUND((char *)pAlertSounds[i]); + + + PRECACHE_SOUND( "hassault/hw_shoot1.wav" ); + + iAgruntMuzzleFlash = PRECACHE_MODEL( "sprites/muz4.spr" ); + + UTIL_PrecacheOther( "hornet" ); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + +//========================================================= +// Fail Schedule +//========================================================= +Task_t tlAGruntFail[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, +}; + +Schedule_t slAGruntFail[] = +{ + { + tlAGruntFail, + ARRAYSIZE ( tlAGruntFail ), + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1, + 0, + "AGrunt Fail" + }, +}; + +//========================================================= +// Combat Fail Schedule +//========================================================= +Task_t tlAGruntCombatFail[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, +}; + +Schedule_t slAGruntCombatFail[] = +{ + { + tlAGruntCombatFail, + ARRAYSIZE ( tlAGruntCombatFail ), + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1, + 0, + "AGrunt Combat Fail" + }, +}; + +//========================================================= +// Standoff schedule. Used in combat when a monster is +// hiding in cover or the enemy has moved out of sight. +// Should we look around in this schedule? +//========================================================= +Task_t tlAGruntStandoff[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, +}; + +Schedule_t slAGruntStandoff[] = +{ + { + tlAGruntStandoff, + ARRAYSIZE ( tlAGruntStandoff ), + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_SEE_ENEMY | + bits_COND_NEW_ENEMY | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "Agrunt Standoff" + } +}; + +//========================================================= +// Suppress +//========================================================= +Task_t tlAGruntSuppressHornet[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slAGruntSuppress[] = +{ + { + tlAGruntSuppressHornet, + ARRAYSIZE ( tlAGruntSuppressHornet ), + 0, + 0, + "AGrunt Suppress Hornet", + }, +}; + +//========================================================= +// primary range attacks +//========================================================= +Task_t tlAGruntRangeAttack1[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slAGruntRangeAttack1[] = +{ + { + tlAGruntRangeAttack1, + ARRAYSIZE ( tlAGruntRangeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_HEAVY_DAMAGE, + + 0, + "AGrunt Range Attack1" + }, +}; + + +Task_t tlAGruntHiddenRangeAttack1[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_STANDOFF }, + { TASK_AGRUNT_SETUP_HIDE_ATTACK, 0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_IDEAL, 0 }, + { TASK_RANGE_ATTACK1_NOTURN, (float)0 }, +}; + +Schedule_t slAGruntHiddenRangeAttack[] = +{ + { + tlAGruntHiddenRangeAttack1, + ARRAYSIZE ( tlAGruntHiddenRangeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "AGrunt Hidden Range Attack1" + }, +}; + +//========================================================= +// Take cover from enemy! Tries lateral cover before node +// cover! +//========================================================= +Task_t tlAGruntTakeCoverFromEnemy[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_WAIT, (float)0.2 }, + { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_FACE_ENEMY, (float)0 }, +}; + +Schedule_t slAGruntTakeCoverFromEnemy[] = +{ + { + tlAGruntTakeCoverFromEnemy, + ARRAYSIZE ( tlAGruntTakeCoverFromEnemy ), + bits_COND_NEW_ENEMY, + 0, + "AGruntTakeCoverFromEnemy" + }, +}; + +//========================================================= +// Victory dance! +//========================================================= +Task_t tlAGruntVictoryDance[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_AGRUNT_THREAT_DISPLAY }, + { TASK_WAIT, (float)0.2 }, + { TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, + { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, + { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, +}; + +Schedule_t slAGruntVictoryDance[] = +{ + { + tlAGruntVictoryDance, + ARRAYSIZE ( tlAGruntVictoryDance ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "AGruntVictoryDance" + }, +}; + +//========================================================= +//========================================================= +Task_t tlAGruntThreatDisplay[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, +}; + +Schedule_t slAGruntThreatDisplay[] = +{ + { + tlAGruntThreatDisplay, + ARRAYSIZE ( tlAGruntThreatDisplay ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + + bits_SOUND_PLAYER | + bits_SOUND_COMBAT | + bits_SOUND_WORLD, + "AGruntThreatDisplay" + }, +}; + +DEFINE_CUSTOM_SCHEDULES( CAGrunt ) +{ + slAGruntFail, + slAGruntCombatFail, + slAGruntStandoff, + slAGruntSuppress, + slAGruntRangeAttack1, + slAGruntHiddenRangeAttack, + slAGruntTakeCoverFromEnemy, + slAGruntVictoryDance, + slAGruntThreatDisplay, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CAGrunt, CSquadMonster ); + +//========================================================= +// FCanCheckAttacks - this is overridden for alien grunts +// because they can use their smart weapons against unseen +// enemies. Base class doesn't attack anyone it can't see. +//========================================================= +BOOL CAGrunt :: FCanCheckAttacks ( void ) +{ + if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +//========================================================= +// CheckMeleeAttack1 - alien grunts zap the crap out of +// any enemy that gets too close. +//========================================================= +BOOL CAGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) +{ + if ( HasConditions ( bits_COND_SEE_ENEMY ) && flDist <= AGRUNT_MELEE_DIST && flDot >= 0.6 && m_hEnemy != NULL ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckRangeAttack1 +// +// !!!LATER - we may want to load balance this. Several +// tracelines are done, so we may not want to do this every +// server frame. Definitely not while firing. +//========================================================= +BOOL CAGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( gpGlobals->time < m_flNextHornetAttackCheck ) + { + return m_fCanHornetAttack; + } + + if ( HasConditions( bits_COND_SEE_ENEMY ) && flDist >= AGRUNT_MELEE_DIST && flDist <= 1024 && flDot >= 0.5 && NoFriendlyFire() ) + { + TraceResult tr; + Vector vecArmPos, vecArmDir; + + // verify that a shot fired from the gun will hit the enemy before the world. + // !!!LATER - we may wish to do something different for projectile weapons as opposed to instant-hit + UTIL_MakeVectors( pev->angles ); + GetAttachment( 0, vecArmPos, vecArmDir ); +// UTIL_TraceLine( vecArmPos, vecArmPos + gpGlobals->v_forward * 256, ignore_monsters, ENT(pev), &tr); + UTIL_TraceLine( vecArmPos, m_hEnemy->BodyTarget(vecArmPos), dont_ignore_monsters, ENT(pev), &tr); + + if ( tr.flFraction == 1.0 || tr.pHit == m_hEnemy->edict() ) + { + m_flNextHornetAttackCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); + m_fCanHornetAttack = TRUE; + return m_fCanHornetAttack; + } + } + + m_flNextHornetAttackCheck = gpGlobals->time + 0.2;// don't check for half second if this check wasn't successful + m_fCanHornetAttack = FALSE; + return m_fCanHornetAttack; +} + +//========================================================= +// StartTask +//========================================================= +void CAGrunt :: StartTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE: + { + UTIL_MakeVectors( pev->angles ); + if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 50, bits_MF_TO_LOCATION, NULL ) ) + { + TaskComplete(); + } + else + { + ALERT ( at_aiconsole, "AGruntGetPathToEnemyCorpse failed!!\n" ); + TaskFail(); + } + } + break; + + case TASK_AGRUNT_SETUP_HIDE_ATTACK: + // alien grunt shoots hornets back out into the open from a concealed location. + // try to find a spot to throw that gives the smart weapon a good chance of finding the enemy. + // ideally, this spot is along a line that is perpendicular to a line drawn from the agrunt to the enemy. + + CBaseMonster *pEnemyMonsterPtr; + + pEnemyMonsterPtr = m_hEnemy->MyMonsterPointer(); + + if ( pEnemyMonsterPtr ) + { + Vector vecCenter; + TraceResult tr; + BOOL fSkip; + + fSkip = FALSE; + vecCenter = Center(); + + UTIL_VecToAngles( m_vecEnemyLKP - pev->origin ); + + UTIL_TraceLine( Center() + gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); + if ( tr.flFraction == 1.0 ) + { + MakeIdealYaw ( pev->origin + gpGlobals->v_right * 128 ); + fSkip = TRUE; + TaskComplete(); + } + + if ( !fSkip ) + { + UTIL_TraceLine( Center() - gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); + if ( tr.flFraction == 1.0 ) + { + MakeIdealYaw ( pev->origin - gpGlobals->v_right * 128 ); + fSkip = TRUE; + TaskComplete(); + } + } + + if ( !fSkip ) + { + UTIL_TraceLine( Center() + gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); + if ( tr.flFraction == 1.0 ) + { + MakeIdealYaw ( pev->origin + gpGlobals->v_right * 256 ); + fSkip = TRUE; + TaskComplete(); + } + } + + if ( !fSkip ) + { + UTIL_TraceLine( Center() - gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); + if ( tr.flFraction == 1.0 ) + { + MakeIdealYaw ( pev->origin - gpGlobals->v_right * 256 ); + fSkip = TRUE; + TaskComplete(); + } + } + + if ( !fSkip ) + { + TaskFail(); + } + } + else + { + ALERT ( at_aiconsole, "AGRunt - no enemy monster ptr!!!\n" ); + TaskFail(); + } + break; + + default: + CSquadMonster :: StartTask ( pTask ); + break; + } +} + +//========================================================= +// GetSchedule - Decides which type of schedule best suits +// the monster's current state and conditions. Then calls +// monster's member function to get a pointer to a schedule +// of the proper type. +//========================================================= +Schedule_t *CAGrunt :: GetSchedule ( void ) +{ + if ( HasConditions(bits_COND_HEAR_SOUND) ) + { + CSound *pSound; + pSound = PBestSound(); + + ASSERT( pSound != NULL ); + if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + { + // dangerous sound nearby! + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); + } + } + + switch ( m_MonsterState ) + { + case MONSTERSTATE_COMBAT: + { +// dead enemy + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // call base class, all code to handle dead enemies is centralized there. + return CBaseMonster :: GetSchedule(); + } + + if ( HasConditions(bits_COND_NEW_ENEMY) ) + { + return GetScheduleOfType( SCHED_WAKE_ANGRY ); + } + + // zap player! + if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) + { + AttackSound();// this is a total hack. Should be parto f the schedule + return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); + } + + if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) + { + return GetScheduleOfType( SCHED_SMALL_FLINCH ); + } + + // can attack + if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot ( bits_SLOTS_AGRUNT_HORNET ) ) + { + return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); + } + + if ( OccupySlot ( bits_SLOT_AGRUNT_CHASE ) ) + { + return GetScheduleOfType ( SCHED_CHASE_ENEMY ); + } + + return GetScheduleOfType ( SCHED_STANDOFF ); + } + } + + return CSquadMonster :: GetSchedule(); +} + +//========================================================= +//========================================================= +Schedule_t* CAGrunt :: GetScheduleOfType ( int Type ) +{ + switch ( Type ) + { + case SCHED_TAKE_COVER_FROM_ENEMY: + return &slAGruntTakeCoverFromEnemy[ 0 ]; + break; + + case SCHED_RANGE_ATTACK1: + if ( HasConditions( bits_COND_SEE_ENEMY ) ) + { + //normal attack + return &slAGruntRangeAttack1[ 0 ]; + } + else + { + // attack an unseen enemy + // return &slAGruntHiddenRangeAttack[ 0 ]; + return &slAGruntRangeAttack1[ 0 ]; + } + break; + + case SCHED_AGRUNT_THREAT_DISPLAY: + return &slAGruntThreatDisplay[ 0 ]; + break; + + case SCHED_AGRUNT_SUPPRESS: + return &slAGruntSuppress[ 0 ]; + break; + + case SCHED_STANDOFF: + return &slAGruntStandoff[ 0 ]; + break; + + case SCHED_VICTORY_DANCE: + return &slAGruntVictoryDance[ 0 ]; + break; + + case SCHED_FAIL: + // no fail schedule specified, so pick a good generic one. + { + if ( m_hEnemy != NULL ) + { + // I have an enemy + // !!!LATER - what if this enemy is really far away and i'm chasing him? + // this schedule will make me stop, face his last known position for 2 + // seconds, and then try to move again + return &slAGruntCombatFail[ 0 ]; + } + + return &slAGruntFail[ 0 ]; + } + break; + + } + + return CSquadMonster :: GetScheduleOfType( Type ); +} + diff --git a/dlls/aghl/agscore.cpp b/dlls/aghl/agscore.cpp new file mode 100644 index 00000000..9fd58a11 --- /dev/null +++ b/dlls/aghl/agscore.cpp @@ -0,0 +1,24 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "agglobal.h" +#include "agscore.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgScore::AgScore() +{ + m_iFrags = 0; + m_iDeaths = 0; + m_bIngame = false; +} + +AgScore::~AgScore() +{ + +} + +//-- Martin Webrant diff --git a/dlls/aghl/agscore.h b/dlls/aghl/agscore.h new file mode 100644 index 00000000..b87776d0 --- /dev/null +++ b/dlls/aghl/agscore.h @@ -0,0 +1,23 @@ +//++ BulliT + +#if !defined(AFX_AGSCORE_H__7014D216_A0B2_432F_9A67_E54F7D3D6B1D__INCLUDED_) +#define AFX_AGSCORE_H__7014D216_A0B2_432F_9A67_E54F7D3D6B1D__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgScore +{ +public: + AgScore(); + virtual ~AgScore(); + + int m_iFrags; + int m_iDeaths; + bool m_bIngame; +}; + +#endif // !defined(AFX_AGSCORE_H__7014D216_A0B2_432F_9A67_E54F7D3D6B1D__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agscorecache.cpp b/dlls/aghl/agscorecache.cpp new file mode 100644 index 00000000..dbca31a4 --- /dev/null +++ b/dlls/aghl/agscorecache.cpp @@ -0,0 +1,135 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "agscore.h" +#include "agscorecache.h" +#include "agglobal.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgScoreCache::AgScoreCache() +{ +} + +AgScoreCache::~AgScoreCache() +{ + Reset(); +} + + +AgScore* AgScoreCache::FindScore(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return NULL; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return NULL; + + if (g_bLangame) + { + AgScoreMap::iterator itrScores = m_mapScores.find(g_pGameRules->GetIPAddress(pPlayer->edict())); + if (itrScores != m_mapScores.end()) + { + return (*itrScores).second; + } + return NULL; + } + + + + //Search for auth id. + + AgScoreMap::iterator itrScores = m_mapScores.find(pPlayer->GetAuthID()); + if (itrScores != m_mapScores.end()) + { + return (*itrScores).second; + } + + return NULL; +} + +void AgScoreCache::RestoreScore(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + AgScore* pScore = FindScore(pPlayer); + + if (pScore) + { + pPlayer->pev->frags = pScore->m_iFrags; + pPlayer->m_iDeaths = pScore->m_iDeaths; + + ClientPrint( pPlayer->pev, HUD_PRINTCENTER, "Your score was autorestored.\n"); + } +} + +void AgScoreCache::RestoreInGame(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + AgScore* pScore = FindScore(pPlayer); + if (pScore) + pPlayer->SetIngame(pScore->m_bIngame); +} + + +void AgScoreCache::UpdateScore(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return; + + if (1 > ag_match_running.value) + return; + + if (pPlayer->IsProxy() || pPlayer->pev->flags & FL_FAKECLIENT) + return; + + AgScore* pScore = FindScore(pPlayer); + + if (!pScore) + { + + pScore = new AgScore; + + if (!g_bLangame) + m_mapScores.insert(AgScoreMap::value_type(pPlayer->GetAuthID(),pScore)); + else + m_mapScores.insert(AgScoreMap::value_type(g_pGameRules->GetIPAddress(pPlayer->edict()),pScore)); + } + + + pScore->m_iFrags = (int)pPlayer->pev->frags; + pScore->m_iDeaths = pPlayer->m_iDeaths; + pScore->m_bIngame = pPlayer->IsIngame(); +} + +void AgScoreCache::Reset() +{ + for (AgScoreMap::iterator itrScores = m_mapScores.begin() ;itrScores != m_mapScores.end(); ++itrScores) + delete (*itrScores).second; + + m_mapScores.clear(); +} + + +//-- Martin Webrant diff --git a/dlls/aghl/agscorecache.h b/dlls/aghl/agscorecache.h new file mode 100644 index 00000000..a3e2c506 --- /dev/null +++ b/dlls/aghl/agscorecache.h @@ -0,0 +1,32 @@ +//++ BulliT + +#if !defined(AFX_AGSCORECACHE_H__92DDA4B4_AB28_483B_8028_FAAB0667ECD4__INCLUDED_) +#define AFX_AGSCORECACHE_H__92DDA4B4_AB28_483B_8028_FAAB0667ECD4__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "agscore.h" + +class CBasePlayer; +class AgScoreCache +{ + typedef map > AgScoreMap; + AgScoreMap m_mapScores; //Holds the map score for each player. + +public: + AgScoreCache(); + virtual ~AgScoreCache(); + + //Score cache. + AgScore* FindScore(CBasePlayer* pPlayer); //Find a score for a player. + void RestoreScore(CBasePlayer* pPlayer); //Restore his score from scorecache. + void UpdateScore(CBasePlayer* pPlayer); //Update the cache with current score. + void RestoreInGame(CBasePlayer* pPlayer); //Restore ingame flag from the scorecache. + void Reset(); //Reset it. +}; + +#endif // !defined(AFX_AGSCORECACHE_H__92DDA4B4_AB28_483B_8028_FAAB0667ECD4__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agscorelog.cpp b/dlls/aghl/agscorelog.cpp new file mode 100644 index 00000000..0b6564f6 --- /dev/null +++ b/dlls/aghl/agscorelog.cpp @@ -0,0 +1,153 @@ +//++ BulliT + + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "game.h" +#include "gamerules.h" + +#include "agglobal.h" +#include "agscorelog.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgScoreLog::AgScoreLog() +{ + m_fNextLogUpdate = 0; +} + +AgScoreLog::~AgScoreLog() +{ +} + +void AgScoreLog::Think() +{ + if (0 < ag_match_running.value && m_fNextLogUpdate < gpGlobals->time && g_pGameRules) + { + if (0 < timelimit.value) + { + long lTime = (long)timelimit.value * 60 - (long)g_pGameRules->m_Timer.GetEffectiveTime(); + ldiv_t d = ldiv(lTime, 60L); + UTIL_LogPrintf("World triggered \"Time left\" (Minutes \"%ld\") (Seconds \"%02ld\")\n", d.quot,d.rem); + } + + Score(); + + m_fNextLogUpdate = gpGlobals->time + 30.0; + } +} + +void AgScoreLog::Start() +{ + if (0 < ag_match_running.value) + { + UTIL_LogPrintf("World triggered \"Match started\"\n"); + } +} + +void AgScoreLog::End() +{ + if (0 < ag_match_running.value) + { + UTIL_LogPrintf("World triggered \"Match over\"\n"); + EndScore(); + m_fNextLogUpdate = 0; + } +} + +void AgScoreLog::GetScores(AgScoreLogMap& mapScores) +{ + if (g_pGameRules->IsTeamplay()) + { + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + if (0 != strlen(pPlayerLoop->TeamID()) && !pPlayerLoop->IsSpectator()) + { + AgScoreLogMap::iterator itrScoreLog = mapScores.find(pPlayerLoop->TeamID()); + if (itrScoreLog != mapScores.end()) + { + (*itrScoreLog).second += (int)pPlayerLoop->pev->frags; + } + else + { + mapScores.insert(AgScoreLogMap::value_type(pPlayerLoop->TeamID(),pPlayerLoop->pev->frags)); + } + } + } + } + } + else + { + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + if (0 != strlen(pPlayerLoop->GetName()) && !pPlayerLoop->IsSpectator()) + { + mapScores.insert(AgScoreLogMap::value_type(pPlayerLoop->GetName(),pPlayerLoop->pev->frags)); + } + } + } + } +} + +void AgScoreLog::Score() +{ + AgScoreLogMap mapScores; + GetScores(mapScores); + + char szScore[1200]; //32 players/teams with 32 chars names + score for each. + szScore[0] = '\0'; + int iSize = 0; + + for (AgScoreLogMap::iterator itrScoreLog = mapScores.begin() ;itrScoreLog != mapScores.end(); ++itrScoreLog) + iSize += sprintf(&szScore[iSize],"%s:%d ",(*itrScoreLog).first.c_str(),(*itrScoreLog).second); + + szScore[iSize] = '\0'; + + UTIL_LogPrintf( "World triggered \"Score Update\" (scores \"%s\")\n", szScore ); + mapScores.clear(); +} + +void AgScoreLog::EndScore() +{ + AgScoreLogMap mapScores; + GetScores(mapScores); + + char szScore[1200]; //32 players/teams with 32 chars names + score for each. + szScore[0] = '\0'; + int iSize = 0; + + for (AgScoreLogMap::iterator itrScoreLog = mapScores.begin() ;itrScoreLog != mapScores.end(); ++itrScoreLog) + iSize += sprintf(&szScore[iSize],"%s:%d ",(*itrScoreLog).first.c_str(),(*itrScoreLog).second); + + szScore[iSize] = '\0'; + + UTIL_LogPrintf( "World triggered \"Score Update\" (scores \"%s\")\n", szScore ); + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + AgString sScore; + sScore = szScore; + sScore += "\n"; + AgConsole(sScore.c_str(),pPlayerLoop); + } + } + + mapScores.clear(); +} + +//-- Martin Webrant + diff --git a/dlls/aghl/agscorelog.h b/dlls/aghl/agscorelog.h new file mode 100644 index 00000000..5830aa41 --- /dev/null +++ b/dlls/aghl/agscorelog.h @@ -0,0 +1,34 @@ +//++ BulliT + + +#if !defined(AFX_AGSCORELOG_H__A764B26F_F098_4237_B5B9_A62BD9FD9BF6__INCLUDED_) +#define AFX_AGSCORELOG_H__A764B26F_F098_4237_B5B9_A62BD9FD9BF6__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +typedef map > AgScoreLogMap; + +class AgScoreLog +{ + float m_fNextLogUpdate; + void EndScore(); + +public: + AgScoreLog(); + virtual ~AgScoreLog(); + + void Think(); + + void Start(); + void End(); + void Score(); + + void GetScores(AgScoreLogMap& mapScores); +}; + +#endif // !defined(AFX_AGSCORELOG_H__A764B26F_F098_4237_B5B9_A62BD9FD9BF6__INCLUDED_) + +//-- Martin Webrant + diff --git a/dlls/aghl/agsettings.cpp b/dlls/aghl/agsettings.cpp new file mode 100644 index 00000000..9c833443 --- /dev/null +++ b/dlls/aghl/agsettings.cpp @@ -0,0 +1,753 @@ +//++ BulliT +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "gamerules.h" +#include "player.h" +#include "game.h" +#include "agglobal.h" +#include "agsettings.h" +#ifdef AGSTATS +#include "agstats.h" +#endif +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DLL_GLOBAL bool g_bMapchange = false; +DLL_GLOBAL AgString g_sNextMap; +DLL_GLOBAL AgString g_sNextRules; + +extern cvar_t timeleft, fragsleft; +extern int gmsgNextmap; + + +AgSettings::AgSettings() +{ + m_bChangeNextLevel = false; + g_bMapchange = false; + + m_bCheckNextMap = true; + m_bCalcNextMap = true; + + m_fNextCheck = gpGlobals->time + 10.0; +} + +AgSettings::~AgSettings() +{ + +} + +bool AgSettings::Think() +{ + if (!g_pGameRules) + return false; + + if (g_bMapchange) + return false; + + if (m_bChangeNextLevel) + { + m_bChangeNextLevel = false; + g_bMapchange = true; + //Change the map. + AgChangelevel(g_sNextMap); + + if (g_sNextRules.size()) + { + SERVER_COMMAND((char*)g_sNextRules.c_str()); + g_sNextRules = ""; + } + return false; + } + + if (g_fGameOver) + return true; + + //No need to do rest of this every frame. + if (m_fNextCheck > gpGlobals->time) + return true; + + if (m_bCalcNextMap) + CalcNextMap(); + + m_fNextCheck = gpGlobals->time + 5.0; //Every 5 seconds. + + //Check if to display next map. + if (m_bCheckNextMap && timelimit.value || m_bCheckNextMap && fraglimit.value) + { + if (timeleft.value && 60 > timeleft.value || fraglimit.value && 2 > fragsleft.value) + { +#ifdef AG_NO_CLIENT_DLL + AgSay(NULL,UTIL_VarArgs("Next map is %s\n",GetNextLevel().c_str()),NULL,30,0.03,0.05,2); +#else + MESSAGE_BEGIN(MSG_BROADCAST,gmsgNextmap); + WRITE_STRING( GetNextLevel().c_str() ); + MESSAGE_END(); +#endif + + m_bCheckNextMap = false; + } + } + + return true; +} + +bool AgSettings::AdminSetting(const AgString& sSetting, const AgString& sValue) +{ + if (0 == strnicmp(sSetting.c_str(),"ag_",3) + ||0 == strnicmp(sSetting.c_str(),"mp_timelimit",12) + ||0 == strnicmp(sSetting.c_str(),"mp_fraglimit",12) + ) + { + CVAR_SET_STRING(sSetting.c_str(),sValue.c_str()); + return true; + } + return false; +} + + +void AgSettings::Changelevel(const AgString& sMap) +{ + if (32 < sMap.size() || 0 == sMap.size()) + return; + + char szTemp[64]; + strcpy(szTemp,sMap.c_str()); + + //Check if it exists. + if (IS_MAP_VALID(szTemp)) + { + g_sNextMap = sMap; + g_sNextRules = ""; + g_pGameRules->GoToIntermission(); + +#ifdef AGSTATS + Stats.OnChangeLevel(); +#endif + } +} + + +void AgSettings::SetNextLevel(const AgString& sMap) +{ + if (32 < sMap.size() || 0 == sMap.size()) + return; + + char szTemp[64]; + strcpy(szTemp,sMap.c_str()); + + //Check if it exists. + if (IS_MAP_VALID(szTemp)) + g_sNextMap = sMap; + + if (g_sNextMap.size()) + { +#ifdef AG_NO_CLIENT_DLL + char szNextMap[128]; + sprintf(szNextMap, "Next map is %s", g_sNextMap.c_str()); + AgSay(NULL,szNextMap,NULL,5,0.5,0.2); +#else + MESSAGE_BEGIN(MSG_BROADCAST,gmsgNextmap); + WRITE_STRING( g_sNextMap.c_str() ); + MESSAGE_END(); +#endif + } +} + +AgString AgSettings::GetNextLevel() +{ + return g_sNextMap; +} + +void AgSettings::ChangeNextLevel() +{ + if (32 < g_sNextMap.size() || 0 == g_sNextMap.size()) + return; + + m_bChangeNextLevel = true; +} + +/* +void AgSettings::CalcNextMap() +{ + //Calc next map, wont work with maps that are in more than one place in mapcycle file. + typedef list AgMapList; + AgMapList lstMaps; + + char *pszMapFile = (char*) CVAR_GET_STRING( "mapcyclefile" ); + ASSERT( pszMapFile != NULL ); + + // Load the file + int nLength = 0; + char* pFileList = (char *)LOAD_FILE_FOR_ME(pszMapFile,&nLength); + + if (pFileList && nLength) + { + // Loop while there are lines + char *pFileCur = pFileList; + while (nLength > 0) + { + // Get the next line + char szLine [256]; + char *pszLine = szLine; + while (nLength > 0 && *pFileCur != '\n') + { + char c = *pFileCur++; + if (c > ' ' && c < 127) *pszLine++ = c; + nLength--; + } + + // Remove the LF + if (nLength > 0) + { + nLength--; + pFileCur++; + } + + // Terminate the line + *pszLine++ = 0; + + // If there is anything in the line, add to map list + if (szLine[0] && IS_MAP_VALID(szLine)) + lstMaps.push_back(szLine); + } + + // Free the file + FREE_FILE(pFileList); + } + + //Find the next map. Ain't there a find function in stl? weird.. + AgMapList::iterator itrMaps = lstMaps.begin(); + for ( ;itrMaps != lstMaps.end() && *itrMaps != g_sNextMap; ++itrMaps) + { + } + + if (itrMaps == lstMaps.end()) + { + if (0 == lstMaps.size()) + { + //No maps in list. Set the current. + g_sNextMap = STRING(gpGlobals->mapname); + } + else + { + //Map aint in list. Do default to first map. + g_sNextMap = *lstMaps.begin(); + } + } + else + { + ++itrMaps; + if (itrMaps == lstMaps.end()) + { + //End of list, use first map in list. + g_sNextMap = *lstMaps.begin(); + } + else + { + //Set next map. + g_sNextMap = *itrMaps; + } + + } + + //Still empty? Should not be so... - this is VERY defenisive programming :) + if (0 == g_sNextMap.size()) + g_sNextMap = STRING(gpGlobals->mapname); + + //No need to calc more. + m_bCalcNextMap = false; + lstMaps.clear(); +} +*/ + + +#define MAX_RULE_BUFFER 1024 + +typedef struct mapcycle_item_s +{ + struct mapcycle_item_s *next; + + char mapname[ 32 ]; + int minplayers, maxplayers; + char rulebuffer[ MAX_RULE_BUFFER ]; +} mapcycle_item_t; + +typedef struct mapcycle_s +{ + struct mapcycle_item_s *items; + struct mapcycle_item_s *next_item; +} mapcycle_t; + +/* +============== +DestroyMapCycle + +Clean up memory used by mapcycle when switching it +============== +*/ +void AgDestroyMapCycle( mapcycle_t *cycle ) +{ + mapcycle_item_t *p, *n, *start; + p = cycle->items; + if ( p ) + { + start = p; + p = p->next; + while ( p != start ) + { + n = p->next; + delete p; + p = n; + } + + delete cycle->items; + } + cycle->items = NULL; + cycle->next_item = NULL; +} + +static char com_token[ 1500 ]; + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *AgCOM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + return NULL; // end of file; + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + while (1) + { + c = *data++; + if (c=='\"' || !c) + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + +/* +============== +COM_TokenWaiting + +Returns 1 if additional data is waiting to be processed on this line +============== +*/ +int AgCOM_TokenWaiting( char *buffer ) +{ + char *p; + + p = buffer; + while ( *p && *p!='\n') + { + if ( !isspace( *p ) || isalnum( *p ) ) + return 1; + + p++; + } + + return 0; +} + + + +/* +============== +ReloadMapCycleFile + + +Parses mapcycle.txt file into mapcycle_t structure +============== +*/ +int AgReloadMapCycleFile( char *filename, mapcycle_t *cycle ) +{ + char szBuffer[ MAX_RULE_BUFFER ]; + char szMap[ 32 ]; + int length; + char *pFileList; + char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( filename, &length ); + int hasbuffer; + mapcycle_item_s *item, *newlist = NULL, *next; + + if ( pFileList && length ) + { + // the first map name in the file becomes the default + while ( 1 ) + { + hasbuffer = 0; + memset( szBuffer, 0, MAX_RULE_BUFFER ); + + pFileList = AgCOM_Parse( pFileList ); + if ( strlen( com_token ) <= 0 ) + break; + + strcpy( szMap, com_token ); + + // Any more tokens on this line? + if ( AgCOM_TokenWaiting( pFileList ) ) + { + pFileList = AgCOM_Parse( pFileList ); + if ( strlen( com_token ) > 0 ) + { + hasbuffer = 1; + strcpy( szBuffer, com_token ); + } + } + + // Check map + if ( IS_MAP_VALID( szMap ) ) + { + // Create entry + char *s; + + item = new mapcycle_item_s; + + strcpy( item->mapname, szMap ); + + item->minplayers = 0; + item->maxplayers = 0; + + memset( item->rulebuffer, 0, MAX_RULE_BUFFER ); + + if ( hasbuffer ) + { + s = g_engfuncs.pfnInfoKeyValue( szBuffer, "minplayers" ); + if ( s && s[0] ) + { + item->minplayers = atoi( s ); + item->minplayers = max( item->minplayers, 0 ); + item->minplayers = min( item->minplayers, gpGlobals->maxClients ); + } + s = g_engfuncs.pfnInfoKeyValue( szBuffer, "maxplayers" ); + if ( s && s[0] ) + { + item->maxplayers = atoi( s ); + item->maxplayers = max( item->maxplayers, 0 ); + item->maxplayers = min( item->maxplayers, gpGlobals->maxClients ); + } + + // Remove keys + // + g_engfuncs.pfnInfo_RemoveKey( szBuffer, "minplayers" ); + g_engfuncs.pfnInfo_RemoveKey( szBuffer, "maxplayers" ); + + strcpy( item->rulebuffer, szBuffer ); + } + + item->next = cycle->items; + cycle->items = item; + } + else + { + ALERT( at_console, "Skipping %s from mapcycle, not a valid map\n", szMap ); + } + + } + + FREE_FILE( aFileList ); + } + + // Fixup circular list pointer + item = cycle->items; + + // Reverse it to get original order + while ( item ) + { + next = item->next; + item->next = newlist; + newlist = item; + item = next; + } + cycle->items = newlist; + item = cycle->items; + + // Didn't parse anything + if ( !item ) + { + return 0; + } + + while ( item->next ) + { + item = item->next; + } + item->next = cycle->items; + + cycle->next_item = item->next; + + return 1; +} + +/* +============== +CountPlayers + +Determine the current # of active players on the server for map cycling logic +============== +*/ +int AgCountPlayers( void ) +{ + int num = 0; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex( i ); + + if ( pEnt ) + { + num = num + 1; + } + } + + return num; +} + +/* +============== +ExtractCommandString + +Parse commands/key value pairs to issue right after map xxx command is issued on server + level transition +============== +*/ +void AgExtractCommandString( char *s, char *szCommand ) +{ + // Now make rules happen + char pkey[512]; + char value[512]; // use two buffers so compares + // work without stomping on each other + char *o; + + if ( *s == '\\' ) + s++; + + while (1) + { + o = pkey; + while ( *s != '\\' ) + { + if ( !*s ) + return; + *o++ = *s++; + } + *o = 0; + s++; + + o = value; + + while (*s != '\\' && *s) + { + if (!*s) + return; + *o++ = *s++; + } + *o = 0; + + strcat( szCommand, pkey ); + if ( strlen( value ) > 0 ) + { + strcat( szCommand, " " ); + strcat( szCommand, value ); + } + strcat( szCommand, "\n" ); + + if (!*s) + return; + s++; + } +} + +/* +============== +ChangeLevel + +Server is changing to a new level, check mapcycle.txt for map name and setup info +============== +*/ +void AgSettings::CalcNextMap() +{ + static char szPreviousMapCycleFile[ 256 ]; + static mapcycle_t mapcycle; + + char szNextMap[32]; + char szFirstMapInList[32]; + char szCommands[ 1500 ]; + char szRules[ 1500 ]; + int minplayers = 0, maxplayers = 0; + strcpy( szFirstMapInList, "boot_camp" ); // the absolute default level is hldm1 + + int curplayers; + BOOL do_cycle = TRUE; + + // find the map to change to + char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); + ASSERT( mapcfile != NULL ); + + szCommands[ 0 ] = '\0'; + szRules[ 0 ] = '\0'; + + curplayers = AgCountPlayers(); + + // Has the map cycle filename changed? + if ( stricmp( mapcfile, szPreviousMapCycleFile ) ) + { + strcpy( szPreviousMapCycleFile, mapcfile ); + + AgDestroyMapCycle( &mapcycle ); + + if ( !AgReloadMapCycleFile( mapcfile, &mapcycle ) || ( !mapcycle.items ) ) + { + ALERT( at_console, "Unable to load map cycle file %s\n", mapcfile ); + do_cycle = FALSE; + } + } + + if ( do_cycle && mapcycle.items ) + { + BOOL keeplooking = FALSE; + BOOL found = FALSE; + mapcycle_item_s *item; + + // Assume current map + strcpy( szNextMap, STRING(gpGlobals->mapname) ); + strcpy( szFirstMapInList, STRING(gpGlobals->mapname) ); + + // Traverse list + for ( item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next ) + { + keeplooking = FALSE; + + ASSERT( item != NULL ); + + if ( item->minplayers != 0 ) + { + if ( curplayers >= item->minplayers ) + { + found = TRUE; + minplayers = item->minplayers; + } + else + { + keeplooking = TRUE; + } + } + + if ( item->maxplayers != 0 ) + { + if ( curplayers <= item->maxplayers ) + { + found = TRUE; + maxplayers = item->maxplayers; + } + else + { + keeplooking = TRUE; + } + } + + if ( keeplooking ) + continue; + + found = TRUE; + break; + } + + if ( !found ) + { + item = mapcycle.next_item; + } + + // Increment next item pointer + mapcycle.next_item = item->next; + + // Perform logic on current item + strcpy( szNextMap, item->mapname ); + + AgExtractCommandString( item->rulebuffer, szCommands ); + strcpy( szRules, item->rulebuffer ); + } + + if ( !IS_MAP_VALID(szNextMap) ) + { + strcpy( szNextMap, szFirstMapInList ); + } + + ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap ); + if ( minplayers || maxplayers ) + { + ALERT( at_console, "PLAYER COUNT: min %i max %i current %i\n", minplayers, maxplayers, curplayers ); + } + if ( strlen( szRules ) > 0 ) + { + ALERT( at_console, "RULES: %s\n", szRules ); + } + + g_sNextMap = szNextMap; + g_sNextRules = szCommands; + //No need to calc more. + m_bCalcNextMap = false; +} + + +//-- Martin Webrant diff --git a/dlls/aghl/agsettings.h b/dlls/aghl/agsettings.h new file mode 100644 index 00000000..11b1d5e7 --- /dev/null +++ b/dlls/aghl/agsettings.h @@ -0,0 +1,36 @@ +//++ BulliT + +#if !defined(AFX_AGSETTINGS_H__84946760_20B0_4629_84A4_115B6422C74D__INCLUDED_) +#define AFX_AGSETTINGS_H__84946760_20B0_4629_84A4_115B6422C74D__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgSettings +{ + bool m_bChangeNextLevel; + bool m_bCheckNextMap; + bool m_bCalcNextMap; + float m_fNextCheck; + void CalcNextMap(); + +public: + AgSettings(); + virtual ~AgSettings(); + + bool Think(); + + void SetNextLevel(const AgString& sMap); + AgString GetNextLevel(); + void ChangeNextLevel(); + + void Changelevel(const AgString& sMap); + bool AdminSetting(const AgString& sSetting, const AgString& sValue); //Not all settings is allowed. + +}; + + +#endif // !defined(AFX_AGSETTINGS_H__84946760_20B0_4629_84A4_115B6422C74D__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agspectator.cpp b/dlls/aghl/agspectator.cpp new file mode 100644 index 00000000..f4e55a2b --- /dev/null +++ b/dlls/aghl/agspectator.cpp @@ -0,0 +1,547 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" + +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" + +extern int gmsgTeamInfo; +extern int gmsgSetFOV; +extern int gmsgSplash; + +extern int gmsgGamemode; +extern int g_teamplay; + +void CBasePlayer::Spectate_Init() +{ + m_fSpectateTime = AgTime(); + m_iSpot = 0; + m_hSpectateTarget = NULL; + m_iSpectateWeapon = 0; + m_iSpectateAmmoClip = 0; +} + + +//Spectate code with parts from Robin Walkers Tutorial. +void CBasePlayer::Spectate_Spectate() +{ + ASSERT(NULL != pev); + if (!pev) + return; + + if (IsSpectator()) + Spectate_Stop(); + else + Spectate_Start(); +} + +bool CBasePlayer::Spectate_HLTV() +{ + g_pGameRules->m_bProxyConnected = true; + //This is the valve proxy. + if (g_pGameRules->IsTeamplay()) + { + strcpy(m_szTeamName,""); + g_engfuncs.pfnSetClientKeyValue( entindex(), g_engfuncs.pfnGetInfoKeyBuffer( edict() ), "model", m_szTeamName ); + g_engfuncs.pfnSetClientKeyValue( entindex(), g_engfuncs.pfnGetInfoKeyBuffer( edict() ), "team", m_szTeamName ); + g_pGameRules->RecountTeams(); + } + g_pGameRules->UpdateGameMode(this); + g_pGameRules->ResendScoreBoard(); + return true; +} + +void CBasePlayer::Spectate_Start(bool bResetScore) +{ + ASSERT(NULL != pev); + if (!pev) + return; + + if (IsSpectator()) //Don't start it if already spectator or if its a player in the arena. + return; + + if (IsProxy()) + return; + + //CTF + if (CTF == AgGametype()) + g_pGameRules->m_CTF.PlayerDropFlag(this); + + //Reset. + Spectate_Init(); + + //Set player as spectator. + pev->iuser1 = OBS_ROAMING; + pev->iuser2 = 0; + m_hSpectateTarget = NULL; + + //Remove spectators from this player + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && this != pPlayerLoop ) + { + if ((CBaseEntity*)pPlayerLoop->m_hSpectateTarget == (CBaseEntity*)this) + { + //Move to next player. + pPlayerLoop->Spectate_Nextplayer(false); + } + } + } + + // clear any clientside entities attached to this player + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_KILLPLAYERATTACHMENTS ); + WRITE_BYTE( (BYTE)entindex() ); + MESSAGE_END(); + + + pev->health = 1; //Remove clientside screentilt. If you find this one helpful - give me credit because I spent 3 hours a friday night figuring it out! + + EnableControl(TRUE); + + if ( m_pTank != NULL ) + { + m_pTank->Use( this, this, USE_OFF, 0 ); + m_pTank = NULL; + } + + // clear out the suit message cache so we don't keep chattering + SetSuitUpdate(NULL, FALSE, 0); + + RemoveAllItemsNoClientMessage(); + + pev->deadflag = DEAD_DEAD; + pev->flags |= FL_SPECTATOR; + pev->flags |= FL_NOTARGET; + + ClearBits( m_afPhysicsFlags, PFLAG_DUCKING ); + ClearBits( pev->flags, FL_DUCKING ); + SetBits(m_afPhysicsFlags, PFLAG_OBSERVER); + UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); + + pev->fixangle = TRUE; + pev->solid = SOLID_NOT; + pev->takedamage = DAMAGE_NO; + pev->movetype = MOVETYPE_NOCLIP; + pev->effects |= EF_NODRAW; + pev->view_ofs = g_vecZero; + m_hSpectateTarget = NULL; + // clear attack/use commands from player + m_afButtonPressed = 0; + pev->button = 0; + m_afButtonReleased = 0; + m_iHideHUD |= HIDEHUD_WEAPONS | HIDEHUD_FLASHLIGHT | HIDEHUD_HEALTH; + + // reset FOV + pev->fov = m_iFOV = m_iClientFOV = 0; + MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); + WRITE_BYTE(0); + MESSAGE_END(); + + + MESSAGE_BEGIN(MSG_ALL,gmsgSpectator); + WRITE_BYTE( ENTINDEX(edict()) ); + WRITE_BYTE(1); + MESSAGE_END(); + + //Change teamname + if (g_pGameRules->IsTeamplay()) + { + MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + WRITE_BYTE( entindex() ); + WRITE_STRING( TeamID() ); + MESSAGE_END(); + } + + //Reset score + if (bResetScore) + ResetScore(); + + pev->nextthink = gpGlobals->time + 0.1; + + //Tell clients + UTIL_ClientPrintAll(HUD_PRINTNOTIFY, UTIL_VarArgs("%s entered spectator mode\n",GetName())); + + //Put up splash screen for 10 secs :) +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_ONE_UNRELIABLE, gmsgSplash, NULL, pev ); + WRITE_BYTE(10); + MESSAGE_END(); +#endif +} + + +void CBasePlayer::Spectate_Stop(bool bIntermediateSpawn) +{ + ASSERT(NULL != pev); + if (!pev) + return; + + if (!IsSpectator()) + return; + + if (IsProxy()) + return; + + if (!g_pGameRules->FPlayerCanRespawn( this)) + return; + + EnableControl(TRUE); + + //Reset flags. + Spectate_Init(); + pev->flags &= ~FL_SPECTATOR; + pev->flags &= ~FL_NOTARGET; + pev->deadflag = DEAD_RESPAWNABLE; + pev->button = 0; + pev->iuser1 = OBS_NONE; + pev->iuser2 = 0; + pev->effects &= ~EF_NODRAW; + pev->movetype = MOVETYPE_WALK; + m_iRespawnFrames = 0; + m_bDoneFirstSpawn = !bIntermediateSpawn; + m_iHideHUD &= ~HIDEHUD_WEAPONS; + m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; + m_iHideHUD &= ~HIDEHUD_HEALTH; + + //Reset fov + pev->fov = m_iFOV = m_iClientFOV = 0; + MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); + WRITE_BYTE(0); + MESSAGE_END(); + + //Remove spec + MESSAGE_BEGIN(MSG_ALL,gmsgSpectator); + WRITE_BYTE(ENTINDEX(edict())); + WRITE_BYTE(0); + MESSAGE_END(); + + //Change teamname + + if (g_pGameRules->IsTeamplay()) + { + MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + WRITE_BYTE( entindex() ); + WRITE_STRING( TeamID() ); + MESSAGE_END(); + } + + //Force data to be resent. + m_fKnownItem = FALSE; // Force weaponinit messages. + + //Tell client(s) + UTIL_ClientPrintAll(HUD_PRINTNOTIFY, UTIL_VarArgs("%s left spectator mode\n",GetName())); + + Spawn(); + +#ifndef AG_NO_CLIENT_DLL + //Remove splash screen + MESSAGE_BEGIN( MSG_ONE, gmsgSplash, NULL, pev ); + WRITE_BYTE(0); + MESSAGE_END(); +#endif +} + +// Find the next client in the game for this player to spectate +void CBasePlayer::Spectate_Nextplayer( bool bReverse ) +{ + ASSERT(NULL != pev); + if (!pev) + return; + + if (IsProxy()) + return; + + // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching + // only a subset of the players. e.g. Make it check the target's team. + + int iStart; + if ( m_hSpectateTarget ) + iStart = ENTINDEX( m_hSpectateTarget->edict() ); + else + iStart = ENTINDEX( edict() ); + + int iCurrent = iStart; + m_hSpectateTarget = NULL; + int iDir = bReverse ? -1 : 1; + + do + { + iCurrent += iDir; + + // Loop through the clients + if (iCurrent > gpGlobals->maxClients) + iCurrent = 1; + if (iCurrent < 1) + iCurrent = gpGlobals->maxClients; + + CBaseEntity *pEnt = AgPlayerByIndex( iCurrent ); + if ( !pEnt ) + continue; + if ( pEnt == this ) + continue; + + // Don't spec observers or invisible players + if ( ((CBasePlayer*)pEnt)->IsSpectator() || (pEnt->pev->effects == EF_NODRAW) ) + continue; + + if (0 < ag_spec_enable_disable.value && ((CBasePlayer*)pEnt)->DisableSpecs()) + continue; + + m_hSpectateTarget = pEnt; + break; + } + while ( iCurrent != iStart ); + + // Did we find a target? + if (m_hSpectateTarget != NULL && m_hSpectateTarget->pev != NULL) + { + // Store the target in pev so the physics DLL can get to it + pev->iuser2 = ENTINDEX( m_hSpectateTarget->edict() ); + // Move to the target + UTIL_SetOrigin( pev, m_hSpectateTarget->pev->origin ); + + //ClientPrint(m_hSpectateTarget->pev, HUD_PRINTNOTIFY, UTIL_VarArgs("You are being watched by %s\n",STRING(pev->netname))); + } + else + { + //Go roaming. + Spectate_SetMode(OBS_ROAMING); + } +} + + +// Handle buttons in spectate mode +void CBasePlayer::Spectate_HandleButtons() +{ + ASSERT(NULL != pev); + if (!pev) + return; + + if (IsProxy()) + return; + + // Slow down mouse clicks + if ( m_fSpectateTime > AgTime() ) + return; + + pev->impulse = 0; + + // Jump changes from modes: Chase to Roaming + if ( m_afButtonPressed & IN_JUMP ) + { + //Reset fov + pev->fov = m_iFOV = m_iClientFOV = 0; + MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); + WRITE_BYTE(0); + MESSAGE_END(); + + if ( pev->iuser1 == OBS_ROAMING ) + Spectate_SetMode( OBS_IN_EYE ); + else if ( pev->iuser1 == OBS_IN_EYE ) + Spectate_SetMode( OBS_CHASE_LOCKED ); + else if ( pev->iuser1 == OBS_CHASE_LOCKED ) + Spectate_SetMode( OBS_CHASE_FREE ); + else if ( pev->iuser1 == OBS_CHASE_FREE ) + Spectate_SetMode( OBS_MAP_CHASE ); + else if ( pev->iuser1 == OBS_MAP_CHASE) + Spectate_SetMode( OBS_MAP_FREE ); + else if ( pev->iuser1 == OBS_MAP_FREE ) + Spectate_SetMode( OBS_ROAMING ); + else + Spectate_SetMode( OBS_ROAMING ); + } + + // Attack moves to the next player + if ( m_afButtonPressed & IN_ATTACK) + { + //Reset fov + pev->fov = m_iFOV = m_iClientFOV = 0; + MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); + WRITE_BYTE(0); + MESSAGE_END(); + + if (pev->iuser2 != 0) + Spectate_Nextplayer(false); + else + Spectate_Nextspot(false); + + m_fSpectateTime = AgTime() + 0.2; + } + + // Attack2 moves to the prev player + if ( m_afButtonPressed & IN_ATTACK2) + { + //Reset fov + pev->fov = m_iFOV = m_iClientFOV = 0; + MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); + WRITE_BYTE(0); + MESSAGE_END(); + + if (pev->iuser2 != 0) + Spectate_Nextplayer(true); + else + Spectate_Nextspot(true); + + m_fSpectateTime = AgTime() + 0.2; + } +} + +void CBasePlayer::Spectate_UpdatePosition() +{ + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && this != pPlayerLoop && pPlayerLoop->IsSpectator()) + { + if ((CBaseEntity*)pPlayerLoop->m_hSpectateTarget == (CBaseEntity*)this) + { + if (pPlayerLoop->m_hSpectateTarget->pev) + { + //Update the spectators position + //pPlayerLoop->m_hSpectateTarget = (CBaseEntity*)this; + UTIL_SetOrigin( pPlayerLoop->pev, pev->origin ); + } + } + } + } +} + +// Attempt to change the spectate mode +void CBasePlayer::Spectate_SetMode( int iMode ) +{ + ASSERT(NULL != pev); + if (!pev) + return; + + if (IsProxy() || !IsSpectator()) + return; + + // Just abort if we're changing to the mode we're already in + if ( iMode == pev->iuser1 ) + return; + + // Changing to Roaming or Map Free? + if ( iMode == OBS_ROAMING || iMode == OBS_MAP_FREE) + { + // MOD AUTHORS: If you don't want to allow roaming observers at all in your mod, just abort here. + pev->iuser1 = iMode; + pev->iuser2 = 0; + m_hSpectateTarget = NULL; + + pev->weapons &= ~WEAPON_ALLWEAPONS; + m_iHideHUD |= HIDEHUD_WEAPONS | HIDEHUD_FLASHLIGHT | HIDEHUD_HEALTH; + return; + } + + // Changing to Chase Lock, Chase Freelook, Map Chase? + if (iMode == OBS_CHASE_FREE || iMode == OBS_MAP_CHASE || iMode == OBS_CHASE_LOCKED) + { + // If changing from Roaming, or starting observing, make sure there is a target + if ( m_hSpectateTarget == NULL ) + Spectate_Nextplayer( false ); + + if (m_hSpectateTarget) + { + pev->iuser1 = iMode; + pev->iuser2 = ENTINDEX( m_hSpectateTarget->edict() ); + pev->maxspeed = 0; + + pev->weapons |= (1<iuser1 = iMode; + pev->iuser2 = ENTINDEX( m_hSpectateTarget->edict() ); + pev->maxspeed = 0; + + pev->weapons |= (1< m_iSpot) + m_iSpot = g_pGameRules->m_InfoInterMission.GetCount() - 1; + else if (m_iSpot >= g_pGameRules->m_InfoInterMission.GetCount()) + m_iSpot = 0; + + //Move the dude + edict_t* pSpot = g_pGameRules->m_InfoInterMission.GetSpot(m_iSpot); + if (pSpot) + MoveToInfoIntermission(pSpot); +} + +bool CBasePlayer::Spectate_Follow(EHANDLE& pPlayer,int iMode) +{ + if (IsProxy()) + return true; + + m_hSpectateTarget = pPlayer; + Spectate_SetMode(iMode); + return true; +} + +//-- Martin Webrant diff --git a/dlls/aghl/agstats.cpp b/dlls/aghl/agstats.cpp new file mode 100644 index 00000000..5a7877c0 --- /dev/null +++ b/dlls/aghl/agstats.cpp @@ -0,0 +1,216 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "agglobal.h" +#include "agstats.h" +#include "weapons.h" +#include "monsters.h" + +DLL_GLOBAL AgStats Stats; + +AgStats::AgStats() +{ +} + +AgStats::~AgStats() +{ + Reset(); +} + +void AgStats::Reset() +{ + for (AgPlayerStatsMap::iterator itrPlayerStats = m_mapPlayerStats.begin() ;itrPlayerStats != m_mapPlayerStats.end(); ++itrPlayerStats) + delete (*itrPlayerStats).second; + + m_mapPlayerStats.clear(); +} + +bool AgStats::HandleCommand(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return false; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return false; + ASSERT(NULL != g_pGameRules); + + if (!g_pGameRules || 0 == CMD_ARGC()) + return false; + + if (FStrEq(CMD_ARGV(0), "agstats")) + { + CBasePlayer* pStatsPlayer = pPlayer; + if (CMD_ARGC() == 2) + pStatsPlayer = AgPlayerByName(CMD_ARGV(1)); + + if (pStatsPlayer) + PrintStats(pPlayer,pStatsPlayer); + return true; + } + + return false; +} + +void AgStats::PrintStats(CBasePlayer* pPlayer, CBasePlayer* pStatsPlayer) +{ + AgPlayerStats* pStats = GetStats(pStatsPlayer); + + AgString sStats; + char szTempBuff[1024]; + static char s_szPlayerStats[] = "Kills %d, Deaths %d, Team Kills %d, Damage ratio %d"; + sprintf(szTempBuff,s_szPlayerStats,pStats->m_iKills,pStats->m_iDeaths,pStats->m_iTeamKills,(int)(pStats->m_iDamageTaken ? ((float)pStats->m_iDamageGiven / (float)pStats->m_iDamageTaken * 100) : 0)); + AgConsole(szTempBuff,pPlayer); + + for (AgPlayerStats::AgWeaponStatsMap::iterator itrWeaponStats = pStats->m_mapWeaponStats.begin() ;itrWeaponStats != pStats->m_mapWeaponStats.end(); ++itrWeaponStats) + { + AgPlayerStats::AgWeaponStats* pWeaponStats = (*itrWeaponStats).second; + static char s_szWeaponStats[] = "%s, Shots %d, Hits %d, Accuracy %d"; + int iHits = pWeaponStats->m_iHits; + if ((*itrWeaponStats).first == "weapon_shotgun") + iHits /= 4; + sprintf(szTempBuff,s_szWeaponStats,(*itrWeaponStats).first.c_str(), pWeaponStats->m_iShots, iHits, (int)(pWeaponStats->m_iShots ? ((float)iHits / (float)pWeaponStats->m_iShots * 100) : 0)); + AgConsole(szTempBuff,pPlayer); + } +} + +void AgStats::OnChangeLevel() +{ + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && !pPlayerLoop->IsProxy()) + PrintStats(pPlayerLoop,pPlayerLoop); + } +} + +AgStats::AgPlayerStats* AgStats::GetStats(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return NULL; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return NULL; + + if (g_bLangame) + { + for (AgPlayerStatsMap::iterator itrPlayerStats = m_mapPlayerStats.begin() ;itrPlayerStats != m_mapPlayerStats.end(); ++itrPlayerStats) + { + if (pPlayer->GetName() == (*itrPlayerStats).second->m_sName) + return (*itrPlayerStats).second; + } + } + else + { + //Search for auth id. + AgPlayerStatsMap::iterator itrPlayerStats = m_mapPlayerStats.find(pPlayer->GetAuthID()); + if (itrPlayerStats != m_mapPlayerStats.end()) + { + (*itrPlayerStats).second->m_sName = pPlayer->GetName(); //Update name... + return (*itrPlayerStats).second; + } + } + + + AgPlayerStats* pPlayerStats = new AgPlayerStats(); + pPlayerStats->m_sName = pPlayer->GetName(); + if (!g_bLangame) + m_mapPlayerStats.insert(AgPlayerStatsMap::value_type(pPlayer->GetAuthID(),pPlayerStats)); + else + m_mapPlayerStats.insert(AgPlayerStatsMap::value_type(pPlayer->GetName(),pPlayerStats)); + + return pPlayerStats; +} + +AgStats::AgPlayerStats::AgWeaponStats* AgStats::AgPlayerStats::GetWeaponStats(const char* pszItem) +{ + AgWeaponStatsMap::iterator itrWeaponStats = m_mapWeaponStats.find(pszItem); + if (itrWeaponStats != m_mapWeaponStats.end()) + return (*itrWeaponStats).second; + + AgWeaponStats* pWeaponStats = new AgWeaponStats(); + m_mapWeaponStats.insert(AgWeaponStatsMap::value_type(pszItem,pWeaponStats)); + return pWeaponStats; +} + +void AgStats::FireShot(CBasePlayer* pPlayer, const char* pszItem) +{ + GetStats(pPlayer)->GetWeaponStats(pszItem)->m_iShots++; +} + +void AgStats::FireHit(CBasePlayer* pPlayer, int iDamage, entvars_t* pevAttacker) +{ + CBasePlayer* pInflictor = NULL; + AgString strItem = STRING(pevAttacker->classname); + + if (strItem == "player") + { + strItem = ""; + pInflictor = (CBasePlayer*)CBaseEntity::Instance(pevAttacker); + if (pInflictor && pInflictor->m_pActiveItem) + strItem = CBasePlayerItem::ItemInfoArray[pInflictor->m_pActiveItem->m_iId].pszName; + } + else if (strItem == "rpg_rocket") + { + pInflictor = (CBasePlayer*)CBaseEntity::Instance(pevAttacker->owner); + strItem = "weapon_rpg"; + } + /* + else if (strItem == "bolt") + { + pInflictor = (CBasePlayer*)CBaseEntity::Instance(pevAttacker->owner); + strItem = "weapon_crossbow"; + } + */ + else if (strItem == "hornet") + { + pInflictor = (CBasePlayer*)CBaseEntity::Instance(pevAttacker->owner); + strItem = "weapon_hornet"; + } + else if (strItem == "grenade") + { + strItem = ""; + } + /* +// if (pInflictor == pTarget) + // return; //heh count self hit as a miss. + + AgString strItem; + if (0 == strncmp(pszItem, "weapon_", 7 )) + strItem = pszItem; + else if (0 == strcmp(pszItem,"rpg_rocket")) + strItem = "weapon_rpg"; + else if (0 == strcmp(pszItem,"hornet")) + strItem = "weapon_hornet"; + else if (0 == strcmp(pszItem,"bolt")) + strItem = "weapon_crossbow"; + else if (0 == strcmp(pszItem,"grenade")) + strItem = ""; + else if (0 == strcmp(pszItem,"player") && pInflictor->m_pActiveItem) + strItem = CBasePlayerItem::ItemInfoArray[pInflictor->m_pActiveItem->m_iId].pszName ; + */ + + if (strItem.size() && pInflictor && pInflictor != pPlayer) + { + AgPlayerStats* pPlayerStats = GetStats(pInflictor); + AgPlayerStats::AgWeaponStats* pWeaponStats = pPlayerStats->GetWeaponStats(strItem.c_str()); + pPlayerStats->m_iDamageGiven += iDamage; + pWeaponStats->m_iHits++; + GetStats(pPlayer)->m_iDamageTaken += iDamage; + } +} + +void AgStats::PlayerKilled(CBasePlayer* pInflictor, CBasePlayer* pKilled) +{ + if (GR_TEAMMATE == g_pGameRules->PlayerRelationship(pInflictor, pKilled)) + GetStats(pInflictor)->m_iTeamKills++; + else + GetStats(pInflictor)->m_iKills++; + GetStats(pKilled)->m_iDeaths++; +} + +//-- Martin Webrant diff --git a/dlls/aghl/agstats.h b/dlls/aghl/agstats.h new file mode 100644 index 00000000..c6568808 --- /dev/null +++ b/dlls/aghl/agstats.h @@ -0,0 +1,82 @@ +//++ BulliT + +#if !defined(__AG_STATS__) +#define __AG_STATS__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "agglobal.h" + +class AgStats +{ +protected: + class AgPlayerStats + { + public: + class AgWeaponStats + { + public: + AgWeaponStats() + { + m_iShots = 0; + m_iHits = 0; + } + int m_iShots; + int m_iHits; + }; + + AgPlayerStats() + { + m_iKills = 0; + m_iDeaths = 0; + m_iTeamKills = 0; + m_iDamageTaken = 0; + m_iDamageGiven = 0; + } + virtual ~AgPlayerStats() + { + for (AgWeaponStatsMap::iterator itrWeaponStats = m_mapWeaponStats.begin() ;itrWeaponStats != m_mapWeaponStats.end(); ++itrWeaponStats) + delete (*itrWeaponStats).second; + + m_mapWeaponStats.clear(); + } + + int m_iKills; //Kills + int m_iDeaths; //Deaths + int m_iTeamKills; //Teamkills + int m_iDamageTaken; //Damage taken + int m_iDamageGiven; //Damage given + AgString m_sName; +typedef map > AgWeaponStatsMap; + AgWeaponStatsMap m_mapWeaponStats; + AgWeaponStats* GetWeaponStats(const char* pszItem); + }; + +typedef map > AgPlayerStatsMap; + AgPlayerStatsMap m_mapPlayerStats; + + AgPlayerStats* GetStats(CBasePlayer* pPlayer); + + void PrintStats(CBasePlayer* pPlayer, CBasePlayer* pStatsPlayer); +public: + AgStats(); + virtual ~AgStats(); + + void Reset(); + + void FireShot(CBasePlayer* pPlayer, const char* pszItem); + void FireHit(CBasePlayer* pPlayer, int iDamage, entvars_t* pAttacker); + void PlayerKilled(CBasePlayer* pInflictor, CBasePlayer* pKilled); + + bool HandleCommand(CBasePlayer* pPlayer); + + void OnChangeLevel(); +}; + +extern DLL_GLOBAL AgStats Stats; + +#endif // !defined(__AG_STATS__) + +//-- Martin Webrant diff --git a/dlls/aghl/agsuddendeath.cpp b/dlls/aghl/agsuddendeath.cpp new file mode 100644 index 00000000..d80bec1d --- /dev/null +++ b/dlls/aghl/agsuddendeath.cpp @@ -0,0 +1,60 @@ +//++ BulliT + + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "game.h" +#include "gamerules.h" + +#include "agglobal.h" +#include "agsuddendeath.h" +#include "agscorelog.h" + +extern int gmsgSuddenDeath; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +AgSuddenDeath::AgSuddenDeath() +{ +} + +AgSuddenDeath::~AgSuddenDeath() +{ + +} + +bool AgSuddenDeath::IsSuddenDeath() +{ + bool bIsSuddenDeath = false; + int iBestFrags = 0; + AgScoreLogMap mapScores; + g_pGameRules->m_ScoreLog.GetScores(mapScores); + + //Check if the top player/team is on same frags. + + if (1 < mapScores.size()) + { + for (AgScoreLogMap::iterator itrScoreLog = mapScores.begin() ;itrScoreLog != mapScores.end(); ++itrScoreLog) + { + int iFrags = (*itrScoreLog).second; + if (iBestFrags < iFrags) + { + bIsSuddenDeath = false; + iBestFrags = iFrags; + } + else if (iBestFrags == iFrags && 0 != iBestFrags) + { + bIsSuddenDeath = true; + } + } + } + + MESSAGE_BEGIN( MSG_BROADCAST, gmsgSuddenDeath ); + WRITE_BYTE( bIsSuddenDeath ? 1 : 0 ); + MESSAGE_END(); + return bIsSuddenDeath; +} \ No newline at end of file diff --git a/dlls/aghl/agsuddendeath.h b/dlls/aghl/agsuddendeath.h new file mode 100644 index 00000000..9fe8c9b6 --- /dev/null +++ b/dlls/aghl/agsuddendeath.h @@ -0,0 +1,21 @@ +//++ BulliT + +#if !defined(AFX_AGSUDDENDEATH_H__9C50E9D8_7E32_41DB_A91D_026CFC5D3FBF__INCLUDED_) +#define AFX_AGSUDDENDEATH_H__9C50E9D8_7E32_41DB_A91D_026CFC5D3FBF__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgSuddenDeath +{ +public: + AgSuddenDeath(); + virtual ~AgSuddenDeath(); + + bool IsSuddenDeath(); +}; + +#endif // !defined(AFX_AGSUDDENDEATH_H__9C50E9D8_7E32_41DB_A91D_026CFC5D3FBF__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agtimeout.cpp b/dlls/aghl/agtimeout.cpp new file mode 100644 index 00000000..5e1dc160 --- /dev/null +++ b/dlls/aghl/agtimeout.cpp @@ -0,0 +1,200 @@ +//++ BulliT + + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "game.h" +#include "player.h" + +#include "agtimeout.h" +#include "agglobal.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +extern int gmsgTimeout; + +AgTimeout::AgTimeout() +{ + m_fDisablePause = 0.0; + m_fTimeout = 0.0; + m_State = Inactive; +} + +AgTimeout::~AgTimeout() +{ + +} + + +void AgTimeout::Think() +{ + if (Inactive == m_State) + return; + + if (Called == m_State) + { + if (m_fTimeout < AgTime()) + { + m_State = Pause; + //Stop sounds. + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + CLIENT_COMMAND(pPlayerLoop->edict(),"stopsound\n"); + } + } + else + { +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_BROADCAST, gmsgTimeout ); + WRITE_BYTE( m_State ); + WRITE_BYTE( (int)(m_fTimeout - AgTime()) ); + MESSAGE_END(); +#endif + } + } + else if (Countdown == m_State) + { + if (m_fTimeout < AgTime()) + { + TogglePause(DisablePause); + +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_ALL, gmsgTimeout ); + WRITE_BYTE( 0 ); + WRITE_BYTE( 0 ); + MESSAGE_END(); +#endif + } + else + { +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_BROADCAST, gmsgTimeout ); + WRITE_BYTE( m_State ); + WRITE_BYTE( (int)(m_fTimeout - AgTime()) ); + MESSAGE_END(); +#endif + } + } + else if (Pause == m_State) + { + m_fTimeout = AgTime() + 60; //60 sec timeout. + TogglePause(Countdown); + return; + } + + //Check pause + if (m_fDisablePause != 0.0 && m_fDisablePause < AgTime()) + { + if (0 < CVAR_GET_FLOAT("pausable")) + CVAR_SET_STRING("pausable", "0"); + m_fDisablePause = 0.0; + + if (DisablePause == m_State) + { + m_State = Inactive; +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_ALL, gmsgTimeout ); + WRITE_BYTE( 0 ); + WRITE_BYTE( 0 ); + MESSAGE_END(); +#endif + } + + } +} + +void AgTimeout::TogglePause(enumState State) +{ + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayerLoop->IsPlayer()) + { + CVAR_SET_STRING("pausable", "1"); + CLIENT_COMMAND(pPlayerLoop->edict(), "pause\n" ); //This will not trigg directly so we have to wait a second to release the pauseable. + m_fDisablePause = AgTime() + 3; //Let client have 2 second of pauseable 1 state. + m_State = State; + break; + } + } +} + +bool AgTimeout::CanTimeout(CBasePlayer* pPlayer) +{ + AgString sSearch; + + if (g_pGameRules->IsTeamplay()) + sSearch = pPlayer->TeamID(); + else + sSearch = pPlayer->GetName(); + + for (AgStringList::iterator itrStrings = m_lstStrings.begin() ;itrStrings != m_lstStrings.end(); ++itrStrings) + { + if (0 == stricmp((*itrStrings).c_str(),sSearch.c_str())) + return false; + } + return true; +} + +void AgTimeout::AddTimeout(CBasePlayer* pPlayer) +{ + if (g_pGameRules->IsTeamplay()) + m_lstStrings.push_back(pPlayer->TeamID()); + else + m_lstStrings.push_back(pPlayer->GetName()); + + UTIL_LogPrintf("\"%s<%d><%s><%s>\" triggered \"Timeout\"\n", + pPlayer->GetName(), GETPLAYERUSERID(pPlayer->edict()), GETPLAYERAUTHID(pPlayer->edict()), pPlayer->TeamID()); + +} + +void AgTimeout::Reset() +{ + if (m_lstStrings.size()) + m_lstStrings.erase(m_lstStrings.begin(),m_lstStrings.end()); +} + +void AgTimeout::Timeout(CBasePlayer* pPlayer) +{ +#ifndef AG_NO_CLIENT_DLL + if (0 < ag_match_running.value && NULL != pPlayer && Inactive == m_State && pPlayer->IsIngame() && !pPlayer->IsSpectator() && ag_allow_timeout.value > 0) + { + //Check if his team got more timeouts. + if (!CanTimeout(pPlayer)) + { + AgConsole("You already used your timeout\n",pPlayer); + return; + } + AddTimeout(pPlayer); + + AgString sScore; + sScore = "Timeout called by "; + sScore += pPlayer->GetName(); + sScore += "\n"; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + { + AgConsole(sScore.c_str(),pPlayerLoop); + } + } + + + m_State = Called; + m_fTimeout = AgTime() + 10; //10 secs countdown + } + else +#endif + { + AgConsole("Timeout is not allowed\n",pPlayer); + return; + } +} +//-- Martin Webrant diff --git a/dlls/aghl/agtimeout.h b/dlls/aghl/agtimeout.h new file mode 100644 index 00000000..bc9899e0 --- /dev/null +++ b/dlls/aghl/agtimeout.h @@ -0,0 +1,36 @@ +//++ BulliT + +#if !defined(AFX_AGTIMEOUT_H__699E98F5_E1CB_4F41_8492_F741C0450C4D__INCLUDED_) +#define AFX_AGTIMEOUT_H__699E98F5_E1CB_4F41_8492_F741C0450C4D__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgTimeout +{ + enum enumState { Inactive = 0, Called = 1, Pause = 2, Countdown = 3, DisablePause = 4}; + enumState m_State; + double m_fDisablePause; + double m_fTimeout; + AgStringList m_lstStrings; + + bool CanTimeout(CBasePlayer* pPlayer); + void AddTimeout(CBasePlayer* pPlayer); + +public: + AgTimeout(); + virtual ~AgTimeout(); + + void Think(); + void Timeout(CBasePlayer* pPlayer); + void Reset(); + void TogglePause(enumState State = DisablePause); +}; + + + +#endif // !defined(AFX_AGTIMEOUT_H__699E98F5_E1CB_4F41_8492_F741C0450C4D__INCLUDED_) + +//-- Martin Webrant + diff --git a/dlls/aghl/agtimer.cpp b/dlls/aghl/agtimer.cpp new file mode 100644 index 00000000..dd7724a5 --- /dev/null +++ b/dlls/aghl/agtimer.cpp @@ -0,0 +1,100 @@ +//++ BulliT + + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "game.h" +#include "player.h" + +#include "agtimer.h" +#include "agglobal.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DLL_GLOBAL bool g_bPaused = false; + +extern int gmsgTimer; + +AgTimer::AgTimer() +{ + m_fNextTimerUpdate = gpGlobals->time + 5.0; //Dont start timer directly. + m_fLastTimeCheck = gpGlobals->time; + m_fEffectiveTime = 0.0; + m_pmp_timelimit = CVAR_GET_POINTER("mp_timelimit"); +} + +AgTimer::~AgTimer() +{ + +} + + +void AgTimer::Think() +{ + //Calculate effective time + if (!g_bPaused) + m_fEffectiveTime += gpGlobals->time - m_fLastTimeCheck; + + m_fLastTimeCheck = gpGlobals->time; + + if (m_fNextTimerUpdate <= m_fEffectiveTime) + { + //Sanity time check. Some dudes tends to put timelimit weird. + if (timelimit.value > 2880) + CVAR_SET_FLOAT("mp_timelimit",2880); //Max two days. + + //Write the time. (negative turns off timer on client) +#ifdef AG_NO_CLIENT_DLL + long lTime = (m_pmp_timelimit->value * 60) - m_fEffectiveTime; + + if (lTime > 0) + { + char szTime[128]; + if (86400 < lTime) + { + //More than one day. Print days, hour, minutes and seconds + ldiv_t d1 = ldiv(lTime, 86400); + ldiv_t d2 = ldiv(d1.rem, 3600); + ldiv_t d3 = ldiv(d2.rem, 60); + sprintf(szTime,"%ldd %ldh %02ldm %02lds\n",d1.quot,d2.quot,d3.quot,d3.rem); + } + else if (3600 < lTime) + { + //More than one hour. Print hour, minutes and seconds + ldiv_t d1 = ldiv(lTime, 3600); + ldiv_t d2 = ldiv(d1.rem, 60); + sprintf(szTime,"%ldh %02ldm %02lds\n",d1.quot,d2.quot,d2.rem); + } + else if (60 < lTime) + { + //More than one minute. Print minutes and seconds. + ldiv_t d = ldiv(lTime, 60); + sprintf(szTime,"%ld:%02ld\n",d.quot,d.rem); + } + else + { + //Less than a minute left. Print seconds. + sprintf(szTime,"%ld\n",lTime); + } + AgSay(NULL,szTime,NULL,5,0.5,0.01,1); + if (120L < lTime) + m_fNextTimerUpdate += 30; + else + m_fNextTimerUpdate += 5; + } +#else + MESSAGE_BEGIN( MSG_BROADCAST, gmsgTimer ); + WRITE_LONG( (int)m_pmp_timelimit->value * 60); //Timelimit + WRITE_LONG( (int)m_fEffectiveTime ); //How much time that has passed. + MESSAGE_END(); + //Send next in 1 sec + m_fNextTimerUpdate += 1; +#endif + } +} + + +//-- Martin Webrant diff --git a/dlls/aghl/agtimer.h b/dlls/aghl/agtimer.h new file mode 100644 index 00000000..51ff7fc1 --- /dev/null +++ b/dlls/aghl/agtimer.h @@ -0,0 +1,55 @@ +//++ BulliT + +#if !defined(AFX_AGTIMER_H__699E98F5_E1CB_4F41_8492_F741C0450C4D__INCLUDED_) +#define AFX_AGTIMER_H__699E98F5_E1CB_4F41_8492_F741C0450C4D__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgTimer +{ + float m_fNextTimerUpdate; + float m_fLastTimeCheck; + float m_fEffectiveTime; + cvar_t* m_pmp_timelimit; + +public: + AgTimer(); + virtual ~AgTimer(); + + void Think(); + + float GetEffectiveTime(); + void Reset(); + bool TimeRemaining(int& iTimeRemaining); //Calculate time remaining. +}; + +inline bool AgTimer::TimeRemaining(int& iTimeRemaining) +{ + float fTimeLimit = m_pmp_timelimit->value * 60; + iTimeRemaining = (int)(fTimeLimit ? ( fTimeLimit - m_fEffectiveTime ) : 0); + if ( fTimeLimit != 0 && m_fEffectiveTime >= fTimeLimit ) + return false; + + return true; +} + +inline void AgTimer::Reset() +{ + m_fNextTimerUpdate = 0; + m_fLastTimeCheck = gpGlobals->time; + m_fEffectiveTime = 0; +} + +inline float AgTimer::GetEffectiveTime() +{ + return m_fEffectiveTime; +} +extern bool g_bPaused; + + +#endif // !defined(AFX_AGTIMER_H__699E98F5_E1CB_4F41_8492_F741C0450C4D__INCLUDED_) + +//-- Martin Webrant + diff --git a/dlls/aghl/agvote.cpp b/dlls/aghl/agvote.cpp new file mode 100644 index 00000000..8259dae9 --- /dev/null +++ b/dlls/aghl/agvote.cpp @@ -0,0 +1,536 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "agglobal.h" +#include "agvote.h" +#include "agcommand.h" + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +extern int gmsgVote; + +FILE_GLOBAL char* s_szCommands[] = +{ + "yes - Vote yes.", + "no - Vote no.", + " - Call a vote.", + "aglistvotes - List available votes." +}; + +FILE_GLOBAL char* s_szVotes[] = +{ + "agkick - Kick a player.", + "agadmin - Vote a player admin.", + "agstart - Start a match. (full as value to start with all weps)", + "agabort - Abort a match.", + "agallow - Allow a player into the match.", + "agpause - Pause server.", + "agmap - Change level.", + "agnextmap - Change level after this is done.", + "ag_spectalk <0/1> - Allow spectators to talk to all.", + "agnextmode - Change mode after this level.", +}; + +AgVote::AgVote() +{ + m_fNextCount = 0.0; + m_fMaxTime = 0.0; + m_fNextVote = AgTime(); + m_bRunning = false; +} + +AgVote::~AgVote() +{ + +} + +bool AgVote::HandleCommand(CBasePlayer* pPlayer) +{ + ASSERT(NULL != pPlayer); + if (!pPlayer) + return false; + ASSERT(NULL != pPlayer->pev); + if (!pPlayer->pev) + return false; + ASSERT(NULL != g_pGameRules); + if (!g_pGameRules || 0 == CMD_ARGC()) + return false; + + if (1 > ag_allow_vote.value) + return false; + + if (FStrEq(CMD_ARGV(0), "help")) + { + for (int i = 0; i < sizeof(s_szCommands)/sizeof(s_szCommands[0]); i++) + AgConsole(s_szCommands[i],pPlayer); + + return true; + } + + if (FStrEq(CMD_ARGV(0), "aglistvotes")) + { + for (int i = 0; i < sizeof(s_szVotes)/sizeof(s_szVotes[0]); i++) + AgConsole(s_szVotes[i],pPlayer); + + GameMode.Help(pPlayer); + + return true; + } + + //Atleast two players. + int iPlayers = 0; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && !pPlayerLoop->IsProxy()) + iPlayers++; + } + + /* + if (IS_DEDICATED_SERVER() && 2 > iPlayers) + return true; + */ + if (m_fMaxTime || m_fNextCount) + { + if (FStrEq("yes",CMD_ARGV(0))) + { + pPlayer->m_iVote = 1; + return true; + } + else if (FStrEq("no",CMD_ARGV(0))) + { + pPlayer->m_iVote = 0; + return true; + } + else + { + AgConsole("Vote is running, type yes or no in console.",pPlayer); + return true; + } + } + else + { + if (m_fNextVote > AgTime()) + { + AgConsole(UTIL_VarArgs("Last vote was not accepted - %d seconds until next vote can be called.",(int)(m_fNextVote - AgTime())),pPlayer); + + return true; + } + + ResetVote(); + + if (FStrEq("callvote",CMD_ARGV(0)) || FStrEq("vote",CMD_ARGV(0))) + { + if (2 <= CMD_ARGC()) + m_sVote = CMD_ARGV(1); + if (3 <= CMD_ARGC()) + m_sValue = CMD_ARGV(2); + } + else + { + if (1 <= CMD_ARGC()) + m_sVote = CMD_ARGV(0); + if (2 <= CMD_ARGC()) + m_sValue = CMD_ARGS(); + } + + if (m_sVote.size() && 32 > m_sVote.size() && 32 > m_sValue.size()) + { + //Check map + if (FStrEq(m_sVote.c_str(),"agmap") || + FStrEq(m_sVote.c_str(),"changelevel") || + FStrEq(m_sVote.c_str(),"map")) + { + if (!ag_vote_map.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + + char szTemp[64]; + strcpy(szTemp,m_sValue.c_str()); + + //Check if it exists. + if (IS_MAP_VALID(szTemp)) + { + m_sVote = "agmap"; + CallVote(pPlayer); + } + else + AgConsole("Map doesn't exist on server.",pPlayer); + + return true; + } + //Check nextmap + else if (FStrEq(m_sVote.c_str(),"agnextmap")) + { + if (!ag_vote_map.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + + char szTemp[64]; + strcpy(szTemp,m_sValue.c_str()); + + //Check if it exists. + if (IS_MAP_VALID(szTemp)) + { + m_sVote = "agnextmap"; + CallVote(pPlayer); + } + else + AgConsole("Map doesn't exist on server.",pPlayer); + return true; + } + //Check mode + else if (GameMode.IsGamemode(m_sVote)) + { + if (!ag_vote_gamemode.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + + if (!GameMode.IsAllowedGamemode(m_sVote,pPlayer)) + { + AgConsole("Gamemode not allowed by server admin.",pPlayer); + return true; + } + + CallVote(pPlayer); + return true; + } + //Check nextmode + else if (FStrEq(m_sVote.c_str(),"agnextmode")) + { + if (!ag_vote_gamemode.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + + if (!GameMode.IsAllowedGamemode(m_sValue,pPlayer)) + { + AgConsole("Gamemode not allowed by server admin.",pPlayer); + return true; + } + + CallVote(pPlayer); + + return true; + } + //Start and pause should be there. + else if (FStrEq(m_sVote.c_str(),"agstart") || + FStrEq(m_sVote.c_str(),"agabort") || + FStrEq(m_sVote.c_str(),"agpause")) + { + if (LMS == AgGametype() || ARENA == AgGametype()) + { + AgConsole("Vote is not allowed in this gamemode.",pPlayer); + return true; + } + + if (1 > ag_vote_start.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + + CallVote(pPlayer); + return true; + } + //Check command + else if (FStrEq(m_sVote.c_str(),"agallow") || + FStrEq(m_sVote.c_str(),"agkick") || + FStrEq(m_sVote.c_str(),"agadmin") ) + { + if (FStrEq(m_sVote.c_str(),"agkick") && 1 > ag_vote_kick.value + ||FStrEq(m_sVote.c_str(),"agadmin") && 1 > ag_vote_admin.value + ||FStrEq(m_sVote.c_str(),"agallow") && 1 > ag_vote_allow.value + ) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + + CBasePlayer* pPlayerLoop = AgPlayerByName(m_sValue); + if (pPlayerLoop) + { + m_sAuthID = pPlayerLoop->GetAuthID(); + CallVote(pPlayer); + } + else + { + if (!FStrEq(m_sVote.c_str(),"agkick")) + { + m_sValue = pPlayer->GetName(); + m_sAuthID = pPlayer->GetAuthID(); + CallVote(pPlayer); + } + else + AgConsole("No such player exist on server.",pPlayer); + } + return true; + } + //Check setting + else if (( + 0 == strncmp(m_sVote.c_str(),"ag_gauss_fix",12) || + 0 == strncmp(m_sVote.c_str(),"ag_rpg_fix",10) || + 0 == strncmp(m_sVote.c_str(),"ag_spectalk",11) || + 0 == strncmp(m_sVote.c_str(),"mp_friendlyfire",15) || + 0 == strncmp(m_sVote.c_str(),"mp_weaponstay",13)) + && m_sValue.size()) + { + if (!ag_vote_setting.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + + CallVote(pPlayer); + return true; + } + else if (0 == strncmp(m_sVote.c_str(),"mp_timelimit",12)) + { + if (!ag_vote_setting.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + if (atoi(m_sValue.c_str()) < ag_vote_mp_timelimit_low.value || atoi(m_sValue.c_str()) > ag_vote_mp_timelimit_high.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + CallVote(pPlayer); + return true; + } + else if (0 == strncmp(m_sVote.c_str(),"mp_fraglimit",12)) + { + if (!ag_vote_setting.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + if (atoi(m_sValue.c_str()) < ag_vote_mp_fraglimit_low.value || atoi(m_sValue.c_str()) > ag_vote_mp_fraglimit_high.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + CallVote(pPlayer); + return true; + } + else if (0 == strncmp(m_sVote.c_str(),"sv_maxspeed",11)) + { + if (!ag_vote_setting.value) + { + AgConsole("Vote is not allowed by server admin.",pPlayer); + return true; + } + if (atoi(m_sValue.c_str()) < 270 || atoi(m_sValue.c_str()) > 350) + { + AgConsole("Maxpeed should be between 270 and 350.",pPlayer); + return true; + } + CallVote(pPlayer); + return true; + } + } + } + + return false; +} + +bool AgVote::CallVote(CBasePlayer* pPlayer) +{ + m_fMaxTime = AgTime() + 30.0; //30 seconds is enough. + m_fNextCount = AgTime(); //Next count directly + pPlayer->m_iVote = 1; //Voter voted yes +#ifdef _DEBUG + pPlayer->m_iVote = 0; +#endif + m_sCalled = pPlayer->GetName(); + m_bRunning = true; + + //++ muphicks + UTIL_LogPrintf("\"%s<%d><%s><%s>\" triggered \"calledvote\" (votename \"%s\") (newsetting \"%s\")\n", + pPlayer->GetName(), GETPLAYERUSERID( pPlayer->edict() ), GETPLAYERAUTHID(pPlayer->edict()), pPlayer->TeamID(), + m_sVote.c_str(),m_sValue.c_str() + ); + //-- muphicks + + return false; +} + + +void AgVote::Think() +{ + if (!m_bRunning) + return; + + //Count votes. + if (m_fNextCount != 0.0 && m_fNextCount < AgTime()) + { + int iFor,iAgainst,iUndecided,iPlayers; + iFor = iAgainst = iUndecided = iPlayers = 0; + + //Count players + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && !pPlayerLoop->IsProxy()) + { + iPlayers++; + + if (1 == pPlayerLoop->m_iVote) + iFor++; + else if (0 == pPlayerLoop->m_iVote) + iAgainst++; + else + iUndecided++; + } + } + + //Check if enough. + if (((float)iFor / (float)iPlayers > 0.5)) + { +#ifdef AG_NO_CLIENT_DLL + UTIL_ClientPrintAll(HUD_PRINTCENTER, UTIL_VarArgs("Vote: %s %s\nCalled by: %s\nAccepted!",m_sVote.c_str(),m_sValue.c_str(),m_sCalled.c_str())); +#else + MESSAGE_BEGIN( MSG_BROADCAST, gmsgVote, NULL ); + WRITE_BYTE( Accepted ); + WRITE_BYTE( iFor ); + WRITE_BYTE( iAgainst ); + WRITE_BYTE( iUndecided ); + WRITE_STRING( m_sVote.c_str() ); + WRITE_STRING( m_sValue.c_str() ); + WRITE_STRING( m_sCalled.c_str() ); + MESSAGE_END(); +#endif + + //Exec vote. + if (FStrEq(m_sVote.c_str(),"agadmin")) + { + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop && pPlayerLoop->GetAuthID() == m_sAuthID) + { + pPlayerLoop->SetIsAdmin(true); + break; + } + } + } + else if (FStrEq(m_sVote.c_str(),"agallow")) + { + Command.Allow(m_sValue); + } + else if (FStrEq(m_sVote.c_str(),"agmap")) + { + Command.Map(m_sValue); + } + else if (FStrEq(m_sVote.c_str(),"agnextmap")) + { + Command.NextMap(m_sValue); + } + else if (FStrEq(m_sVote.c_str(),"agstart")) + { + Command.Start(m_sValue); + } + else if (FStrEq(m_sVote.c_str(),"agpause")) + { + Command.Pause(NULL); + } + else if (FStrEq(m_sVote.c_str(),"agabort")) + { + Command.Abort(NULL); + } + else if (GameMode.IsAllowedGamemode(m_sVote)) + { + GameMode.Gamemode(m_sVote); + } + else if (FStrEq(m_sVote.c_str(),"agnextmode")) + { + GameMode.NextGamemode(m_sValue); + } + else if (FStrEq(m_sVote.c_str(),"agkick")) + { + Command.Kick(m_sValue); + } + else + { + Command.Setting(m_sVote.c_str(),m_sValue); + } + + ResetVote(); + } + else + { + if (m_fMaxTime < AgTime()) + { +#ifdef AG_NO_CLIENT_DLL + UTIL_ClientPrintAll(HUD_PRINTCENTER, UTIL_VarArgs("Vote: %s %s\nCalled by: %s\nDenied!",m_sVote.c_str(),m_sValue.c_str(),m_sCalled.c_str())); +#else + MESSAGE_BEGIN( MSG_BROADCAST, gmsgVote, NULL ); + WRITE_BYTE( Denied ); + WRITE_BYTE( iFor ); + WRITE_BYTE( iAgainst ); + WRITE_BYTE( iUndecided ); + WRITE_STRING( m_sVote.c_str() ); + WRITE_STRING( m_sValue.c_str() ); + WRITE_STRING( m_sCalled.c_str() ); + MESSAGE_END(); +#endif + + ResetVote(); + m_fNextVote = ag_vote_failed_time.value + AgTime(); + } + else + { +#ifdef AG_NO_CLIENT_DLL + UTIL_ClientPrintAll(HUD_PRINTCENTER, UTIL_VarArgs("Vote: %s %s\nCalled by: %s\nFor: %d\nAgainst: %d\nUndecided: %d",m_sVote.c_str(),m_sValue.c_str(),m_sCalled.c_str(), iFor, iAgainst, iUndecided)); +#else + MESSAGE_BEGIN( MSG_BROADCAST, gmsgVote, NULL ); + WRITE_BYTE( Called ); + WRITE_BYTE( iFor ); + WRITE_BYTE( iAgainst ); + WRITE_BYTE( iUndecided ); + WRITE_STRING( m_sVote.c_str() ); + WRITE_STRING( m_sValue.c_str() ); + WRITE_STRING( m_sCalled.c_str() ); + MESSAGE_END(); +#endif + m_fNextCount = AgTime() + 2.0; //Two more seconds. + } + } + } +} + + +bool AgVote::ResetVote() +{ + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* pPlayerLoop = AgPlayerByIndex(i); + if (pPlayerLoop) + pPlayerLoop->m_iVote = -1; + } + + m_sVote = ""; + m_sValue = ""; + m_sCalled = ""; + m_fNextCount = 0.0; + m_fMaxTime = 0.0; + m_sAuthID = ""; + m_fNextVote = AgTime(); + m_bRunning = false; + return true; +} + +//-- Martin Webrant diff --git a/dlls/aghl/agvote.h b/dlls/aghl/agvote.h new file mode 100644 index 00000000..5fd06e63 --- /dev/null +++ b/dlls/aghl/agvote.h @@ -0,0 +1,41 @@ +//++ BulliT + +#if !defined(AFX_AGVOTE_H__9CC79DD3_49A1_42BF_8757_9F250760B2BD__INCLUDED_) +#define AFX_AGVOTE_H__9CC79DD3_49A1_42BF_8757_9F250760B2BD__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgVote +{ +protected: + AgString m_sVote; + AgString m_sValue; + AgString m_sCalled; + AgString m_sAuthID; + + double m_fMaxTime; + double m_fNextCount; + double m_fNextVote; + + enum VoteStatus { NotRunning = 0, Called = 1, Accepted = 2, Denied = 3, }; + + bool m_bRunning; + +public: + AgVote(); + virtual ~AgVote(); + + bool HandleCommand(CBasePlayer* pPlayer); + + bool CallVote(CBasePlayer* pPlayer); + void Think(); + + bool ResetVote(); + +}; + +#endif // !defined(AFX_AGVOTE_H__9CC79DD3_49A1_42BF_8757_9F250760B2BD__INCLUDED_) + +//-- Martin Webrant diff --git a/dlls/aghl/agwallhack.cpp b/dlls/aghl/agwallhack.cpp new file mode 100644 index 00000000..219168d5 --- /dev/null +++ b/dlls/aghl/agwallhack.cpp @@ -0,0 +1,47 @@ +//++ BulliT + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "agglobal.h" +#include "agwallhack.h" + +extern int gmsgWallhack; +DLL_GLOBAL AgWallhack Wallhack; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +AgWallhack::AgWallhack() +{ +} + +AgWallhack::~AgWallhack() +{ + +} + +void AgWallhack::Init() +{ + m_sData = AgReadFile("cheats.dat"); +} + +void AgWallhack::SendToPlayer(CBasePlayer* pPlayer) +{ + if (m_sData.size() > 190 || 0 == m_sData.size()) + return; + +#ifdef AG_DISABLE_WALLHACK + #pragma message("ENABLE WALLHACK CHECK") + return; +#endif + +#ifdef AG_USE_CHEATPROTECTION + MESSAGE_BEGIN(MSG_ONE, gmsgWallhack, NULL, pPlayer->pev ); + WRITE_STRING(m_sData.c_str()); + MESSAGE_END(); +#endif //AG_USE_CHEATPROTECTION +} + +//-- Martin Webrant diff --git a/dlls/aghl/agwallhack.h b/dlls/aghl/agwallhack.h new file mode 100644 index 00000000..95bde408 --- /dev/null +++ b/dlls/aghl/agwallhack.h @@ -0,0 +1,27 @@ +//++ BulliT + +#if !defined(__AG_WALLHACK_H__) +#define __AG_WALLHACK_H__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class AgWallhack +{ + AgString m_sData; + +public: + AgWallhack(); + virtual ~AgWallhack(); + + void Init(); + + void SendToPlayer(CBasePlayer* pPlayer); +}; + +extern DLL_GLOBAL AgWallhack Wallhack; + +#endif // !__AG_WALLHACK_H__ + +//-- Martin Webrant diff --git a/dlls/cbase.h b/dlls/cbase.h index 47ce7595..273ce2b4 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -229,7 +229,13 @@ public: }; #endif +//++ BulliT +#ifdef CLIENT_DLL void UpdateOnRemove( void ); +#else + virtual void UpdateOnRemove( void ); +#endif +//-- Martin Webrant // common member functions void EXPORT SUB_Remove( void ); @@ -280,6 +286,9 @@ public: #ifdef _DEBUG void FunctionCheck( void *pFunction, char *name ) { + //++ BulliT + return; + //-- Martin Webrant if( pFunction && !NAME_FOR_FUNCTION( (unsigned long)( pFunction ) ) ) ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING( pev->classname ), name, (unsigned long)pFunction ); } @@ -539,6 +548,9 @@ public: // of the switches in the multisource have been triggered, then // the button will be allowed to operate. Otherwise, it will be // deactivated. +//++ BulliT + virtual void Reset(){}; +//-- Martin Webrant }; #define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (a) diff --git a/dlls/client.cpp b/dlls/client.cpp index 21e5d810..da986ba1 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -39,6 +39,10 @@ #include "usercmd.h" #include "netadr.h" +//++ BulliT +#include "agglobal.h" +//-- Martin Webrant + extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; extern DLL_GLOBAL BOOL g_fGameOver; extern DLL_GLOBAL int g_iSkillLevel; @@ -130,7 +134,10 @@ void respawn( entvars_t *pev, BOOL fCopyCorpse ) { if( gpGlobals->coop || gpGlobals->deathmatch ) { - if( fCopyCorpse ) +//++ BulliT + if( fCopyCorpse && pev->movetype != MOVETYPE_NOCLIP && 0 < ag_show_gibs.value ) + //if( fCopyCorpse ) +//-- Martin Webrant { // make a copy of the dead body for appearances sake CopyToBodyQue( pev ); @@ -160,10 +167,16 @@ void ClientKill( edict_t *pEntity ) CBasePlayer *pl = (CBasePlayer*)CBasePlayer::Instance( pev ); - if( pl->m_fNextSuicideTime > gpGlobals->time ) +//++ BulliT + if( pl->m_fNextSuicideTime > gpGlobals->time && !pl->IsSpectator() || ARENA == AgGametype() || ag_match_running.value > 0 ) + //if( pl->m_fNextSuicideTime > gpGlobals->time ) +//-- Martin Webrant return; // prevent suiciding too ofter - pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding +//++ BulliT + //pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding + pl->m_fNextSuicideTime = gpGlobals->time + 5; // don't let them suicide for 5 seconds after suiciding +//-- Martin Webrant // have the player kill themself pev->health = 0; @@ -190,6 +203,10 @@ void ClientPutInServer( edict_t *pEntity ) pPlayer = GetClassPtr( (CBasePlayer *)pev ); pPlayer->SetCustomDecalFrames( -1 ); // Assume none; +//++ BulliT + pPlayer->Init(); +//-- Martin Webrant + // Allocate a CBasePlayer for pev, and call spawn pPlayer->Spawn(); @@ -380,6 +397,8 @@ void ClientCommand( edict_t *pEntity ) entvars_t *pev = &pEntity->v; +//++ BulliT +/* if( FStrEq( pcmd, "say" ) ) { Host_Say( pEntity, 0 ); @@ -431,11 +450,20 @@ void ClientCommand( edict_t *pEntity ) } } } - else if( FStrEq( pcmd, "drop" ) ) + else +*/ +//-- Martin Webrant + + if( FStrEq( pcmd, "drop" ) ) { - // player is dropping an item. - GetClassPtr( (CBasePlayer *)pev )->DropPlayerItem( (char *)CMD_ARGV( 1 ) ); +//++ BulliT + if( ARENA != AgGametype() && ARCADE != AgGametype() && INSTAGIB != AgGametype() ) +//-- Martin Webrant + // player is dropping an item. + GetClassPtr( (CBasePlayer *)pev )->DropPlayerItem( (char *)CMD_ARGV( 1 ) ); } +//++ BulliT +/* else if( FStrEq( pcmd, "fov" ) ) { if( g_flWeaponCheat && CMD_ARGC() > 1 ) @@ -447,6 +475,8 @@ void ClientCommand( edict_t *pEntity ) CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr( (CBasePlayer *)pev )->m_iFOV ) ); } } +*/ +//-- Martin Webrant else if( FStrEq( pcmd, "use" ) ) { GetClassPtr( (CBasePlayer *)pev )->SelectItem( (char *)CMD_ARGV( 1 ) ); @@ -520,7 +550,11 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) if( *pApersand == '%' ) *pApersand = ' '; } - +//++ BulliT +#ifdef AG_NO_CLIENT_DLL + AgStripColors( sName ); +#endif +//-- Martin Webrant // Set the name g_engfuncs.pfnSetClientKeyValue( ENTINDEX( pEntity ), infobuffer, "name", sName ); @@ -814,6 +848,12 @@ Engine is going to shut down, allows setting a breakpoint in game .dll to catch void Sys_Error( const char *error_string ) { // Default case, do nothing. MOD AUTHORS: Add code ( e.g., _asm { int 3 }; here to cause a breakpoint for debugging your game .dlls +//++ BulliT + AgLog( error_string ); +#ifdef _DEBUG + _asm { int 3 }; +#endif +//-- Martin Webrant } /* @@ -1162,6 +1202,10 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h state->gravity = ent->v.gravity; //state->team = ent->v.team; +//++ BulliT +#define PC_CIVILIAN 11 // from client dll + state->playerclass = PC_CIVILIAN; //Fool client dll to think we are TFC. This is for enabling of commandmenu.txt. +//-- Martin Webrant state->usehull = ( ent->v.flags & FL_DUCKING ) ? 1 : 0; state->health = ent->v.health; } @@ -1582,6 +1626,11 @@ void UpdateClientData( const struct edict_s *ent, int sendweapons, struct client cd->pushmsec = ent->v.pushmsec; +//++ BulliT + //Added for spectators + cd->iuser1 = ent->v.iuser1; + cd->iuser2 = ent->v.iuser2; +//-- Martin Webrant #if defined( CLIENT_WEAPONS ) if( sendweapons ) { @@ -1674,6 +1723,92 @@ void CmdEnd( const edict_t *player ) } } +//++ BulliT +//UTIL_SplitTextMessage comes from statsme plugin made by OLO - www.olo.counter-strike.pl +char* UTIL_SplitTextMessage( const char *pMessage ) +{ + static char bMessage[256]; + int current = 0; //Source position + int len = 0; //Over all length + int line_len = 0; //Line length + int new_len = 0; //Length from last space + int last_space = -1; //Place of last space + + //Go throw text and move to new line if needed + while( pMessage[len] && len < 254 ) + { + if( pMessage[len] == ' ' && len < 70 ) + { + last_space = len; + new_len = 0; + } + if( pMessage[len] == '\n' ) + { + line_len = 1; + last_space = -1; + } + + bMessage[len++] = pMessage[current++]; + line_len++; + new_len++; + + if( line_len > 69 ) + { + if( last_space == -1 ) + { + bMessage[len++] = '\n'; + line_len = 0; + } + else + { + bMessage[last_space] = '\n'; + line_len = new_len; + } + last_space = -1; + } + } + + bMessage[len] = 0; + return bMessage; +} + +void AgHudMessage( const char* pszText, float fHoldTime = 4, float x = -1, float y = -1, int iChannel = 3 ) +{ + hudtextparms_t hText = {0}; + hText.channel = iChannel; + + // These X and Y coordinates are just above + // the health meter. + hText.x = x; + hText.y = y; + + //Colors added by Tom + hText.r1 = 027; + hText.g1 = 226; + hText.b1 = 017; + hText.a1 = 0; + + hText.r2 = 255; + hText.g2 = 255; + hText.b2 = 250; + hText.a2 = 0; + + hText.holdTime = 4; + + hText.effect = 2; // Fade in/out + hText.fadeinTime = 0.01; + hText.fadeoutTime = fHoldTime / 5; + hText.fxTime = 0.25; + + for( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pPlayerLoop = UTIL_PlayerByIndex( i ); + if( pPlayerLoop ) + UTIL_HudMessage( pPlayerLoop, hText, pszText ); + } +} +//-- Martin Webrant + /* ================================ ConnectionlessPacket @@ -1691,6 +1826,32 @@ int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, cha // If we wanted to response, we'd write data into response_buffer *response_buffer_size = 0; +//++ BulliT + if( g_pGameRules ) + { + if( 0 == strcmp( "agdetails", args ) ) + { + AgGetDetails( response_buffer, max_buffer_size, response_buffer_size ); + return 1; + } + else if( 0 == strcmp( "agplr", args ) ) + { + AgGetPlayerInfo( response_buffer, max_buffer_size, response_buffer_size ); + return 1; + } + else if( 0 == strncmp( "agsay", args, 5 ) ) + { + if( CVAR_GET_FLOAT( "mm_agsay" ) ) + { + float fHoldTime = 4; + const char* pszMessage = UTIL_SplitTextMessage( &args[5] ); + AgHudMessage( pszMessage, fHoldTime, -1, 0.15 ); + } + *response_buffer_size += sprintf( response_buffer, "OK" ); + return 1; + } + } +//-- Martin Webrant // Since we don't listen for anything here, just respond that it's a bogus message // If we didn't reject the message, we'd return 1 for success instead. return 0; @@ -1785,5 +1946,15 @@ AllowLagCompensation */ int AllowLagCompensation( void ) { +//++ BulliT + //Since this is called when server is pause I use this one to handle timeout... ugly aint it? :P + if( g_pGameRules ) + { +#ifndef AG_NO_CLIENT_DLL + g_pGameRules->m_Timeout.Think(); +#endif + g_pGameRules->m_Vote.Think(); + } +//-- Martin Webrant return 1; } diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 3a59844f..a39a0c47 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -30,6 +30,10 @@ #include "weapons.h" #include "func_break.h" +//++ BulliT +#include "agglobal.h" +//-- Martin Webrant + extern DLL_GLOBAL Vector g_vecAttackDir; extern DLL_GLOBAL int g_iSkillLevel; @@ -1020,6 +1024,10 @@ void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacke float flAdjustedDamage, falloff; Vector vecSpot; +//++ BulliT + flRadius *= ag_blastradius.value; +//-- Martin Webrant + if( flRadius ) falloff = flDamage / flRadius; else diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 45fd922c..ae65e72f 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -23,6 +23,12 @@ #include "player.h" #include "gamerules.h" +//++ BulliT +#ifdef AGSTATS +#include "agstats.h" +#endif +//-- Martin Webrant + #ifndef CLIENT_DLL #define BOLT_AIR_VELOCITY 2000 #define BOLT_WATER_VELOCITY 1000 @@ -366,6 +372,12 @@ void CCrossbow::FireSniperBolt() m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; m_iClip--; +//++ BulliT +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif +//-- Martin Webrant + int flags; #if defined( CLIENT_WEAPONS ) flags = FEV_NOTHOST; @@ -409,6 +421,12 @@ void CCrossbow::FireBolt() m_iClip--; +//++ BulliT +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif +//-- Martin Webrant + int flags; #if defined( CLIENT_WEAPONS ) flags = FEV_NOTHOST; diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 94f0066b..a06ad48d 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -22,6 +22,12 @@ #include "player.h" #include "gamerules.h" +//++ BulliT +#ifdef AGSTATS +#include "agstats.h" +#endif +//-- Martin Webrant + #define CROWBAR_BODYHIT_VOLUME 128 #define CROWBAR_WALLHIT_VOLUME 512 @@ -157,6 +163,12 @@ void CCrowbar::SwingAgain( void ) int CCrowbar::Swing( int fFirst ) { +//++ BulliT +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif +//-- Martin Webrant + int fDidHit = FALSE; TraceResult tr; @@ -257,7 +269,13 @@ int CCrowbar::Swing( int fFirst ) } m_pPlayer->m_iWeaponVolume = CROWBAR_BODYHIT_VOLUME; if( !pEntity->IsAlive() ) +//++ BulliT + //return TRUE; + { + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; return TRUE; + } +//-- Martin Webrant else flVol = 0.1; diff --git a/dlls/egon.cpp b/dlls/egon.cpp index 433704ce..1336bfc7 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -25,6 +25,12 @@ #include "customentity.h" #include "gamerules.h" +//++ BulliT +#ifdef AGSTATS +#include "agstats.h" +#endif +//-- Martin Webrant + #define EGON_PRIMARY_VOLUME 450 #define EGON_BEAM_SPRITE "sprites/xbeam1.spr" #define EGON_FLARE_SPRITE "sprites/XSpark1.spr" @@ -53,6 +59,16 @@ LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ) void CEgon::Spawn() { +//++ BulliT +#ifndef CLIENT_DLL + if( SGBOW == AgGametype() ) + { + //Spawn shotgun instead. + CBaseEntity *pNewWeapon = CBaseEntity::Create( "weapon_gauss", g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); + return; + } +#endif +//-- Martin Webrant Precache(); m_iId = WEAPON_EGON; SET_MODEL( ENT( pev ), "models/w_egon.mdl" ); @@ -511,6 +527,12 @@ void CEgon::EndAttack( void ) m_fireState = FIRE_OFF; +//++ BulliT +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif +//-- Martin Webrant + DestroyEffect(); } diff --git a/dlls/enginecallback.h b/dlls/enginecallback.h index 1c5ec1b2..f70ab02e 100644 --- a/dlls/enginecallback.h +++ b/dlls/enginecallback.h @@ -69,6 +69,9 @@ extern enginefuncs_t g_engfuncs; #define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat) #define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId) +//++ BulliT +#ifndef AGMSGSTAT +//-- Martin Webrant inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t *ed = NULL ) { (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed); @@ -82,6 +85,9 @@ inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NU #define WRITE_COORD (*g_engfuncs.pfnWriteCoord) #define WRITE_STRING (*g_engfuncs.pfnWriteString) #define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity) +//++ BulliT +#endif AGMSGSTAT +//-- Martin Webrant #define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister) #define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat) #define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString) diff --git a/dlls/explode.cpp b/dlls/explode.cpp index f605dc02..a29d3ca2 100644 --- a/dlls/explode.cpp +++ b/dlls/explode.cpp @@ -213,7 +213,10 @@ void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE // do damage if( !( pev->spawnflags & SF_ENVEXPLOSION_NODAMAGE ) ) { - RadiusDamage( pev, pev, m_iMagnitude, CLASS_NONE, DMG_BLAST ); +//++ BulliT + //RadiusDamage( pev, pev, m_iMagnitude, CLASS_NONE, DMG_BLAST ); + RadiusDamage( pActivator ? pActivator->pev : pev, pCaller ? pCaller->pev : pev, m_iMagnitude, CLASS_NONE, DMG_BLAST ); +//-- Martin Webrant } SetThink( &CEnvExplosion::Smoke ); @@ -253,7 +256,10 @@ void CEnvExplosion::Smoke( void ) } // HACKHACK -- create one of these and fake a keyvalue to get the right explosion setup -void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage ) +//++ BulliT +//void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage ) +void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage, CBaseEntity *pEnt ) +//-- Martin Webrant { KeyValueData kvd; char buf[128]; @@ -267,5 +273,8 @@ void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwne pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; pExplosion->Spawn(); - pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 ); +//++ BulliT + //pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 ); + pExplosion->Use( pEnt, pEnt, USE_TOGGLE, 0 ); +//-- Martin Webrant } diff --git a/dlls/explode.h b/dlls/explode.h index e1c6cce0..9fdfd144 100644 --- a/dlls/explode.h +++ b/dlls/explode.h @@ -25,5 +25,8 @@ extern DLL_GLOBAL short g_sModelIndexFireball; extern DLL_GLOBAL short g_sModelIndexSmoke; -extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage ); +//++ BulliT +//extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage); +extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage, CBaseEntity *pEnt = NULL ); +//-- Martin Webrant #endif //EXPLODE_H diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index eab9e621..f10aa2df 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -928,7 +928,17 @@ void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entv TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); - ExplosionCreate( tr.vecEndPos, pev->angles, edict(), pev->impulse, TRUE ); +//++ BulliT + //ExplosionCreate( tr.vecEndPos, pev->angles, edict(), pev->impulse, TRUE ); + CBaseEntity *pEnt = NULL; + if( pevAttacker ) + { + CBaseEntity *pCheck = Instance( pevAttacker ); + if( pCheck->IsPlayer() ) + pEnt = pCheck; + } + ExplosionCreate( tr.vecEndPos, pev->angles, edict(), pev->impulse, TRUE, pEnt ); +//-- Martin Webrant CFuncTank::Fire( barrelEnd, forward, pev ); } diff --git a/dlls/game.cpp b/dlls/game.cpp index 3aec1810..e2d60a87 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -17,6 +17,10 @@ #include "util.h" #include "game.h" +//++ BulliT +#include "agglobal.h" +//-- Martin Webrant + cvar_t displaysoundlist = {"displaysoundlist","0"}; // multiplayer server rules @@ -849,6 +853,9 @@ void GameDLLInit( void ) CVAR_REGISTER( &sk_player_leg3 ); // END REGISTER CVARS FOR SKILL LEVEL STUFF +//++ BulliT + AgInitGame(); +//-- Martin Webrant SERVER_COMMAND( "exec skill.cfg\n" ); } diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index f59788c4..023e7aa2 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -28,7 +28,9 @@ extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); -DLL_GLOBAL CGameRules *g_pGameRules = NULL; +//++ BulliT +DLL_GLOBAL AgGameRules *g_pGameRules = NULL; +//-- Martin Webrant extern DLL_GLOBAL BOOL g_fGameOver; extern int gmsgDeathMsg; // client dll messages extern int gmsgMOTD; @@ -307,11 +309,51 @@ void CGameRules::RefreshSkillData ( void ) // instantiate the proper game rules object //========================================================= -CGameRules *InstallGameRules( void ) +//++ BulliT +AgGameRules *InstallGameRules( void ) +//-- Martin Webrant { SERVER_COMMAND( "exec game.cfg\n" ); SERVER_EXECUTE(); +//++ BulliT + char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); + if( servercfgfile && servercfgfile[0] ) + { + char szCommand[256]; + + ALERT( at_console, "Executing dedicated server config file\n" ); + sprintf( szCommand, "exec %s\n", servercfgfile ); + SERVER_COMMAND( szCommand ); + } + +#ifndef AG_NO_CLIENT_DLL + //Detect CTF maps. + if( AgIsCTFMap( STRING( gpGlobals->mapname ) ) ) + { + AgString sGametype = CVAR_GET_STRING( "sv_ag_gametype" ); + if( sGametype != "ctf" && NULL == strstr( CVAR_GET_STRING( "sv_ag_gamemode" ), "ctf" ) ) + CVAR_SET_STRING( "sv_ag_gamemode","ctf" ); + } + + //Detect DOM maps. + if( AgIsDOMMap( STRING( gpGlobals->mapname ) ) ) + { + AgString sGametype = CVAR_GET_STRING( "sv_ag_gametype" ); + if( sGametype != "dom" ) + CVAR_SET_STRING( "sv_ag_gamemode", "dom" ); + } +#endif + + //Execute my rules just before allocating what class to use. + //This ensures that all is set correctly. Server.cfg can override my vars with no trouble. + GameMode.ExecConfig(); + + //Execute per map basis settings. + SERVER_COMMAND( UTIL_VarArgs( "exec %s.cfg\n", STRING( gpGlobals->mapname ) ) ); + SERVER_EXECUTE(); + +/* if( !gpGlobals->deathmatch ) { // generic half-life @@ -319,6 +361,8 @@ CGameRules *InstallGameRules( void ) return new CHalfLifeRules; } else +*/ +//-- Martin Webrant { if( teamplay.value > 0 ) { diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 6ad470d0..37f85153 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -15,6 +15,11 @@ //========================================================= // GameRules //========================================================= +//++ BulliT +#if !defined(_GAMERULES_H_) +#define _GAMERULES_H_ +#include "agglobal.h" +//-- Martin Webrant //#include "weapons.h" //#include "items.h" @@ -151,6 +156,9 @@ public: virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) {} virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; } +//++ BulliT + virtual void RecountTeams( void ) {}; +//-- Martin Webrant // Sounds virtual BOOL PlayTextureSounds( void ) { return TRUE; } virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ) { return TRUE; } @@ -162,8 +170,9 @@ public: virtual void EndMultiplayerGame( void ) {} }; +//++ BulliT extern CGameRules *InstallGameRules( void ); - +//-- Martin Webrant //========================================================= // CHalfLifeRules - rules for the single player Half-Life @@ -251,113 +260,11 @@ public: virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); }; -//========================================================= -// CHalfLifeMultiplay - rules for the basic half life multiplayer -// competition -//========================================================= -class CHalfLifeMultiplay : public CGameRules -{ -public: - CHalfLifeMultiplay(); - // GR_Think - virtual void Think( void ); - virtual void RefreshSkillData( void ); - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); - virtual BOOL FAllowFlashlight( void ); +//++ BulliT +#include "aggamerules.h" +extern AgGameRules *InstallGameRules( void ); +extern DLL_GLOBAL AgGameRules *g_pGameRules; +//-- Martin Webrant - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); - - // Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ); - virtual BOOL IsDeathmatch( void ); - virtual BOOL IsCoOp( void ); - - // Client connection/disconnection - // If ClientConnected returns FALSE, the connection is rejected and the user is provided the reason specified in - // svRejectReason - // Only the client's name and remote address are provided to the dll for verification. - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ); - virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ); - virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode - - // Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); - - // Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ); - virtual void PlayerThink( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); - virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer ); - - virtual BOOL AllowAutoTargetCrosshair( void ); - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); - - // Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - - // Weapon retrieval - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? - - // Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); - virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); - virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); - virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); - - // Item retrieval - virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); - virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); - - // Item spawn/respawn control - virtual int ItemShouldRespawn( CItem *pItem ); - virtual float FlItemRespawnTime( CItem *pItem ); - virtual Vector VecItemRespawnSpot( CItem *pItem ); - - // Ammo retrieval - virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); - - // Ammo spawn/respawn control - virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); - virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); - virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); - - // Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ); - virtual float FlHEVChargerRechargeTime( void ); - - // What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); - - // What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); - - // Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";} - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); - - virtual BOOL PlayTextureSounds( void ) { return FALSE; } - virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ); - - // Monsters - virtual BOOL FAllowMonsters( void ); - - // Immediately end a multiplayer game - virtual void EndMultiplayerGame( void ) { GoToIntermission(); } - -protected: - virtual void ChangeLevel( void ); - virtual void GoToIntermission( void ); - float m_flIntermissionEndTime; - BOOL m_iEndIntermissionButtonHit; - void SendMOTDToClient( edict_t *client ); -}; - -extern DLL_GLOBAL CGameRules *g_pGameRules; +#endif //_GAMERULES_H_ diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 14aac39b..538957e2 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -25,6 +25,11 @@ #include "shake.h" #include "gamerules.h" +//++ BulliT +#ifdef AGSTATS +#include "agstats.h" +#endif +//-- Martin Webrant #define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging #define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged @@ -141,6 +146,35 @@ void CGauss::Holster( int skiplocal /* = 0 */ ) void CGauss::PrimaryAttack() { +//++ BulliT + if( SGBOW == AgGametype() ) + { + PlayEmptySound(); + m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + return; + } + else if( INSTAGIB == AgGametype() ) + { + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 10 ) + { + PlayEmptySound(); + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; + return; + } + + m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + + m_fPrimaryFire = TRUE; + + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 10; + + StartFire(); + m_fInAttack = 0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; + return; + } +//-- Martin Webrant // don't fire underwater if( m_pPlayer->pev->waterlevel == 3 ) { @@ -392,6 +426,16 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) //ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); #ifndef CLIENT_DLL +//++ BulliT + if( INSTAGIB == AgGametype() ) + nMaxHits = 1; + if( SGBOW == AgGametype() ) + return; + +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif +//-- Martin Webrant while( flDamage > 10 && nMaxHits > 0 ) { nMaxHits--; @@ -418,11 +462,25 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) if( pEntity->pev->takedamage ) { ClearMultiDamage(); - pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET ); +//++ BulliT + //pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_ENERGYBEAM ); + if( pEntity == m_pPlayer && 0 < ag_gauss_fix.value ) + { + //Skip reflective gauss on the player that holds the gun. Americans that wanna fiddle around :P + } + else + { + pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_ENERGYBEAM ); + //pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET ); + } +//-- Martin Webrant ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); } - if( pEntity->ReflectGauss() ) +//++ BulliT + if( pEntity->ReflectGauss() && INSTAGIB != AgGametype() ) + //if( pEntity->ReflectGauss() ) +//-- Martin Webrant { float n; @@ -461,7 +519,10 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) fHasPunched = 1; // try punching through wall if secondary attack (primary is incapable of breaking through) - if( !m_fPrimaryFire ) +//++ BulliT + if( !m_fPrimaryFire && 0 < ag_wallgauss.value ) + //if( !m_fPrimaryFire ) +//-- Martin Webrant { UTIL_TraceLine( tr.vecEndPos + vecDir * 8, vecDest, dont_ignore_monsters, pentIgnore, &beam_tr ); if( !beam_tr.fAllSolid ) @@ -486,7 +547,10 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) if( g_pGameRules->IsMultiplayer() ) { - damage_radius = flDamage * 1.75; // Old code == 2.5 +//++ BulliT + //damage_radius = flDamage * 1.75; // Old code == 2.5 + damage_radius = flDamage * 1.75 * ag_wallgauss.value; // Old code == 2.5 +//-- Martin Webrant } else { diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index fdb7c645..11c88da6 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -47,6 +47,9 @@ public: int m_iJuice; int m_iOn; // 0 = off, 1 = startup, 2 = going float m_flSoundTime; +//++ BulliT + virtual void Reset(); +//-- Martin Webrant }; TYPEDESCRIPTION CRecharge::m_SaveData[] = @@ -116,7 +119,10 @@ void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use } // if the player doesn't have the suit, or there is no juice left, make the deny noise - if( ( m_iJuice <= 0 ) || ( !( pActivator->pev->weapons & ( 1 << WEAPON_SUIT ) ) ) ) +//++ BulliT + //if( ( m_iJuice <= 0 ) || ( !( pActivator->pev->weapons & ( 1 << WEAPON_SUIT ) ) ) ) + if( ( m_iJuice <= 0 ) || ( !( pActivator->pev->weapons & ( 1 <time ) { @@ -193,3 +199,11 @@ void CRecharge::Off( void ) else SetThink( &CBaseEntity::SUB_DoNothing ); } + +void CRecharge::Reset() +{ + m_iJuice = gSkillData.suitchargerCapacity; + pev->frame = 0; + pev->nextthink = pev->ltime; + Off(); +} diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index e1b22467..7518a989 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -115,6 +115,9 @@ public: int m_iJuice; int m_iOn; // 0 = off, 1 = startup, 2 = going float m_flSoundTime; +//++ BulliT + virtual void Reset(); +//-- Martin Webrant }; TYPEDESCRIPTION CWallHealth::m_SaveData[] = @@ -187,7 +190,8 @@ void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u } // if the player doesn't have the suit, or there is no juice left, make the deny noise - if( ( m_iJuice <= 0 ) || ( !( pActivator->pev->weapons & ( 1 << WEAPON_SUIT ) ) ) ) + //if( ( m_iJuice <= 0 ) || ( !( pActivator->pev->weapons & ( 1 << WEAPON_SUIT ) ) ) ) + if( ( m_iJuice <= 0 ) || ( !( pActivator->pev->weapons & ( 1<time ) { @@ -251,3 +255,11 @@ void CWallHealth::Off( void ) else SetThink( &CBaseEntity::SUB_DoNothing ); } + +void CWallHealth::Reset() +{ + m_iJuice = gSkillData.healthchargerCapacity; + pev->frame = 0; + pev->nextthink = pev->ltime; + Off(); +} diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index cc63d6db..f9ee56a1 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -24,6 +24,12 @@ #include "hornet.h" #include "gamerules.h" +//++ BulliT +#ifdef AGSTATS +#include "agstats.h" +#endif +//-- Martin Webrant + enum hgun_e { HGUN_IDLE1 = 0, @@ -49,6 +55,16 @@ BOOL CHgun::IsUseable( void ) void CHgun::Spawn() { +//++ BulliT +#ifndef CLIENT_DLL + if( SGBOW == AgGametype() ) + { + //Spawn shotgun instead. + CBaseEntity *pNewWeapon = CBaseEntity::Create( "weapon_shotgun", g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); + return; + } +#endif +//-- Martin Webrant Precache(); m_iId = WEAPON_HORNETGUN; SET_MODEL( ENT( pev ), "models/w_hgun.mdl" ); @@ -141,6 +157,12 @@ void CHgun::PrimaryAttack() #endif m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; +//++ BulliT +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif +//-- Martin Webrant + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; @@ -233,6 +255,12 @@ void CHgun::SecondaryAttack( void ) #endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_FAST, 0, 0, 0 ); +//++ BulliT +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif +//-- Martin Webrant + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; diff --git a/dlls/items.cpp b/dlls/items.cpp index d9cc7871..516da8c2 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -327,6 +327,9 @@ class CItemLongJump : public CItem MESSAGE_END(); EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A1" ); // Play the longjump sound UNDONE: Kelly? correct sound? +//++ BulliT + pPlayer->OnPickupLongjump(); +//-- Martin Webrant return TRUE; } return FALSE; diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index 7d05d5e1..3d422116 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -23,6 +23,12 @@ #include "soundent.h" #include "gamerules.h" +//++ BulliT +#ifdef AGSTATS +#include "agstats.h" +#endif +//-- Martin Webrant + enum mp5_e { MP5_LONGIDLE = 0, @@ -47,13 +53,28 @@ int CMP5::SecondaryAmmoIndex( void ) void CMP5::Spawn() { +//++ BulliT +#ifndef CLIENT_DLL + if( SGBOW == AgGametype() ) + { + //Spawn shotgun instead. + CBaseEntity *pNewWeapon = CBaseEntity::Create( "weapon_shotgun", g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); + return; + } +#endif +//-- Martin Webrant pev->classname = MAKE_STRING( "weapon_9mmAR" ); // hack to allow for old names Precache(); SET_MODEL( ENT( pev ), "models/w_9mmAR.mdl" ); m_iId = WEAPON_MP5; m_iDefaultAmmo = MP5_DEFAULT_GIVE; - +//++ BulliT +#ifndef CLIENT_DLL + if( ARENA == AgGametype() || ARCADE == AgGametype() || LMS == AgGametype() ) + m_iDefaultAmmo = MP5_MAX_CLIP; +#endif +//-- Martin Webrant FallInit();// get ready to fall down. } @@ -142,6 +163,9 @@ void CMP5::PrimaryAttack() m_iClip--; +#ifdef AGSTATS + Stats.FireShot( m_pPlayer,STRING( pev->classname ) ); +#endif m_pPlayer->pev->effects = (int)( m_pPlayer->pev->effects ) | EF_MUZZLEFLASH; // player "shoot" animation diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 929c2bf6..5634ffcd 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -31,7 +31,14 @@ #endif #include "hltv.h" -extern DLL_GLOBAL CGameRules *g_pGameRules; +//++ BulliT +#include "aggamerules.h" +#include "multi_gamerules.h" + +//extern DLL_GLOBAL CGameRules *g_pGameRules; +extern DLL_GLOBAL AgGameRules *g_pGameRules; +extern int gmsgAuthID; +//-- Martin Webrant extern DLL_GLOBAL BOOL g_fGameOver; extern int gmsgDeathMsg; // client dll messages extern int gmsgScoreInfo; @@ -56,6 +63,13 @@ public: { if( g_teamplay ) { +//++ BulliT + if( pListener->IsSpectator() && pTalker->IsSpectator() ) + return true; + + if( pListener->IsSpectator() || pTalker->IsSpectator() ) + return false; +//-- Martin Webrant if( g_pGameRules->PlayerRelationship( pListener, pTalker ) != GR_TEAMMATE ) { return false; @@ -79,7 +93,10 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() RefreshSkillData(); m_flIntermissionEndTime = 0; g_flIntermissionStartTime = 0; - + +//++ BulliT + m_iEndIntermissionButtonHit = 0; +//-- Martin Webrant // 11/8/98 // Modified by YWB: Server .cfg file is now a cvar, so that // server ops can run multiple game servers, with different server .cfg files, @@ -89,6 +106,8 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() // 3/31/99 // Added lservercfg file cvar, since listen and dedicated servers should not // share a single config file. (sjb) +//++ BulliT +/* if( IS_DEDICATED_SERVER() ) { // dedicated server @@ -117,6 +136,8 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() SERVER_COMMAND( szCommand ); } } +*/ +//-- Martin Webrant } BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) @@ -125,60 +146,20 @@ BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) if( g_VoiceGameMgr.ClientCommand( pPlayer, pcmd ) ) return TRUE; #endif - return CGameRules::ClientCommand( pPlayer, pcmd ); +//++ BulliT + //return CGameRules::ClientCommand( pPlayer, pcmd ); + return AgGameRules::ClientCommand( pPlayer, pcmd ); +//-- Martin Webrant } //========================================================= //========================================================= void CHalfLifeMultiplay::RefreshSkillData( void ) { - // load all default values - CGameRules::RefreshSkillData(); - - // override some values for multiplay. - - // suitcharger - gSkillData.suitchargerCapacity = 30; - - // Crowbar whack - gSkillData.plrDmgCrowbar = 25; - - // Glock Round - gSkillData.plrDmg9MM = 12; - - // 357 Round - gSkillData.plrDmg357 = 40; - - // MP5 Round - gSkillData.plrDmgMP5 = 12; - - // M203 grenade - gSkillData.plrDmgM203Grenade = 100; - - // Shotgun buckshot - gSkillData.plrDmgBuckshot = 20;// fewer pellets in deathmatch - - // Crossbow - gSkillData.plrDmgCrossbowClient = 20; - - // RPG - gSkillData.plrDmgRPG = 120; - - // Egon - gSkillData.plrDmgEgonWide = 20; - gSkillData.plrDmgEgonNarrow = 10; - - // Hand Grendade - gSkillData.plrDmgHandGrenade = 100; - - // Satchel Charge - gSkillData.plrDmgSatchel = 120; - - // Tripmine - gSkillData.plrDmgTripmine = 150; - - // hornet - gSkillData.plrDmgHornet = 10; +//++ BulliT + AgGameRules::RefreshSkillData(); + return; +//-- Martin Webrant } // longest the intermission can last, in seconds @@ -196,6 +177,10 @@ void CHalfLifeMultiplay::Think( void ) g_VoiceGameMgr.Update( gpGlobals->frametime ); #endif +//++ BulliT + if( !AgGameRules::AgThink() ) + return; +//-- Martin Webrant ///// Check game rules ///// static int last_frags; static int last_time; @@ -219,12 +204,19 @@ void CHalfLifeMultiplay::Think( void ) { if( m_iEndIntermissionButtonHit // check that someone has pressed a key, or the max intermission time is over || ( ( g_flIntermissionStartTime + MAX_INTERMISSION_TIME ) < gpGlobals->time ) ) - ChangeLevel(); // intermission is over + //ChangeLevel(); // intermission is over +//++ BulliT + { + ChangeNextLevel(); + } +//-- Martin Webrant } return; } +//++ BulliT +/* float flTimeLimit = timelimit.value * 60; float flFragLimit = fraglimit.value; @@ -235,6 +227,24 @@ void CHalfLifeMultiplay::Think( void ) GoToIntermission(); return; } +*/ + + if( !m_Timer.TimeRemaining( time_remaining ) ) + { + if( !m_SuddenDeath.IsSuddenDeath() ) + { + //Go intermission. + GoToIntermission(); + return; + } + else + { + //Sudden death! + time_remaining = 0; + } + } + float flFragLimit = fraglimit.value; +//-- Martin Webrant if( flFragLimit ) { @@ -305,96 +315,16 @@ BOOL CHalfLifeMultiplay::IsCoOp( void ) //========================================================= BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) { - if( !pWeapon->CanDeploy() ) - { - // that weapon can't deploy anyway. - return FALSE; - } - - if( !pPlayer->m_pActiveItem ) - { - // player doesn't have an active item! - return TRUE; - } - - if( !pPlayer->m_pActiveItem->CanHolster() ) - { - // can't put away the active item. - return FALSE; - } - - if( pWeapon->iWeight() > pPlayer->m_pActiveItem->iWeight() ) - { - return TRUE; - } - - return FALSE; +//++ BulliT + return AgGameRules::FShouldSwitchWeapon( pPlayer, pWeapon ); +//-- Martin Webrant } BOOL CHalfLifeMultiplay::GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { - CBasePlayerItem *pCheck; - CBasePlayerItem *pBest;// this will be used in the event that we don't find a weapon in the same category. - int iBestWeight; - int i; - - iBestWeight = -1;// no weapon lower than -1 can be autoswitched to - pBest = NULL; - - if( !pCurrentWeapon->CanHolster() ) - { - // can't put this gun away right now, so can't switch. - return FALSE; - } - - for( i = 0; i < MAX_ITEM_TYPES; i++ ) - { - pCheck = pPlayer->m_rgpPlayerItems[i]; - - while( pCheck ) - { - if( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) - { - // this weapon is from the same category. - if ( pCheck->CanDeploy() ) - { - if ( pPlayer->SwitchWeapon( pCheck ) ) - { - return TRUE; - } - } - } - else if( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of - { - //ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) ); - // we keep updating the 'best' weapon just in case we can't find a weapon of the same weight - // that the player was using. This will end up leaving the player with his heaviest-weighted - // weapon. - if( pCheck->CanDeploy() ) - { - // if this weapon is useable, flag it as the best - iBestWeight = pCheck->iWeight(); - pBest = pCheck; - } - } - - pCheck = pCheck->m_pNext; - } - } - - // if we make it here, we've checked all the weapons and found no useable - // weapon in the same catagory as the current weapon. - - // if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always - // at least get the crowbar, but ya never know. - if( !pBest ) - { - return FALSE; - } - - pPlayer->SwitchWeapon( pBest ); - - return TRUE; +//++ BulliT + return AgGameRules::GetNextBestWeapon( pPlayer, pCurrentWeapon ); +//-- Martin Webrant } //========================================================= @@ -404,7 +334,7 @@ BOOL CHalfLifeMultiplay::ClientConnected( edict_t *pEntity, const char *pszName, #ifndef NO_VOICEGAMEMGR g_VoiceGameMgr.ClientConnected( pEntity ); #endif - return TRUE; + return AgGameRules::ClientConnected( pEntity, pszName, pszAddress, szRejectReason ); } extern int gmsgSayText; @@ -419,6 +349,9 @@ void CHalfLifeMultiplay::UpdateGameMode( CBasePlayer *pPlayer ) void CHalfLifeMultiplay::InitHUD( CBasePlayer *pl ) { +//++ BulliT + AgGameRules::InitHUD( pl ); +//-- Martin Webrant // notify other clients of player joining the game UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s has joined the game\n", ( pl->pev->netname && STRING( pl->pev->netname )[0] != 0 ) ? STRING( pl->pev->netname ) : "unconnected" ) ); @@ -470,6 +403,19 @@ void CHalfLifeMultiplay::InitHUD( CBasePlayer *pl ) WRITE_SHORT( 0 ); WRITE_SHORT( GetTeamIndex( plr->m_szTeamName ) + 1 ); MESSAGE_END(); +//++ BulliT + MESSAGE_BEGIN( MSG_ONE, gmsgSpectator, NULL, pl->edict() ); + WRITE_BYTE( ENTINDEX( plr->edict() ) ); + WRITE_BYTE( plr->IsSpectator() ? 1 : 0 ); + MESSAGE_END(); + +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_ONE, gmsgAuthID, NULL, pl->edict() ); + WRITE_BYTE( plr->entindex() ); + WRITE_STRING( plr->GetAuthID() ); + MESSAGE_END(); +#endif +//-- Martin Webrant } } @@ -484,6 +430,9 @@ void CHalfLifeMultiplay::InitHUD( CBasePlayer *pl ) //========================================================= void CHalfLifeMultiplay::ClientDisconnected( edict_t *pClient ) { +//++ BulliT + AgGameRules::ClientDisconnected( pClient ); +//-- Martin Webrant if( pClient ) { CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); @@ -540,7 +489,10 @@ float CHalfLifeMultiplay::FlPlayerFallDamage( CBasePlayer *pPlayer ) //========================================================= BOOL CHalfLifeMultiplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) { - return TRUE; +//++ BulliT + return AgGameRules::FPlayerCanTakeDamage( pPlayer, pAttacker ); + //return TRUE; +//-- Martin Webrant } //========================================================= @@ -564,32 +516,20 @@ void CHalfLifeMultiplay::PlayerThink( CBasePlayer *pPlayer ) //========================================================= void CHalfLifeMultiplay::PlayerSpawn( CBasePlayer *pPlayer ) { - BOOL addDefault; - CBaseEntity *pWeaponEntity = NULL; - - pPlayer->pev->weapons |= ( 1 << WEAPON_SUIT ); - - addDefault = TRUE; - - while( ( pWeaponEntity = UTIL_FindEntityByClassname( pWeaponEntity, "game_player_equip" ) ) ) - { - pWeaponEntity->Touch( pPlayer ); - addDefault = FALSE; - } - - if( addDefault ) - { - pPlayer->GiveNamedItem( "weapon_crowbar" ); - pPlayer->GiveNamedItem( "weapon_9mmhandgun" ); - pPlayer->GiveAmmo( 68, "9mm", _9MM_MAX_CARRY );// 4 full reloads - } +//++ BulliT + AgGameRules::PlayerSpawn( pPlayer ); + return; +//-- Martin Webrant } //========================================================= //========================================================= BOOL CHalfLifeMultiplay::FPlayerCanRespawn( CBasePlayer *pPlayer ) { - return TRUE; +//++ BulliT + return AgGameRules::FPlayerCanRespawn( pPlayer ); + //return TRUE; +//-- Martin Webrant } //========================================================= @@ -610,6 +550,9 @@ BOOL CHalfLifeMultiplay::AllowAutoTargetCrosshair( void ) //========================================================= int CHalfLifeMultiplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) { +//++ BulliT + AgGameRules::IPointsForKill( pAttacker, pKilled ); +//-- Martin Webrant return 1; } @@ -643,7 +586,11 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, else { // killed by the world - pKiller->frags -= 1; +//++ BulliT + //pKiller->frags -= 1; + if( pVictim->pev ) + pVictim->pev->frags -= 1; +//-- Martin Webrant } // update the scores @@ -652,8 +599,10 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, WRITE_BYTE( ENTINDEX(pVictim->edict()) ); WRITE_SHORT( pVictim->pev->frags ); WRITE_SHORT( pVictim->m_iDeaths ); - WRITE_SHORT( 0 ); +//++ BulliT + WRITE_SHORT( g_teamplay ); WRITE_SHORT( GetTeamIndex( pVictim->m_szTeamName ) + 1 ); +//-- Martin Webrant MESSAGE_END(); // killers score, if it's a player @@ -666,8 +615,10 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, WRITE_BYTE( ENTINDEX( PK->edict() ) ); WRITE_SHORT( PK->pev->frags ); WRITE_SHORT( PK->m_iDeaths ); - WRITE_SHORT( 0 ); +//++ BulliT + WRITE_SHORT( g_teamplay ); WRITE_SHORT( GetTeamIndex( PK->m_szTeamName ) + 1 ); +//-- Martin Webrant MESSAGE_END(); // let the killer paint another decal as soon as he'd like. @@ -679,6 +630,9 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, DeactivateSatchels( pVictim ); } #endif +//++ BulliT + AgGameRules::PlayerKilled( pVictim, pKiller, pInflictor ); +//-- Martin Webrant } //========================================================= @@ -686,6 +640,9 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, //========================================================= void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) { +//++ BulliT + AgGameRules::DeathNotice( pVictim, pKiller, pevInflictor ); +//-- Martin Webrant // Work out what killed the player, and send a message to all clients about it CBaseEntity *Killer = CBaseEntity::Instance( pKiller ); @@ -822,6 +779,9 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, } } +//++ BulliT + UTIL_SendDirectorMessage( pVictim->edict(), pevInflictor ? ENT( pevInflictor ) : ENT( pKiller ), 7 | DRC_FLAG_DRAMATIC ); +/* MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); WRITE_BYTE( 9 ); // command length in bytes WRITE_BYTE( DRC_CMD_EVENT ); // player killed @@ -832,7 +792,8 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, WRITE_SHORT( ENTINDEX( ENT( pKiller ) ) ); // index number of secondary entity WRITE_LONG( 7 | DRC_FLAG_DRAMATIC ); // eventflags (priority and flags) MESSAGE_END(); - +*/ +//-- Martin Webrant // Print a standard message // TODO: make this go direct to console return; // just remove for now @@ -964,7 +925,9 @@ BOOL CHalfLifeMultiplay::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerIte if( weaponstay.value > 0 ) { if( pItem->iFlags() & ITEM_FLAG_LIMITINWORLD ) - return CGameRules::CanHavePlayerItem( pPlayer, pItem ); +//++ BulliT + return AgGameRules::CanHavePlayerItem( pPlayer, pItem ); +//-- Martin Webrant // check if the player already has this weapon for( int i = 0; i < MAX_ITEM_TYPES; i++ ) @@ -983,14 +946,18 @@ BOOL CHalfLifeMultiplay::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerIte } } - return CGameRules::CanHavePlayerItem( pPlayer, pItem ); +//++ BulliT + return AgGameRules::CanHavePlayerItem( pPlayer, pItem ); +//-- Martin Webrant } //========================================================= //========================================================= BOOL CHalfLifeMultiplay::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) { - return TRUE; +//++ BulliT + return AgGameRules::CanHaveItem( pPlayer, pItem ); +//-- Martin Webrant } //========================================================= @@ -1038,10 +1005,13 @@ void CHalfLifeMultiplay::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int //========================================================= BOOL CHalfLifeMultiplay::IsAllowedToSpawn( CBaseEntity *pEntity ) { +//++ BulliT + return AgGameRules::IsAllowedToSpawn( pEntity ); +//-- Martin Webrant // if( pEntity->pev->flags & FL_MONSTER ) // return FALSE; - return TRUE; +// return TRUE; } //========================================================= @@ -1086,14 +1056,18 @@ float CHalfLifeMultiplay::FlHEVChargerRechargeTime( void ) //========================================================= int CHalfLifeMultiplay::DeadPlayerWeapons( CBasePlayer *pPlayer ) { - return GR_PLR_DROP_GUN_ACTIVE; +//++ BulliT + return AgGameRules::DeadPlayerWeapons( pPlayer ); +//-- Martin Webrant } //========================================================= //========================================================= int CHalfLifeMultiplay::DeadPlayerAmmo( CBasePlayer *pPlayer ) { - return GR_PLR_DROP_AMMO_ACTIVE; +//++ BulliT + return AgGameRules::DeadPlayerAmmo( pPlayer ); +//-- Martin Webrant } edict_t *CHalfLifeMultiplay::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) @@ -1147,6 +1121,10 @@ void CHalfLifeMultiplay::GoToIntermission( void ) if( g_fGameOver ) return; // intermission has already been triggered, so ignore. +//++ BulliT + AgGameRules::GoToIntermission(); +//-- Martin Webrant + MESSAGE_BEGIN( MSG_ALL, SVC_INTERMISSION ); MESSAGE_END(); diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index a97b6a80..d0bc641d 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -23,6 +23,9 @@ #include "nodes.h" #include "animation.h" #include "doors.h" +//++ BulliT +#include "agglobal.h" +//-- Martin Webrant #define HULL_STEP_SIZE 16// how far the test hull moves on each step #define NODE_HEIGHT 8 // how high to lift nodes off the ground after we drop them all (make stair/ramp mapping easier) @@ -1699,7 +1702,9 @@ void CTestHull::BuildNodeGraph( void ) } // make sure directories have been made - GET_GAME_DIR( szNrpFilename ); +//++ BulliT + strcpy( szNrpFilename, AgGetDirectoryValve() ); +//-- Martin Webrant strcat( szNrpFilename, "/maps" ); CreateDirectory( szNrpFilename, NULL ); strcat( szNrpFilename, "/graphs" ); @@ -2368,7 +2373,9 @@ int CGraph::FLoadGraph( char *szMapName ) // make sure the directories have been made char szDirName[MAX_PATH]; - GET_GAME_DIR( szDirName ); +//++ BulliT + strcpy( szDirName, AgGetDirectoryValve() ); +//-- Martin Webrant strcat( szDirName, "/maps" ); CreateDirectory( szDirName, NULL ); strcat( szDirName, "/graphs" ); @@ -2551,7 +2558,9 @@ int CGraph::FSaveGraph( char *szMapName ) } // make sure directories have been made - GET_GAME_DIR( szFilename ); +//++ BulliT + strcpy( szFilename, AgGetDirectoryValve() ); +//-- Martin Webrant strcat( szFilename, "/maps" ); CreateDirectory( szFilename, NULL ); strcat( szFilename, "/graphs" ); diff --git a/dlls/player.cpp b/dlls/player.cpp index 2f097072..1baf7443 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -183,6 +183,40 @@ int gmsgTeamNames = 0; int gmsgStatusText = 0; int gmsgStatusValue = 0; +//++ BulliT +int gmsgAllowSpec = 0; +int gmsgSpectator = 0; +int gmsgVGUIMenu = 0; +int gmsgCheatCheck = 0; +int gmsgSplash = 0; +int gmsgCountdown = 0; +int gmsgTimer = 0; +int gmsgPlayerId = 0; +int gmsgSettings = 0; +int gmsgSuddenDeath = 0; +int gmsgLongjump = 0; +int gmsgTimeout = 0; +int gmsgPlaySound = 0; +int gmsgVote = 0; +int gmsgNextmap = 0; +int gmsgInitLoc = 0; +int gmsgLocation = 0; +int gmsgWallhack = 0; +int gmsgSpikeCheck = 0; +int gmsgGametype = 0; +int gmsgStatusIcon = 0; +int gmsgCTF = 0; +int gmsgAuthID = 0; +int gmsgCTFSound = 0; +int gmsgMapList = 0; +int gmsgCTFFlag = 0; +int gmsgCRC32 = 0; + +extern int g_teamplay; +#ifdef AGSTATS +#include "agstats.h" +#endif +//-- Martin Webrant void LinkUserMessages( void ) { @@ -209,7 +243,9 @@ void LinkUserMessages( void ) gmsgInitHUD = REG_USER_MSG( "InitHUD", 0 ); // called every time a new player joins the server gmsgShowGameTitle = REG_USER_MSG( "GameTitle", 1 ); gmsgDeathMsg = REG_USER_MSG( "DeathMsg", -1 ); - gmsgScoreInfo = REG_USER_MSG( "ScoreInfo", 9 ); +//++ BulliT + //gmsgScoreInfo = REG_USER_MSG( "ScoreInfo", 9 ); +//-- Martin Webrant gmsgTeamInfo = REG_USER_MSG( "TeamInfo", -1 ); // sets the name of a player's team gmsgTeamScore = REG_USER_MSG( "TeamScore", -1 ); // sets the score of a team on the scoreboard gmsgGameMode = REG_USER_MSG( "GameMode", 1 ); @@ -228,6 +264,40 @@ void LinkUserMessages( void ) gmsgStatusText = REG_USER_MSG( "StatusText", -1 ); gmsgStatusValue = REG_USER_MSG( "StatusValue", 3 ); +//++ BulliT + gmsgScoreInfo = REG_USER_MSG( "ScoreInfo", 9 ); + gmsgAllowSpec = REG_USER_MSG( "AllowSpec", 1 ); //Allow spectator button message. + gmsgSpectator = REG_USER_MSG( "Spectator", 2 ); //Spectator message. + gmsgVGUIMenu = REG_USER_MSG( "VGUIMenu", 1 ); //VGUI menu. + gmsgCheatCheck = REG_USER_MSG( "CheatCheck", 1 ); //Spike check. + gmsgSplash = REG_USER_MSG( "Splash", 1 ); //Splash screen. + gmsgCountdown = REG_USER_MSG( "Countdown", -1 ); //Show countdown timer and play sound. + gmsgTimer = REG_USER_MSG( "Timer", 8 ); //Timer. Sends timelimit, effective time. + gmsgPlayerId = REG_USER_MSG( "PlayerId", 6 ); //Sends playerid,team,health,armour. + gmsgSettings = REG_USER_MSG( "Settings", -1 ); //Sends settings. + gmsgSuddenDeath = REG_USER_MSG( "SuddenDeath", 1 ); //Display sudden death if 1. + gmsgLongjump = REG_USER_MSG( "Longjump", 1 ); //Longjump timer. + gmsgTimeout = REG_USER_MSG( "Timeout", 2 ); //Timeout is called. + gmsgPlaySound = REG_USER_MSG( "PlaySound", -1 ); //Play a sound. + gmsgNextmap = REG_USER_MSG( "Nextmap", -1 ); //Send next map. + gmsgVote = REG_USER_MSG( "Vote", -1 ); //Vote is running. + gmsgInitLoc = REG_USER_MSG( "InitLoc", -1 ); //Init location files for this map. + gmsgLocation = REG_USER_MSG( "Location", 7 ); //Send a players position. + gmsgWallhack = REG_USER_MSG( "WhString", -1 ); //Init wallhack data. + gmsgSpikeCheck = REG_USER_MSG( "SpikeCheck", -1 ); //Check a model for spikes. + gmsgGametype = REG_USER_MSG( "Gametype", 1 ); //The gametype. + gmsgStatusIcon = REG_USER_MSG( "StatusIcon", -1 ); //Generic status icon + gmsgCTF = REG_USER_MSG( "CTF", 2); //CTF status + gmsgAuthID = REG_USER_MSG( "AuthID", -1 ); //Auth ID + gmsgCTFSound = REG_USER_MSG( "CTFSound", 1 ); //CTF Sound + gmsgMapList = REG_USER_MSG( "MapList", -1 ); //MapList + gmsgCTFFlag = REG_USER_MSG( "CTFFlag", 2 ); //Who is carrying the flags. + gmsgCRC32 = REG_USER_MSG( "CRC32", -1 ); //Checksum, file +//-- Martin Webrant +#ifdef AG_NO_CLIENT_DLL + gmsgStatusText = REG_USER_MSG( "StatusText", -1 ); + gmsgStatusValue = REG_USER_MSG( "StatusValue", 3 ); +#endif } LINK_ENTITY_TO_CLASS( player, CBasePlayer ) @@ -408,6 +478,10 @@ void CBasePlayer::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage );// a little surface blood. TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); + +#ifdef AGSTATS + Stats.FireHit( this, flDamage, pevAttacker ); +#endif } } @@ -493,6 +567,9 @@ int CBasePlayer::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, fl m_rgbTimeBasedDamage[i] = 0; } +//++ BulliT + UTIL_SendDirectorMessage( this->edict(), ENT( pevInflictor ), 5 | DRC_FLAG_DRAMATIC ); +/* // tell director about it MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); WRITE_BYTE( 9 ); // command length in bytes @@ -501,7 +578,8 @@ int CBasePlayer::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, fl WRITE_SHORT( ENTINDEX( ENT( pevInflictor ) ) ); // index number of secondary entity WRITE_LONG( 5 ); // eventflags (priority and flags) MESSAGE_END(); - +*/ +//-- Martin Webrant // how bad is it, doc? ftrivial = ( pev->health > 75 || m_lastDamageAmount < 5 ); fmajor = ( m_lastDamageAmount > 25 ); @@ -831,6 +909,10 @@ entvars_t *g_pevLastInflictor; // Set in combat.cpp. Used to pass the damage i void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) { +//++ BulliT + if( pev ) + m_vKilled = pev->origin; +//-- Martin Webrant CSound *pSound; // Holster weapon immediately, to allow it to cleanup @@ -895,7 +977,10 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) if( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) { pev->solid = SOLID_NOT; - GibMonster(); // This clears pev->model +//++ BulliT + if( 0 < ag_show_gibs.value ) + GibMonster(); // This clears pev->model +//-- Martin Webrant pev->effects |= EF_NODRAW; return; } @@ -1271,6 +1356,13 @@ void CBasePlayer::PlayerDeathThink( void ) pev->effects |= EF_NOINTERP; pev->framerate = 0.0; + //++ BulliT + //Remove sticky dead models. + pev->solid = SOLID_NOT; + if( Spectate_Think() ) + return; + //-- Martin Webrant + BOOL fAnyButtonDown = ( pev->button & ~IN_SCORE ); // wait for all buttons released @@ -1293,13 +1385,18 @@ void CBasePlayer::PlayerDeathThink( void ) // choose to respawn. if( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > ( m_fDeadTime + 6 ) ) && !( m_afPhysicsFlags & PFLAG_OBSERVER ) ) { - // go to dead camera. - StartDeathCam(); +//++ BulliT + m_fDisplayGamemode = gpGlobals->time + 1; + // go to dead camera. + //StartDeathCam(); +//-- Martin Webrant } - // wait for any button down, or mp_forcerespawn is set and the respawn time is up - if( !fAnyButtonDown && !( g_pGameRules->IsMultiplayer() && forcerespawn.value > 0 && ( gpGlobals->time > ( m_fDeadTime + 5 ) ) ) ) - return; +//++ BulliT + //Don't trigg on any button - just attack button. + if( !( pev->button & IN_ATTACK || pev->button & IN_USE ) && !( g_pGameRules->IsMultiplayer() && CVAR_GET_FLOAT( "mp_forcerespawn" ) > 0 && ( gpGlobals->time > ( m_fDeadTime + 5 ) ) ) ) + return; +//-- Martin Webrant pev->button = 0; m_iRespawnFrames = 0; @@ -1591,8 +1688,10 @@ void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) WRITE_BYTE( ENTINDEX( edict() ) ); WRITE_SHORT( pev->frags ); WRITE_SHORT( m_iDeaths ); - WRITE_SHORT( 0 ); +//++ BulliT + WRITE_SHORT( g_teamplay ); WRITE_SHORT( g_pGameRules->GetTeamIndex( m_szTeamName ) + 1 ); +//-- Martin Webrant MESSAGE_END(); } @@ -1643,7 +1742,8 @@ void CBasePlayer::UpdateStatusBar() { CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if( pEntity->Classify() == CLASS_PLAYER ) + //if( pEntity->Classify() == CLASS_PLAYER ) + if( pEntity->Classify() == CLASS_PLAYER && !( m_hSpectateTarget != NULL && ENTINDEX( m_hSpectateTarget->edict() ) == pEntity->entindex() ) ) { newSBarState[SBAR_ID_TARGETNAME] = ENTINDEX( pEntity->edict() ); strcpy( sbuf1, "1 %p1\n2 Health: %i2%%\n3 Armor: %i3%%" ); @@ -1730,6 +1830,50 @@ void CBasePlayer::PreThink( void ) if( g_fGameOver ) return; // intermission or finale +//++ BulliT + if( IsSpectator() || ARENA == AgGametype() || LMS == AgGametype() ) + EnableControl( TRUE ); + else + EnableControl( !g_bPaused ); + + if( m_fDisplayGamemode > 0 && m_fDisplayGamemode < gpGlobals->time ) + { +#ifdef AG_NO_CLIENT_DLL + //Print gameinfo text. + AgSay( this, "www.planethalflife.com/agmod", NULL, 10, 0.03, 0.10, 2 ); + if( 0 < ag_match_running.value ) + AgSay( this, "Match is on!", NULL, 8, 0.03, 0.15, 5 ); + + //Print gamemode text. + AgSay( this, AgGamename().c_str(), NULL, 6, 0.75, 0.10, 3 ); + + //Print settings. + char szSetting[256]; + sprintf( szSetting, "TL = %d\nFL = %d\nFF = %d\nWS = %d\nWG = %s\n", + (int)CVAR_GET_FLOAT( "mp_timelimit" ), + (int)CVAR_GET_FLOAT( "mp_fraglimit" ), + (int)CVAR_GET_FLOAT( "mp_friendlyfire" ), + (int)CVAR_GET_FLOAT( "mp_weaponstay" ), + CVAR_GET_STRING( "sv_ag_wallgauss" ) ); + + AgSay( this, szSetting, NULL, 6, 0.75, 0.15, 4 ); +#else + MESSAGE_BEGIN( MSG_ONE_UNRELIABLE, gmsgSettings, NULL, pev ); + WRITE_BYTE( (int)ag_match_running.value ); + WRITE_STRING( AgGamename().c_str() ); + WRITE_BYTE( (int)CVAR_GET_FLOAT( "mp_timelimit" ) ); + WRITE_BYTE( (int)CVAR_GET_FLOAT( "mp_fraglimit" ) ); + WRITE_BYTE( (int)CVAR_GET_FLOAT( "mp_friendlyfire" ) ); + WRITE_BYTE( (int)CVAR_GET_FLOAT( "mp_weaponstay" ) ); + WRITE_STRING( CVAR_GET_STRING( "sv_ag_version" ) ); + WRITE_STRING( CVAR_GET_STRING( "sv_ag_wallgauss" ) ); + WRITE_STRING( CVAR_GET_STRING( "sv_ag_headshot" ) ); + WRITE_STRING( CVAR_GET_STRING( "sv_ag_blastradius" ) ); + MESSAGE_END(); +#endif + m_fDisplayGamemode = 0; + } +//-- Martin Webrant UTIL_MakeVectors( pev->v_angle ); // is this still used? ItemPreFrame(); @@ -2494,11 +2638,36 @@ void CBasePlayer::PostThink() CheckPowerups( pev ); UpdatePlayerSound(); +//++ BulliT + // Track button info so we can detect 'pressed' and 'released' buttons next frame + //m_afButtonLast = pev->button; + //Remove observe mode if using attack or use. + if( ( pev->button & IN_ATTACK ) && ( pev->effects == EF_NODRAW ) || ( pev->button & IN_USE ) && ( pev->effects == EF_NODRAW ) ) + { + if( DEAD_NO == pev->deadflag || DEAD_RESPAWNABLE == pev->deadflag) + { + pev->button = 0; + m_iRespawnFrames = 0; + pev->effects &= ~EF_NODRAW; + pev->takedamage = DAMAGE_YES; + pev->flags &= ~FL_SPECTATOR; + pev->movetype = MOVETYPE_WALK; + + Spawn(); + } + } + else + { + if( 0 < ag_lj_timer.value ) + LongjumpThink(); + } +//-- Martin Webrant +pt_end: +//++ BulliT // Track button info so we can detect 'pressed' and 'released' buttons next frame m_afButtonLast = pev->button; - -pt_end: +//-- Martin Webrant #if defined( CLIENT_WEAPONS ) // Decay timers on weapons // go through all of the weapons and make a list of the ones to pack @@ -2597,8 +2766,17 @@ Returns the entity to spawn at USES AND SETS GLOBAL g_pLastSpawn ============ */ +//++ BulliT +edict_t *EntSelectCTFSpawnPoint( CBaseEntity *pPlayer ); +//-- Martin Webrant edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ) { +//++ BulliT + if( CTF == AgGametype() ) + { + return EntSelectCTFSpawnPoint( pPlayer ); + } +//-- Martin Webrant CBaseEntity *pSpot; edict_t *player; @@ -2694,7 +2872,10 @@ void CBasePlayer::Spawn( void ) pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_WALK; pev->max_health = pev->health; - pev->flags &= FL_PROXY; // keep proxy flag sey by engine +//++ BulliT + //pev->flags &= FL_PROXY; // keep proxy flag sey by engine + pev->flags &= FL_PROXY | FL_FAKECLIENT; // keep proxy flag sey by engine +//-- Martin Webrant pev->flags |= FL_CLIENT; pev->air_finished = gpGlobals->time + 12; pev->dmg = 2; // initial water damage @@ -2711,7 +2892,11 @@ void CBasePlayer::Spawn( void ) g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - +//++ BulliT + g_engfuncs.pfnSetPhysicsKeyValue( edict(), "bj", CVAR_GET_STRING( "sv_ag_oldphysics" ) ); + m_fPlayerIdCheck = gpGlobals->time + 2; + m_fLongjumpTimer = gpGlobals->time; +//-- Martin Webrant pev->fov = m_iFOV = 0;// init field of view. m_iClientFOV = -1; // make sure fov reset is sent @@ -2773,9 +2958,25 @@ void CBasePlayer::Spawn( void ) m_lastx = m_lasty = 0; - m_flNextChatTime = gpGlobals->time; +//++ BulliT + if( IsProxy() ) + { + pev->effects |= EF_NODRAW; + pev->solid = SOLID_NOT; + pev->deadflag = DEAD_DEAD; - g_pGameRules->PlayerSpawn( this ); + //Move proxy to info intermission spot + edict_t *pSpot = g_pGameRules->m_InfoInterMission.GetRandomSpot(); + ASSERT( NULL != pSpot ); + if( pSpot ) + MoveToInfoIntermission( pSpot ); + } + else + { + g_pGameRules->PlayerSpawn( this ); + Spectate_UpdatePosition(); + } +//-- Martin Webrant } void CBasePlayer::Precache( void ) @@ -3046,6 +3247,11 @@ const char *CBasePlayer::TeamID( void ) if( pev == NULL ) // Not fully connected yet return ""; +//++ BulliT + if( IsSpectator() && ( LMS != AgGametype() || LMS == AgGametype() && !m_bReady ) ) + return ""; +//-- Martin Webrant + // return their team name return m_szTeamName; } @@ -3233,6 +3439,74 @@ void CBasePlayer::ForceClientDllUpdate( void ) m_fKnownItem = FALSE; // Force weaponinit messages. m_fInitHUD = TRUE; // Force HUD gmsgResetHUD message +//++ BulliT + m_bInitLocation = true; + m_iFlagStatus1Last = -1; + m_iFlagStatus2Last = -1; + +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_ONE, gmsgGametype, NULL, edict() ); + WRITE_BYTE( AgGametype()); + MESSAGE_END(); + if( CTF == AgGametype() ) + g_pGameRules->m_CTF.SendCaptures( this ); +#endif + + //Gamemode + g_pGameRules->UpdateGameMode(this); + + //Teams + if( g_pGameRules->IsTeamplay() ) + { + for( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *plr = AgPlayerByIndex( i ); + if( plr ) + { + //Team + if( plr && g_pGameRules->IsValidTeam( plr->TeamID() ) ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgTeamInfo, NULL, edict() ); + WRITE_BYTE( plr->entindex() ); + WRITE_STRING( plr->TeamID() ); + MESSAGE_END(); + } + } + } + } + + for( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer* plr = AgPlayerByIndex( i ); + if( plr ) + { + /* skip scoreboard, it will update itself. + //Score + MESSAGE_BEGIN( MSG_ONE, gmsgScoreInfo, NULL, edict() ); + WRITE_BYTE(ENTINDEX(plr->edict())); + WRITE_SHORT( plr->pev->frags ); + WRITE_SHORT( m_iDeaths ); +//++ BulliT + WRITE_SHORT( g_teamplay ); + WRITE_SHORT( g_pGameRules->GetTeamIndex( plr->m_szTeamName ) + 1 ); +//-- Martin Webrant + MESSAGE_END(); + */ + + MESSAGE_BEGIN( MSG_ONE, gmsgSpectator, NULL, edict() ); + WRITE_BYTE( ENTINDEX(plr->edict() ) ); + WRITE_BYTE( plr->IsSpectator() ? 1 : 0 ); + MESSAGE_END(); + +#ifndef AG_NO_CLIENT_DLL + MESSAGE_BEGIN( MSG_ONE, gmsgAuthID, NULL, edict() ); + WRITE_BYTE( plr->entindex() ); + WRITE_STRING( plr->GetAuthID() ); + MESSAGE_END(); +#endif + } + } +//-- Martin Webrant // Now force all the necessary messages // to be sent. UpdateClientData(); @@ -3310,7 +3584,7 @@ void CBasePlayer::ImpulseCommands() break; default: // check all of the cheat impulse commands now - CheatImpulseCommands( iImpulse ); + //CheatImpulseCommands( iImpulse ); break; } @@ -3321,6 +3595,9 @@ void CBasePlayer::ImpulseCommands() //========================================================= void CBasePlayer::CheatImpulseCommands( int iImpulse ) { +//++ BulliT + return; +/* #if !defined( HLDEMO_BUILD ) if( g_flWeaponCheat == 0.0 ) { @@ -3489,6 +3766,8 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) break; } #endif // HLDEMO_BUILD +*/ +//-- Martin Webrant } // @@ -3764,7 +4043,22 @@ void CBasePlayer::UpdateClientData( void ) { MESSAGE_BEGIN( MSG_ONE, gmsgInitHUD, NULL, pev ); MESSAGE_END(); +//++ BulliT + SendWallhackInfo(); + if( 0 < ag_match_running.value ) + g_pGameRules->m_ScoreCache.RestoreScore( this ); + g_pGameRules->m_ScoreCache.UpdateScore( this ); + + MESSAGE_BEGIN( MSG_ALL, gmsgSpectator ); + WRITE_BYTE( ENTINDEX( edict() ) ); + WRITE_BYTE( 0 ); + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_ONE, gmsgAllowSpec, NULL, pev ); + WRITE_BYTE( 1 ); + MESSAGE_END(); +//-- Martin Webrant g_pGameRules->InitHUD( this ); m_fGameHUDInitialized = TRUE; if( g_pGameRules->IsMultiplayer() ) @@ -3774,8 +4068,9 @@ void CBasePlayer::UpdateClientData( void ) } FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 ); - +#ifdef AG_NO_CLIENT_DLL InitStatusBar(); +#endif } if( m_iHideHUD != m_iClientHideHUD ) @@ -3787,15 +4082,50 @@ void CBasePlayer::UpdateClientData( void ) m_iClientHideHUD = m_iHideHUD; } - if( m_iFOV != m_iClientFOV ) +//++ BulliT + CBasePlayer* pPlayerTarget = NULL; + if( m_hSpectateTarget != NULL && m_hSpectateTarget->pev != NULL ) + pPlayerTarget = (CBasePlayer*)CBasePlayer::Instance( m_hSpectateTarget->pev ); + +#ifndef AG_NO_CLIENT_DLL + UpdateFlagStatus( pPlayerTarget ? pPlayerTarget : this ); + + if( m_bInitLocation ) { - MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); - WRITE_BYTE( m_iFOV ); + m_bInitLocation = false; + + MESSAGE_BEGIN( MSG_ONE, gmsgInitLoc, NULL, pev ); + WRITE_STRING( STRING( gpGlobals->mapname ) ); MESSAGE_END(); - - // cache FOV change at end of function, so weapon updates can see that FOV has changed } +#endif + if( pev->iuser1 != OBS_IN_EYE ) + { +//-- Martin Webrant + if( m_iFOV != m_iClientFOV ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); + WRITE_BYTE( m_iFOV ); + MESSAGE_END(); + // cache FOV change at end of function, so weapon updates can see that FOV has changed + } +//++ BulliT + } + else + { + if( pPlayerTarget && pPlayerTarget->m_iFOV != m_iClientFOV ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); + WRITE_BYTE( pPlayerTarget->m_iFOV ); + MESSAGE_END(); + } + + if( pPlayerTarget && pPlayerTarget->pev->fov != pev->fov ) + pev->fov = pPlayerTarget->pev->fov; + + } +//-- Martin Webrant // HACKHACK -- send the message to display the game title if( gDisplayTitle ) { @@ -3805,30 +4135,64 @@ void CBasePlayer::UpdateClientData( void ) gDisplayTitle = 0; } - if( pev->health != m_iClientHealth ) +//++ BulliT + if( !pPlayerTarget ) { - int iHealth = max( pev->health, 0 ); // make sure that no negative health values are sent + //if( pev->health != m_iClientHealth ) + if( (int)pev->health != m_iClientHealth ) +//-- Martin Webrant + { + int iHealth = max( (int)pev->health, 0 ); // make sure that no negative health values are sent - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev ); - WRITE_BYTE( iHealth ); - MESSAGE_END(); + // send "health" update message + MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev ); + WRITE_BYTE( iHealth ); + MESSAGE_END(); - m_iClientHealth = pev->health; + m_iClientHealth = pev->health; + } +//++ BulliT + //if( pev->armorvalue != m_iClientBattery ) + if( (int)pev->armorvalue != m_iClientBattery ) +//-- Martin Webrant + { + m_iClientBattery = pev->armorvalue; + + ASSERT( gmsgBattery > 0 ); + + // send "health" update message + MESSAGE_BEGIN( MSG_ONE, gmsgBattery, NULL, pev ); + WRITE_SHORT( (int)pev->armorvalue ); + MESSAGE_END(); + } +//++ BulliT } - - if( pev->armorvalue != m_iClientBattery ) + else { - m_iClientBattery = pev->armorvalue; + if( (int)m_hSpectateTarget->pev->health != m_iClientHealth ) + { + int iHealth = max( (int)m_hSpectateTarget->pev->health, 0 ); // make sure that no negative health values are sent - ASSERT( gmsgBattery > 0 ); + // send "health" update message + MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev ); + WRITE_BYTE( iHealth ); + MESSAGE_END(); - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsgBattery, NULL, pev ); - WRITE_SHORT( (int)pev->armorvalue ); - MESSAGE_END(); + m_iClientHealth = m_hSpectateTarget->pev->health; + } + + if( (int)m_hSpectateTarget->pev->armorvalue != m_iClientBattery ) + { + m_iClientBattery = m_hSpectateTarget->pev->armorvalue; + + ASSERT( gmsgBattery > 0 ); + // send "health" update message + MESSAGE_BEGIN( MSG_ONE, gmsgBattery, NULL, pev ); + WRITE_SHORT( (int)m_hSpectateTarget->pev->armorvalue ); + MESSAGE_END(); + } } - +//-- Martin Webrant if( pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType ) { // Comes from inside me if not set @@ -3955,25 +4319,121 @@ void CBasePlayer::UpdateClientData( void ) } } - SendAmmoUpdate(); - - // Update all the items - for( int i = 0; i < MAX_ITEM_TYPES; i++ ) +//++ BulliT + if( pev->iuser1 != OBS_IN_EYE ) { - if( m_rgpPlayerItems[i] ) // each item updates it's successors - m_rgpPlayerItems[i]->UpdateClientData( this ); - } +//-- Martin Webrant + SendAmmoUpdate(); + // Update all the items + for( int i = 0; i < MAX_ITEM_TYPES; i++ ) + { + if( m_rgpPlayerItems[i] ) // each item updates it's successors + m_rgpPlayerItems[i]->UpdateClientData( this ); + } + +//++ BulliT + } + else + { + if( pPlayerTarget ) + { + if( pPlayerTarget->m_pClientActiveItem ) + { + CBasePlayerWeapon* pWeapon = (CBasePlayerWeapon*)pPlayerTarget->m_pClientActiveItem->GetWeaponPtr(); + if( pWeapon ) + { + if( m_iSpectateAmmoClip != pWeapon->m_iClip || m_pClientActiveItem != pPlayerTarget->m_pClientActiveItem ) + { + m_pClientActiveItem = pPlayerTarget->m_pClientActiveItem; + m_iSpectateAmmoClip = pWeapon->m_iClip; + + MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); + WRITE_BYTE( 1 ); + WRITE_BYTE( pWeapon->m_iId ); + WRITE_BYTE( pWeapon->m_iClip ); + MESSAGE_END(); + } + + for( int i=0; i < MAX_AMMO_SLOTS; i++ ) + { + if( m_pClientActiveItem && i == m_pClientActiveItem->PrimaryAmmoIndex() + || m_pClientActiveItem && i == m_pClientActiveItem->SecondaryAmmoIndex() ) + { + // this is the primary or secondary ammo type for the active weapon so lets update the client with the info if needed. + if( pPlayerTarget->m_rgAmmo[i] != m_rgAmmoLast[i] ) + { + m_rgAmmoLast[i] = pPlayerTarget->m_rgAmmo[i]; + ASSERT( pPlayerTarget->m_rgAmmo[i] >= 0 ); + ASSERT( pPlayerTarget->m_rgAmmo[i] < 255 ); + + // send "Ammo" update message + MESSAGE_BEGIN( MSG_ONE, gmsgAmmoX, NULL, pev ); + WRITE_BYTE( i ); + WRITE_BYTE( max( min( pPlayerTarget->m_rgAmmo[i], 254 ), 0 ) ); // clamp the value to one byte + MESSAGE_END(); + } + } + } + } + else + { + m_pClientActiveItem = NULL; + } + } + else + { + m_pClientActiveItem = NULL; + } + } + } // Cache and client weapon change +//++ BulliT +/* m_pClientActiveItem = m_pActiveItem; m_iClientFOV = m_iFOV; +*/ + if (pev->iuser1 != OBS_IN_EYE || !pPlayerTarget) + { + m_pClientActiveItem = m_pActiveItem; + m_iClientFOV = m_iFOV; + } + else + { + m_iFOV = pPlayerTarget->m_iFOV; + m_iClientFOV = m_iFOV; + } +#ifndef AG_NO_CLIENT_DLL + if( -1 != m_iMapListSent ) + g_pGameRules->SendMapListToClient( this, false ); + + if( !m_bSentCheatCheck ) + { + m_bSentCheatCheck = true; +#ifndef _DEBUG +#ifndef AG_TESTCHEAT + if( !AgIsLocalServer() ) +#endif +#endif + { + MESSAGE_BEGIN( MSG_ONE, gmsgCheatCheck, NULL, pev ); + WRITE_BYTE( (int)ag_pure.value ); + MESSAGE_END(); + } + } + + if( pev->iuser1 == 0 ) + UpdatePlayerId(); +#else // Update Status Bar if( m_flNextSBarUpdateTime < gpGlobals->time ) { UpdateStatusBar(); m_flNextSBarUpdateTime = gpGlobals->time + 0.2; } +#endif +//-- Martin Webrant } //========================================================= @@ -4287,6 +4747,10 @@ int CBasePlayer::GetCustomDecalFrames( void ) //========================================================= void CBasePlayer::DropPlayerItem( char *pszItemName ) { +//++ BulliT + if( FStrEq( pszItemName, "flag" ) && CTF == AgGametype() ) + g_pGameRules->m_CTF.PlayerDropFlag( this, true ); +//-- Martin Webrant if( !g_pGameRules->IsMultiplayer() || ( weaponstay.value > 0 ) ) { // no dropping in single player. @@ -4662,3 +5126,424 @@ void CInfoIntermission::Think( void ) } LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission ) + +//++ BulliT +CBasePlayer* FindPlayerForward( CBasePlayer* pMe ) +{ + TraceResult tr; + + UTIL_MakeVectors( pMe->pev->v_angle ); + UTIL_TraceLine( pMe->pev->origin + pMe->pev->view_ofs,pMe->pev->origin + pMe->pev->view_ofs + gpGlobals->v_forward * 2048,dont_ignore_monsters, pMe->edict(), &tr ); + if( tr.flFraction != 1.0 && !FNullEnt( tr.pHit ) ) + { + CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); + if( pHit->IsPlayer() ) + return (CBasePlayer*)pHit; + else + return NULL; + } + return NULL; +} + +void CBasePlayer::UpdatePlayerId() +{ + // Player id + if( ag_player_id.value > 0 && NULL != pev ) + { + // If we should test + if( m_fPlayerIdCheck < gpGlobals->time ) + { + m_fPlayerIdCheck = gpGlobals->time + 0.5; + + CBasePlayer *pPlayer = FindPlayerForward( this ); + if( !pPlayer ) + return; + if( '\0' == pPlayer->GetName()[0] ) + return; + + if( m_iLastPlayerId != pPlayer->entindex() || m_fNextPlayerId < gpGlobals->time ) + { + m_iLastPlayerId = pPlayer->entindex(); + m_fNextPlayerId = gpGlobals->time + 2; + + if( IsSpectator() || GR_TEAMMATE == g_pGameRules->PlayerRelationship( this, pPlayer ) ) + { + MESSAGE_BEGIN( MSG_ONE_UNRELIABLE, gmsgPlayerId, NULL, pev ); + WRITE_BYTE( pPlayer->entindex() ); + WRITE_BYTE( 1 ); + WRITE_SHORT( (long)max((int)pPlayer->pev->health, 0 ) ); + WRITE_SHORT( (long)pPlayer->pev->armorvalue ); + MESSAGE_END(); + } + else + { + MESSAGE_BEGIN( MSG_ONE_UNRELIABLE, gmsgPlayerId, NULL, pev ); + WRITE_BYTE( pPlayer->entindex() ); + WRITE_BYTE( 0 ); + WRITE_SHORT( 0 ); + WRITE_SHORT( 0 ); + MESSAGE_END(); + } + } + } + } +} + +void CBasePlayer::RemoveAllItemsNoClientMessage() +{ + if( m_pActiveItem ) + { + ResetAutoaim(); + m_pActiveItem->Holster(); + m_pActiveItem = NULL; + } + + m_pLastItem = NULL; + + int i; + CBasePlayerItem *pPendingItem; + for( i = 0; i < MAX_ITEM_TYPES; i++ ) + { + m_pActiveItem = m_rgpPlayerItems[i]; + while( m_pActiveItem ) + { + pPendingItem = m_pActiveItem->m_pNext; + m_pActiveItem->Drop(); + m_pActiveItem = pPendingItem; + } + m_rgpPlayerItems[i] = NULL; + } + m_pActiveItem = NULL; + + pev->viewmodel = 0; + pev->weaponmodel = 0; + pev->weapons &= ~WEAPON_ALLWEAPONS; + + for( i = 0; i < MAX_AMMO_SLOTS; i++ ) + m_rgAmmo[i] = 0; + + // send Selected Weapon Message to our client + MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); + WRITE_BYTE(0); + WRITE_BYTE(0); + WRITE_BYTE(0); + MESSAGE_END(); +} + +//Special spawn - removes all entites attached to the player. +bool CBasePlayer::RespawnMatch() +{ +/* + // clear any clientside entities attached to this player + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_KILLPLAYERATTACHMENTS ); + WRITE_BYTE( (BYTE)entindex() ); + MESSAGE_END(); +*/ + + //Remove all weapons/items + RemoveAllItemsNoClientMessage(); + + if( m_pTank != NULL ) + { + m_pTank->Use( this, this, USE_OFF, 0 ); + m_pTank = NULL; + } + + //Make sure hud is shown correctly + m_iHideHUD &= ~HIDEHUD_WEAPONS; + m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; + m_iHideHUD &= ~HIDEHUD_HEALTH; + + // clear out the suit message cache so we don't keep chattering + SetSuitUpdate(NULL, FALSE, 0); + + m_iTrain |= TRAIN_NEW; // Force new train message. + m_fKnownItem = FALSE; // Force weaponinit messages. + + //Respawn player + m_bDoneFirstSpawn = true; + + UpdateClientData(); + + Spawn(); + + return TRUE; +} + +void CBasePlayer::ResetScore() +{ + //Reset score + pev->frags = 0.0; + m_iDeaths = 0; + + //Send new score to all clients. + MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); + WRITE_BYTE( ENTINDEX( edict() ) ); + WRITE_SHORT( pev->frags ); + WRITE_SHORT( m_iDeaths ); +//++ BulliT + WRITE_SHORT( g_teamplay ); + WRITE_SHORT( g_pGameRules->GetTeamIndex( m_szTeamName ) + 1 ); +//-- Martin Webrant + MESSAGE_END(); +} + +void CBasePlayer::ChangeTeam( const char *pszNewTeam, bool bSendScores ) +{ + //Save the teamname + if( TEAM_NAME_LENGTH > strlen( pszNewTeam ) ) + { + strcpy( m_szTeamName, pszNewTeam ); + AgStringToLower( m_szTeamName ); + } + else + { + strncpy( m_szTeamName, pszNewTeam, TEAM_NAME_LENGTH - 1 ); + m_szTeamName[TEAM_NAME_LENGTH - 1] = '\0'; + AgStringToLower( m_szTeamName ); + } + + //Change teamname + g_engfuncs.pfnSetClientKeyValue( entindex(), g_engfuncs.pfnGetInfoKeyBuffer( edict() ), "model", m_szTeamName ); + g_engfuncs.pfnSetClientKeyValue( entindex(), g_engfuncs.pfnGetInfoKeyBuffer( edict() ), "team", m_szTeamName ); + + if( bSendScores ) + { + g_pGameRules->RecountTeams(); + g_pGameRules->ResendScoreBoard(); + } +} + +//Long jump +void CBasePlayer::OnPickupLongjump() +{ + m_fLongjumpTimer = gpGlobals->time + ag_lj_timer.value; + if( 0 < ag_lj_timer.value ) + { +#ifdef AG_NO_CLIENT_DLL + char szLongJump[128]; + sprintf( szLongJump, "Longjump will turnoff in %d seconds", (int)ag_lj_timer.value ); + AgSay( this, szLongJump, NULL, 5, 0.5, 0.3 ); +#else + MESSAGE_BEGIN( MSG_ONE, gmsgLongjump, NULL, pev ); + WRITE_BYTE( (int)ag_lj_timer.value ); + MESSAGE_END(); +#endif + } +} + +void CBasePlayer::LongjumpThink() +{ + if( gpGlobals->time >= m_fLongjumpTimer && m_fLongJump ) + { + //Remove lj + m_fLongJump = FALSE; + //Set physics back to normal + g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); + } +} + +//++ JAIL BREAK OPEN SOURCE RIP +bool CBasePlayer::FloodCheck() +{ + //Dont check for admins, or when a match is on. + if( ag_match_running.value || IsAdmin() ) + return false; + + if( ag_floodmsgs.value ) + { + if( AgTime() < m_fFloodLockTill ) + { + char szText[256]; + sprintf( szText, "You can't talk for %d more seconds\n", (int)( m_fFloodLockTill - AgTime() ) ); + UTIL_SayText( szText, this ); + return true; + } + int nMax = ( sizeof(m_afFloodWhen) / sizeof(m_afFloodWhen[0]) ); + int i = m_iFloodWhenHead - ag_floodmsgs.value + 1; + + if( i < 0 ) + i = nMax + i; + + if( m_afFloodWhen[i] && AgTime() - m_afFloodWhen [i] < ag_floodpersecond.value ) + { + char szText[256]; + m_fFloodLockTill = AgTime() + ag_floodwaitdelay.value; + sprintf( szText, "Flood protection: You can't talk for %d seconds\n", (int)( ag_floodwaitdelay.value ) ); + UTIL_SayText( szText, this ); + return true; + } + m_iFloodWhenHead = ( m_iFloodWhenHead + 1 ) % nMax; + m_afFloodWhen [m_iFloodWhenHead] = AgTime(); + } + + return false; +} +//-- JAIL BREAK OPEN SOURCE RIP + +void CBasePlayer::MoveToInfoIntermission( edict_t *pSpot ) +{ + if( !FNullEnt( pSpot ) ) + { + edict_t *pTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( VARS( pSpot )->target ) ); + if( !FNullEnt( pTarget ) ) + { + //Intermission point. + UTIL_SetOrigin( pev, VARS( pSpot )->origin - VEC_DUCK_VIEW ); + pev->v_angle = UTIL_VecToAngles( ( VARS( pTarget )->origin - VARS( pSpot )->origin ).Normalize() ); + pev->v_angle.x = -pev->v_angle.x; + pev->v_angle.z = 0; + pev->angles = pev->v_angle; + pev->fixangle = TRUE; + } + else + { + //Spawn point. + pev->v_angle = VARS( pSpot )->angles; + pev->angles = pev->v_angle; + pev->fixangle = TRUE; + UTIL_SetOrigin( pev, VARS( pSpot )->origin - VEC_DUCK_VIEW ); + } + } +} + +bool CBasePlayer::FloodSound() +{ + if( IsAdmin() ) + return false; + + if( m_fPrevSoundFlood > AgTime() ) + { + m_fPrevSoundFlood = AgTime() + 1; //Max one sound per second. + return true; + } + m_fPrevSoundFlood = AgTime() + 1; //Max one sound per second. + return false; +} + +bool CBasePlayer::FloodText() +{ + if( ag_match_running.value || IsAdmin() ) + return false; + + if( m_fPrevTextFlood > AgTime() ) + { + m_fPrevTextFlood = AgTime() + 0.20; //Max five per second. + return true; + } + m_fPrevTextFlood = AgTime() + 0.20; //Max five per second. + return false; +} + +#include "agwallhack.h" +void CBasePlayer::SendWallhackInfo() +{ + if( m_bSentWallhackInfo ) + return; + Wallhack.SendToPlayer( this ); + m_bSentWallhackInfo = true; +} + +extern bool g_bTeam1FlagStolen; +extern bool g_bTeam2FlagStolen; +extern bool g_bTeam1FlagLost; +extern bool g_bTeam2FlagLost; + +void CBasePlayer::UpdateFlagStatus( CBasePlayer *pPlayer ) +{ + int iFlagStatus1; + if( CTF != AgGametype() ) + iFlagStatus1 = Off; + else if( pPlayer->m_bFlagTeam1 ) + iFlagStatus1 = Carry; + else if( g_bTeam1FlagLost ) + iFlagStatus1 = Lost; + else if( g_bTeam1FlagStolen ) + iFlagStatus1 = Stolen; + else + iFlagStatus1 = Home; + + int iFlagStatus2; + if( CTF != AgGametype() ) + iFlagStatus2 = Off; + else if( pPlayer->m_bFlagTeam2 ) + iFlagStatus2 = Carry; + else if( g_bTeam2FlagLost ) + iFlagStatus2 = Lost; + else if( g_bTeam2FlagStolen ) + iFlagStatus2 = Stolen; + else + iFlagStatus2 = Home; + + if( m_iFlagStatus1Last == Carry && ( iFlagStatus1 != Carry ) + ||m_iFlagStatus2Last == Carry && ( iFlagStatus2 != Carry ) ) + { + //Turn off rendering since we cont carry it anymore. + pev->renderfx = kRenderFxNone; + } + + if( m_iFlagStatus1Last != iFlagStatus1 || m_iFlagStatus2Last != iFlagStatus2 ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgCTF, NULL, pev ); + WRITE_BYTE( iFlagStatus1 ); + WRITE_BYTE( iFlagStatus2 ); + MESSAGE_END(); + } + m_iFlagStatus1Last = iFlagStatus1; + m_iFlagStatus2Last = iFlagStatus2; +} + +/* +void CBasePlayer::InitWeaponWeight() +{ + //Save off the default values. + for( i = 0; i < MAX_WEAPONS; i++ ) + m_iWeaponWeight[i] = CBasePlayerItem::ItemInfoArray[i].iWeight; +} +*/ + +int CBasePlayer::GetWeaponWeight( CBasePlayerItem *pItem ) +{ + if( 2 == m_iAutoWepSwitch && pItem->m_iId == WEAPON_CROSSBOW ) + return 20; + + return CBasePlayerItem::ItemInfoArray[pItem->m_iId].iWeight; +/* + if( pItem->m_ID >= WEAPON_NONE && < pItem->WEAPON_SNARK ) + return m_iWeaponWeight[pItem->m_ID]; + return 0; +*/ +} + +/* +void CBasePlayer::SetWeaponWeight( const char *pszWeaponWeights ) +{ + sscanf( pszWeaponWeights, + &m_iWeaponWeight[WEAPON_NONE], + &m_iWeaponWeight[WEAPON_CROWBAR], + &m_iWeaponWeight[WEAPON_GLOCK], + &m_iWeaponWeight[WEAPON_PYTHON], + &m_iWeaponWeight[WEAPON_MP5], + &m_iWeaponWeight[WEAPON_CHAINGUN], + &m_iWeaponWeight[WEAPON_CROSSBOW], + &m_iWeaponWeight[WEAPON_SHOTGUN], + &m_iWeaponWeight[WEAPON_RPG], + &m_iWeaponWeight[WEAPON_GAUSS], + &m_iWeaponWeight[WEAPON_EGON], + &m_iWeaponWeight[WEAPON_HORNETGUN], + &m_iWeaponWeight[WEAPON_HANDGRENADE], + &m_iWeaponWeight[WEAPON_TRIPMINE], + &m_iWeaponWeight[WEAPON_SATCHEL], + &m_iWeaponWeight[WEAPON_SNARK] ); +} +*/ +//-- Martin Webrant + +void CBasePlayer::ShowVGUI( int iMenu ) +{ + MESSAGE_BEGIN( MSG_ONE, gmsgVGUIMenu, NULL, pev ); + WRITE_BYTE( iMenu ); + MESSAGE_END(); +} + diff --git a/dlls/player.h b/dlls/player.h index e75787ee..37704645 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -17,6 +17,15 @@ #include "pm_materials.h" +//++ BulliT +#include "items.h" +#include "gamerules.h" +#include "agglobal.h" +#include "agclient.h" +#include "pm_shared.h" +extern int gmsgSpectator; +//-- Martin Webrant + #define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet #define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet #define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. @@ -203,8 +212,9 @@ public: virtual BOOL IsSneaking( void ) { return m_tSneaking <= gpGlobals->time; } virtual BOOL IsAlive( void ) { return (pev->deadflag == DEAD_NO) && pev->health > 0; } virtual BOOL ShouldFadeOnDeath( void ) { return FALSE; } - virtual BOOL IsPlayer( void ) { return TRUE; } // Spectators should return FALSE for this, they aren't "players" as far as game logic is concerned - +//++ BulliT + virtual BOOL IsPlayer( void ) { return !IsSpectator(); } // Spectators should return FALSE for this, they aren't "players" as far as game logic is concerned +//-- Martin Webrant virtual BOOL IsNetClient( void ) { return TRUE; } // Bots should return FALSE for this, they can't receive NET messages // Spectators should return TRUE for this virtual const char *TeamID( void ); @@ -307,9 +317,328 @@ public: char m_SbarString0[ SBAR_STRING_SIZE ]; char m_SbarString1[ SBAR_STRING_SIZE ]; - float m_flNextChatTime; +//++ BulliT +protected: + bool m_bAdmin; //Player gained admin status. + bool m_bIngame; //Player was in the game when match started. + + float m_fPlayerIdCheck; //Next time to check player id. + + float m_fDisplayGamemode; //Next time to display gamemode. + + float m_fLongjumpTimer; //Long jump timer. + + Vector m_vKilled; //Where the player got killed last time. + + double m_fFloodLockTill; //Flood protection: Locked from talking + double m_afFloodWhen[10]; //Flood protection: When messages were said + int m_iFloodWhenHead; //Flood protection: Head pointer for when said + + double m_fPrevSoundFlood; + double m_fPrevTextFlood; + + bool m_bSpawnFull; //Spawn with all weapons. + + double m_fSpectateTime; //Dont flood the spectate functions. + int m_iSpectateWeapon; + int m_iSpectateAmmoClip; + + int m_iSpot; //Info intermission spot. + bool m_bSentWallhackInfo; + + //int m_iWeaponWeight[MAX_WEAPONS]; + bool m_bInitLocation; //True to init location on client. + + int m_iLastPlayerId; + float m_fNextPlayerId; + bool m_bSentCheatCheck; + +public: + int m_iVote; //What player voted. -1 (not voted), 0 no, 1 yes. + bool m_bDoneFirstSpawn; //True if player has done the first spawn. + bool m_bInSpawn; //True if player is spawning. + bool m_bReady; //True if player is ready to enter lts/lms + int m_iNumTeams; + //Userinfo + int m_iDisableSpecs; + int m_iAutoWepSwitch; + char m_szModel[64]; + + //CTF + bool m_bFlagTeam1; //True if you got flag 1. + bool m_bFlagTeam2; //True if you got flag 2. + + enum enumFlagStatus { Off = -1, Home = 0, Stolen = 1, Lost = 2, Carry = 3}; + int m_iFlagStatus1Last; + int m_iFlagStatus2Last; + + enum { Invalid, Alive, GotKilled, SelfKilled, WorldKilled }; + int m_iStatus; + + //Maps + int m_iMapListSent; + + void Init(); //Init all extra variables. + const char *GetAuthID(); //Get steam ID + const char *GetName(); //Get name + + bool IsAdmin(); //Returns true if a voted or real admin. + void SetIsAdmin(bool bAdmin); //Set to true to be admin. + + bool IsIngame(); //Returns true if allowed to enter the game. If false go specmode. + void SetIngame(bool bIngame); //Set to true to allow player in the game. + + bool ShouldWeaponSwitch(); //Should weapon switch when walking over? + + bool DisableSpecs(); //Does this player allow spectators. + + void UpdatePlayerId(); //Check if we should send player name. + + void OnPickupLongjump(); //Player picked it up. + void LongjumpThink(); //The lj think. Handles timer. + + void SetDisplayGamemode(float fTime); //Display gamemode. + + Vector GetKilledPosition(); //Where the player got killed last time. + + void ShowVGUI( int iMenu ); + void ChangeTeam( const char *pszNewTeam, bool bSendScores = true ); //Change team/model. + bool RespawnMatch(); //Respawn and removes players old enties. + void ResetScore(); //Reset score. + + bool IsSpectator(); //Returns true if spectating. + bool IsProxy(); //Returns true if proxy server client. + + bool FloodCheck(); //Returns true if user is flooding us. Use this one for public messages. + bool FloodSound(); //Returns true if user is flooding us. + bool FloodText(); //Returns true if user is flooding us. + + void MoveToInfoIntermission( edict_t *pSpot ); //Move to a info intermission spot. + friend class AgClient; //AgClient class should be able to access protected variables. + + int BloodColor() { return BLOOD_COLOR_RED; } + + void SetSpawnFull( bool bSpawnFull ); //Set to true to spawn american way. + bool GetSpawnFull(); //Get spawn full with ammo + + void RemoveAllItemsNoClientMessage(); + EHANDLE m_hSpectateTarget;//The player this player is watching. + void Spectate_Init(); + void Spectate_Spectate(); + void Spectate_Start( bool bResetScore = true ); + void Spectate_Stop( bool bIntermediateSpawn = false ); + void Spectate_SetMode( int iMode ); + void Spectate_UpdatePosition(); + void Spectate_HandleButtons(); + void Spectate_Nextplayer( bool bReverse ); + void Spectate_Nextspot( bool bReverse ); + bool Spectate_Think(); + bool Spectate_Follow( EHANDLE &pPlayer, int iMode ); + bool Spectate_HLTV(); + + void SendWallhackInfo(); + + void UpdateFlagStatus( CBasePlayer *pPlayer ); + + int GetWeaponWeight( CBasePlayerItem *pItem ); +/* + void SetWeaponWeight( const char *pszWeaponWeights ); + void InitWeaponWeight(); +*/ +//-- Martin Webrant }; +//++ BulliT +inline void CBasePlayer::Init() +{ + m_bSentWallhackInfo = false; + m_bInSpawn = false; + + m_bAdmin = false; + m_bIngame = 1 > ag_match_running.value; + m_bDoneFirstSpawn = false; + + m_fPlayerIdCheck = gpGlobals->time + 5.0; + + m_fDisplayGamemode = 0.0; + + m_fLongjumpTimer = 0.0; + + m_iVote = -1; + + m_iStatus = Invalid; + + m_fDisplayGamemode = gpGlobals->time + 5; + + m_vKilled = g_vecZero; + + m_fFloodLockTill = AgTime(); + + for( int i = 0; i < sizeof( m_afFloodWhen ) / sizeof( m_afFloodWhen[0] ); i++ ) + { + m_afFloodWhen[i] = AgTime(); + } + + m_iFloodWhenHead = 0; + + m_fPrevSoundFlood = AgTime(); + m_fPrevTextFlood = AgTime(); + + m_bSpawnFull = false; + + Spectate_Init(); + if( ARENA == AgGametype() ) + { + //Never allow new players in arena mode to spawn directly. + m_bIngame = false; + g_pGameRules->m_Arena.ClientConnected( this ); + } + else if( LMS == AgGametype() ) + { + //Never allow new players in arena mode to spawn directly. + m_bIngame = false; + g_pGameRules->m_LMS.ClientConnected( this ); + } + else if( CTF == AgGametype() ) + { + g_pGameRules->m_CTF.ClientConnected( this ); + + if( 1 == ag_match_running.value ) + { + //Check score cache if he was in the game. + g_pGameRules->m_ScoreCache.RestoreInGame( this ); + } + } + else + { + if( 1 == ag_match_running.value ) + { + //Check score cache if he was in the game. + g_pGameRules->m_ScoreCache.RestoreInGame( this ); + } + } + + if( 0 < ag_auto_admin.value ) + { + //Autoadmin the player. + AdminCache.RestoreAdmin( this ); + } + + m_bFlagTeam1 = false; + m_bFlagTeam2 = false; + m_iFlagStatus1Last = Off; + m_iFlagStatus2Last = Off; + + m_iAutoWepSwitch = 1; + m_iDisableSpecs = 0; + + //InitWeaponWeight(); + + m_bReady = true; + m_iNumTeams = 0; + + m_bInitLocation = true; + m_iMapListSent = -1; + + m_szModel[0] = '\0'; + + m_iLastPlayerId = -1; + m_fNextPlayerId = 0.0; + m_bSentCheatCheck = false; + +#ifdef _DEBUG + if( 0 == strcmp( GetAuthID(),"237555" ) ) + m_bAdmin = true; +#endif +}; + +inline const char* CBasePlayer::GetAuthID() +{ + if( g_bLangame ) + return ""; + return GETPLAYERAUTHID( edict() ); +}; + +inline const char* CBasePlayer::GetName() +{ + return pev->netname ? STRING(pev->netname)[0] ? STRING(pev->netname) : "" : ""; +}; + +inline bool CBasePlayer::IsAdmin() +{ + return m_bAdmin; +}; + +inline void CBasePlayer::SetIsAdmin(bool bAdmin) +{ + m_bAdmin = bAdmin; +}; + +inline bool CBasePlayer::IsIngame() +{ + return m_bIngame; +}; + +inline void CBasePlayer::SetIngame(bool bIngame) +{ + m_bIngame = bIngame; +}; + +inline bool CBasePlayer::IsSpectator() +{ + return pev->iuser1 > 0 || IsProxy(); +}; + +inline bool CBasePlayer::IsProxy() +{ + if (pev->flags & FL_PROXY ) + return true; + return false; +}; + +inline Vector CBasePlayer::GetKilledPosition() +{ + return m_vKilled; +} + +inline bool CBasePlayer::ShouldWeaponSwitch() +{ + return 0 != m_iAutoWepSwitch; +}; + +inline void CBasePlayer::SetDisplayGamemode(float fTime) +{ + m_fDisplayGamemode = gpGlobals->time + fTime; +}; + + +inline void CBasePlayer::SetSpawnFull(bool bSpawnFull) +{ + m_bSpawnFull = bSpawnFull; +} + +inline bool CBasePlayer::GetSpawnFull() +{ + return m_bSpawnFull; +} + +inline bool CBasePlayer::DisableSpecs() +{ + return 0 != m_iDisableSpecs; +} + +// Spectator Movement modes (stored in pev->iuser1, so the physics code can get at them) +#define OBS_NONE 0 +#define OBS_CHASE_LOCKED 1 +#define OBS_CHASE_FREE 2 +#define OBS_ROAMING 3 +#define OBS_IN_EYE 4 +#define OBS_MAP_FREE 5 +#define OBS_MAP_CHASE 6 + +//-- Martin Webrant + + #define AUTOAIM_2DEGREES 0.0348994967025 #define AUTOAIM_5DEGREES 0.08715574274766 #define AUTOAIM_8DEGREES 0.1391731009601 diff --git a/dlls/python.cpp b/dlls/python.cpp index 7bb71325..35774521 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -22,6 +22,10 @@ #include "player.h" #include "gamerules.h" +#ifdef AGSTATS +#include "agstats.h" +#endif + enum python_e { PYTHON_IDLE1 = 0, @@ -180,7 +184,9 @@ void CPython::PrimaryAttack() m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; m_iClip--; - +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif m_pPlayer->pev->effects = (int)( m_pPlayer->pev->effects ) | EF_MUZZLEFLASH; // player "shoot" animation diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 1fec5cf1..dce509ae 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -23,6 +23,12 @@ #include "player.h" #include "gamerules.h" +//++ BulliT +#ifdef AGSTATS +#include "agstats.h" +#endif +//-- Martin Webrant + enum rpg_e { RPG_IDLE = 0, @@ -266,6 +272,14 @@ void CRpgRocket::FollowThink( void ) if( pev->waterlevel == 0 && pev->velocity.Length() < 1500 ) { Detonate(); +//++ BulliT + //Fixes the bug where it won't auto reload when it explodes coming out of the water + if( m_pLauncher ) + { + // my launcher is still around, tell it I'm dead. + m_pLauncher->m_cActiveRockets--; + } +//-- Martin Webrant } } // ALERT( at_console, "%.0f\n", flSpeed ); @@ -323,6 +337,16 @@ void CRpg::Reload( void ) void CRpg::Spawn() { +//++ BulliT +#ifndef CLIENT_DLL + if( SGBOW == AgGametype() ) + { + //Spawn crossbow instead. + CBaseEntity *pNewWeapon = CBaseEntity::Create( "weapon_crossbow", g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); + return; + } +#endif +//-- Martin Webrant Precache(); m_iId = WEAPON_RPG; @@ -447,6 +471,17 @@ void CRpg::PrimaryAttack() CRpgRocket *pRocket = CRpgRocket::CreateRpgRocket( vecSrc, m_pPlayer->pev->v_angle, m_pPlayer, this ); UTIL_MakeVectors( m_pPlayer->pev->v_angle );// RpgRocket::Create stomps on globals, so remake. +//++ BulliT + if( ag_rpg_fix.value > 0 ) + { + //Fixes the RPG wall bugg just a little bit - I dont want to remove it all. (You jump back and get the RPG in back of your head) + if( ( pRocket->pev->velocity.x >= 0 && m_pPlayer->pev->velocity.x < 0 ) || ( pRocket->pev->velocity.x < 0 && m_pPlayer->pev->velocity.x > 0 ) ) + pRocket->pev->velocity = pRocket->pev->velocity + 0.5 * gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward ); //Only use 50% of the velocit + else + pRocket->pev->velocity = pRocket->pev->velocity + gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward ); + } + else +//-- Martin Webrant pRocket->pev->velocity = pRocket->pev->velocity + gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward ); #endif @@ -462,7 +497,11 @@ void CRpg::PrimaryAttack() PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usRpg ); m_iClip--; - +//++ BulliT +#ifdef AGSTATS + Stats.FireShot( m_pPlayer,STRING( pev->classname ) ); +#endif +//-- Martin Webrant m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; } diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index 8c96e99c..c6a8a22a 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -22,6 +22,12 @@ #include "player.h" #include "gamerules.h" +//++ BulliT +#ifdef AGSTATS +#include "agstats.h" +#endif +//-- Martin Webrant + // special deathmatch shotgun spreads #define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees #define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees @@ -136,6 +142,9 @@ void CShotgun::PrimaryAttack() m_iClip--; +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif int flags; #if defined( CLIENT_WEAPONS ) flags = FEV_NOTHOST; @@ -202,7 +211,10 @@ void CShotgun::SecondaryAttack( void ) m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; m_iClip -= 2; - +#ifdef AGSTATS + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); + Stats.FireShot( m_pPlayer, STRING( pev->classname ) ); +#endif int flags; #if defined( CLIENT_WEAPONS ) flags = FEV_NOTHOST; diff --git a/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp index 9a46e722..bdca42e3 100644 --- a/dlls/singleplay_gamerules.cpp +++ b/dlls/singleplay_gamerules.cpp @@ -25,7 +25,10 @@ #include "skill.h" #include "items.h" -extern DLL_GLOBAL CGameRules *g_pGameRules; +//++ BulliT +extern DLL_GLOBAL AgGameRules *g_pGameRules; +//-- Martin Webrant + extern DLL_GLOBAL BOOL g_fGameOver; extern int gmsgDeathMsg; // client dll messages extern int gmsgScoreInfo; diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index 22200b74..648a4f9f 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -113,6 +113,16 @@ int CSqueakGrenade::Classify( void ) void CSqueakGrenade::Spawn( void ) { +//++ BulliT +#ifndef CLIENT_DLL + if( SGBOW == AgGametype() ) + { + //Spawn crossbow instead. + CBaseEntity *pNewWeapon = CBaseEntity::Create( "weapon_crossbow", g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); + return; + } +#endif +//-- Martin Webrant Precache(); // motor diff --git a/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index 614bd7bb..9b40b0f9 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -22,6 +22,11 @@ #include "player.h" #include "weapons.h" #include "gamerules.h" +//++ BulliT +#include "multi_gamerules.h" +#include "aggamerules.h" +extern int g_teamplay; +//-- Martin Webrant #include "teamplay_gamerules.h" #include "game.h" @@ -49,7 +54,13 @@ CHalfLifeTeamplay::CHalfLifeTeamplay() edict_t *pWorld = INDEXENT( 0 ); if( pWorld && pWorld->v.team ) { - if( teamoverride.value ) + //++ BulliT + if( CTF == AgGametype() ) + { + sprintf( m_szTeamList, "%s;%s", CTF_TEAM1_NAME, CTF_TEAM2_NAME ); + } + //-- Martin Webrant + else if( teamoverride.value ) { const char *pTeamList = STRING( pWorld->v.team ); if( pTeamList && strlen( pTeamList ) ) @@ -85,12 +96,18 @@ void CHalfLifeTeamplay::Think( void ) #ifndef NO_VOICEGAMEMGR g_VoiceGameMgr.Update(gpGlobals->frametime); #endif +//++ BulliT + if( !AgGameRules::AgThink() ) + return; +//-- Martin Webrant if( g_fGameOver ) // someone else quit the game already { CHalfLifeMultiplay::Think(); return; } +//++ BulliT +/* float flTimeLimit = CVAR_GET_FLOAT( "mp_timelimit" ) * 60; time_remaining = (int)( flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0 ); @@ -100,7 +117,41 @@ void CHalfLifeTeamplay::Think( void ) GoToIntermission(); return; } +*/ + if( !m_Timer.TimeRemaining( time_remaining ) ) + { + if( !m_SuddenDeath.IsSuddenDeath() ) + { + //Go intermission. + GoToIntermission(); + return; + } + else + { + //Sudden death! + time_remaining = 0; + } + } + + if( CTF == AgGametype() ) + { + if( m_CTF.CaptureLimit() ) + { + GoToIntermission(); + return; + } + } //++ muphicks + else if( DOM == AgGametype() ) + { + if( m_DOM.ScoreLimit() ) + { + GoToIntermission(); + return; + } + } + //-- muphicks +//-- Martin Webrant float flFragLimit = fraglimit.value; if( flFragLimit ) { @@ -148,6 +199,10 @@ void CHalfLifeTeamplay::Think( void ) //========================================================= BOOL CHalfLifeTeamplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { +//++ BulliT + if( CHalfLifeMultiplay::ClientCommand( pPlayer, pcmd ) ) + return TRUE; +//-- Martin Webrant #ifndef NO_VOICEGAMEMGR if( g_VoiceGameMgr.ClientCommand( pPlayer, pcmd ) ) return TRUE; @@ -185,6 +240,24 @@ const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) char *mdls = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); strncpy( pPlayer->m_szTeamName, mdls, TEAM_NAME_LENGTH ); +//++ BulliT + if( TEAM_NAME_LENGTH <= strlen( pPlayer->m_szTeamName ) ) + pPlayer->m_szTeamName[TEAM_NAME_LENGTH - 1] = '\0'; + AgStringToLower( pPlayer->m_szTeamName ); + + if( pPlayer->pev->flags & FL_PROXY ) + { + strcpy( pPlayer->m_szTeamName,"" ); + g_engfuncs.pfnSetClientKeyValue( pPlayer->entindex(), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->m_szTeamName ); + g_engfuncs.pfnSetClientKeyValue( pPlayer->entindex(), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->m_szTeamName ); + } + else if( 0 == strlen(pPlayer->m_szTeamName ) ) + { + strcpy( pPlayer->m_szTeamName,"gordon" ); + g_engfuncs.pfnSetClientKeyValue( pPlayer->entindex(), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->m_szTeamName ); + g_engfuncs.pfnSetClientKeyValue( pPlayer->entindex(), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->m_szTeamName ); + } +//-- Martin Webrant RecountTeams(); // update the current player of the team he is joining @@ -225,6 +298,9 @@ void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) } MESSAGE_END(); +//++ BulliT + pPlayer->m_iNumTeams = num_teams; +//-- Martin Webrant RecountTeams(); char *mdls = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); @@ -256,6 +332,18 @@ void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) MESSAGE_END(); } } +//++ BulliT + if( CTF == AgGametype() ) + m_CTF.PlayerInitHud( pPlayer ); + //++ muphicks + else if( DOM == AgGametype() ) + m_DOM.PlayerInitHud( pPlayer ); +//-- muphicks + +#define MENU_TEAM 2 + if( strlen( m_szTeamList ) ) + pPlayer->ShowVGUI( MENU_TEAM ); +//-- Martin Webrant } void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) @@ -292,18 +380,31 @@ void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTea g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->m_szTeamName ); g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->m_szTeamName ); +//++ BulliT + RecountTeams(); +//-- Martin Webrant // notify everyone's HUD of the team change MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); WRITE_BYTE( clientIndex ); - WRITE_STRING( pPlayer->m_szTeamName ); +//++ BulliT + WRITE_STRING( pPlayer->TeamID() ); + //WRITE_STRING( pPlayer->m_szTeamName ); +//-- Martin Webrant MESSAGE_END(); MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); WRITE_BYTE( clientIndex ); WRITE_SHORT( pPlayer->pev->frags ); WRITE_SHORT( pPlayer->m_iDeaths ); - WRITE_SHORT( 0 ); +//++ BulliT + WRITE_SHORT( g_teamplay ); WRITE_SHORT( g_pGameRules->GetTeamIndex( pPlayer->m_szTeamName ) + 1 ); +//-- Martin Webrant + MESSAGE_END(); +//Spectator + MESSAGE_BEGIN( MSG_ALL, gmsgSpectator ); + WRITE_BYTE( ENTINDEX( pPlayer->edict() ) ); + WRITE_BYTE( pPlayer->IsSpectator() ? 1 : 0 ); MESSAGE_END(); } @@ -355,8 +456,12 @@ void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infob ChangePlayerTeam( pPlayer, mdls, TRUE, TRUE ); - // recound stuff - RecountTeams( TRUE ); + // recount stuff +//++ BulliT + //RecountTeams( TRUE ); + //RecountTeams(); + //MSGTEST ResendScoreBoard(); +//-- Martin Webrant } extern int gmsgDeathMsg; @@ -394,6 +499,13 @@ void CHalfLifeTeamplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, e //========================================================= void CHalfLifeTeamplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) { +//++ BulliT + if( pVictim && CTF == AgGametype() ) + m_CTF.PlayerKilled( pVictim, pKiller ); + + if( pVictim && LMS == AgGametype() ) + pVictim->SetIngame( false ); //Cant respawn +//-- Martin Webrant if( !m_DisableDeathPenalty ) { CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor ); @@ -428,6 +540,10 @@ BOOL CHalfLifeTeamplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity //========================================================= int CHalfLifeTeamplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) { +//++ BulliT + if( ARENA == AgGametype() ) + return GR_NOTTEAMMATE; +//-- Martin Webrant // half life multiplay has a simple concept of Player Relationships. // you are either on another player's team, or you are not. if( !pPlayer || !pTarget || !pTarget->IsPlayer() ) @@ -460,6 +576,9 @@ BOOL CHalfLifeTeamplay::ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) //========================================================= int CHalfLifeTeamplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) { +//++ BulliT + AgGameRules::IPointsForKill( pAttacker, pKilled ); +//-- Martin Webrant if( !pKilled ) return 0; @@ -516,6 +635,10 @@ BOOL CHalfLifeTeamplay::IsValidTeam( const char *pTeamName ) const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) { +//++ BulliT + if( strlen( s_szLeastPlayers ) ) + return s_szLeastPlayers; +//-- Martin Webrant int i; int minPlayers = MAX_TEAMS; int teamCount[MAX_TEAMS] = {0}; @@ -549,10 +672,14 @@ const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) //========================================================= //========================================================= -void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) +//++ BulliT +//void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) +void CHalfLifeTeamplay::RecountTeams() +//-- Martin Webrant { char *pName; char teamlist[TEAMPLAY_TEAMLISTLENGTH]; + int i; // loop through all teams, recounting everything num_teams = 0; @@ -578,11 +705,46 @@ void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) m_teamLimit = FALSE; } +//++ BulliT + s_szLeastPlayers[0] = '\0'; + if( m_teamLimit ) + { + int teamCount[MAX_TEAMS] = {0}; + int minPlayers = MAX_TEAMS; + + // loop through all clients, count number of players on each team + for( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pPlayerLoop = AgPlayerByIndex( i ); + if( pPlayerLoop ) + { + int team = GetTeamIndex( pPlayerLoop->m_szTeamName ); + if( team >= 0 ) + teamCount[team]++; + } + } + + // Find team with least players + for( i = 0; i < num_teams; i++ ) + { + if( teamCount[i] < minPlayers ) + { + minPlayers = teamCount[i]; + strcpy( s_szLeastPlayers, team_names[i] ); + } + } + } + else + { + strcpy( team_names[num_teams++], CTF_TEAM1_NAME ); + strcpy( team_names[num_teams++], CTF_TEAM2_NAME ); + } +//-- Martin Webrant // Sanity check memset( team_scores, 0, sizeof(team_scores) ); // loop through all clients - for( int i = 1; i <= gpGlobals->maxClients; i++ ) + for( i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *plr = UTIL_PlayerByIndex( i ); @@ -611,15 +773,30 @@ void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) } if( bResendInfo ) //Someone's info changed, let's send the team info again. +//++ BulliT + plr->edict()->v.team = tm + 1; +//-- Martin Webrant + } + } +//++ BulliT + // loop through all clients and send team names + for( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pPlayerLoop = AgPlayerByIndex( i ); + if( pPlayerLoop ) + { + if( pPlayerLoop->m_iNumTeams != num_teams ) { - if( plr && IsValidTeam( plr->TeamID() ) ) - { - MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo, NULL ); - WRITE_BYTE( plr->entindex() ); - WRITE_STRING( plr->TeamID() ); - MESSAGE_END(); - } + MESSAGE_BEGIN( MSG_ONE, gmsgTeamNames, NULL, pPlayerLoop->edict() ); + WRITE_BYTE( num_teams ); + for( i = 0; i < num_teams; i++ ) + { + WRITE_STRING( team_names[i] ); + } + MESSAGE_END(); + pPlayerLoop->m_iNumTeams = num_teams; } } } +//-- Martin Webrant } diff --git a/dlls/teamplay_gamerules.h b/dlls/teamplay_gamerules.h index 06823ca6..8e2b4d31 100644 --- a/dlls/teamplay_gamerules.h +++ b/dlls/teamplay_gamerules.h @@ -16,6 +16,11 @@ // teamplay_gamerules.h // +//++ BulliT +#if !defined(_TEAMPLAY_H_) +#include "multi_gamerules.h" +#define _TEAMPLAY_H_ +//-- Martin Webrant #define MAX_TEAMNAME_LENGTH 16 #define MAX_TEAMS 32 @@ -36,7 +41,9 @@ public: virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); virtual void InitHUD( CBasePlayer *pl ); virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ); - virtual const char *GetGameDescription( void ) { return "HL Teamplay"; } // this is the game name that gets seen in the server browser +//++ BulliT + //virtual const char *GetGameDescription( void ) { return "HL Teamplay"; } // this is the game name that gets seen in the server browser +//-- Martin Webrant virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); virtual void Think( void ); @@ -46,10 +53,10 @@ public: const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ); virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ); -private: - void RecountTeams( bool bResendInfo = FALSE ); + void RecountTeams( void ); const char *TeamWithFewestPlayers( void ); +private: BOOL m_DisableDeathMessages; BOOL m_DisableDeathPenalty; BOOL m_teamLimit; // This means the server set only some teams as valid diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index d7f9483c..46fcf81b 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -885,7 +885,17 @@ void CBaseTrigger::HurtTouch( CBaseEntity *pOther ) float fldmg; if( !pOther->pev->takedamage ) - return; +//++ BulliT + //return; + { + if( 0 == strncmp( STRING( pOther->pev->classname ), "item_flag_team", 14 ) ) + { + AgCTFFlag *pFlag = (AgCTFFlag*)pOther; + pFlag->ResetFlag(); + } + return; + } +//-- Martin Webrant if( ( pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYTOUCH ) && !pOther->IsPlayer() ) { @@ -1838,7 +1848,8 @@ void CBaseTrigger::TeleportTouch( CBaseEntity *pOther ) edict_t *pentTarget = NULL; // Only teleport monsters or clients - if( !FBitSet( pevToucher->flags, FL_CLIENT | FL_MONSTER ) ) + //if( !FBitSet( pevToucher->flags, FL_CLIENT | FL_MONSTER ) ) + if( !FBitSet( pevToucher->flags, FL_CLIENT | FL_MONSTER ) && !FClassnameIs( pevToucher, "monster_satchel" ) ) return; if( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) @@ -1884,6 +1895,10 @@ void CBaseTrigger::TeleportTouch( CBaseEntity *pOther ) if( pOther->IsPlayer() ) { pevToucher->v_angle = pentTarget->v.angles; + +//++ BulliT + ( (CBasePlayer*)pOther )->Spectate_UpdatePosition(); +//-- Martin Webrant } pevToucher->fixangle = TRUE; diff --git a/dlls/util.cpp b/dlls/util.cpp index d1fceb0a..6d0f3656 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -2450,3 +2450,22 @@ int CRestore::BufferCheckZString( const char *string ) } return 0; } + +//++ BulliT +void UTIL_SendDirectorMessage( edict_t *ent1, edict_t *ent2, int priority_and_flags ) +{ + MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); + WRITE_BYTE( 9 ); //command length in bytes + WRITE_BYTE( DRC_CMD_EVENT ); + if( ent1 ) + WRITE_SHORT( ENTINDEX( ent1 ) ); + else + WRITE_SHORT( 0 ); + if( ent2 ) + WRITE_SHORT( ENTINDEX( ent2 ) ); + else + WRITE_SHORT( 0 ); + WRITE_LONG( priority_and_flags ); + MESSAGE_END(); +} +//-- Martin Webrant diff --git a/dlls/util.h b/dlls/util.h index e8aee878..355406f8 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -143,9 +143,15 @@ inline entvars_t *VARS(edict_t *pent) inline entvars_t* VARS(EOFFSET eoffset) { return VARS(ENT(eoffset)); } inline int ENTINDEX(edict_t *pEdict) { return (*g_engfuncs.pfnIndexOfEdict)(pEdict); } inline edict_t* INDEXENT( int iEdictNum ) { return (*g_engfuncs.pfnPEntityOfEntIndex)(iEdictNum); } +//++ BulliT +#ifndef AGMSGSTAT +//-- Martin Webrant inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ) { (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ENT(ent)); } +//++ BulliT +#endif +//-- Martin Webrant // Testing the three types of "entity" for nullity #define eoNullEntity 0 @@ -456,6 +462,10 @@ extern DLL_GLOBAL int g_Language; #define SVC_ROOMTYPE 37 #define SVC_DIRECTOR 51 +//++ BulliT +void UTIL_SendDirectorMessage( edict_t *ent1, edict_t *ent2, int priority_and_flags ); +//-- Martin Webrant + // triggers #define SF_TRIGGER_ALLOWMONSTERS 1// monsters allowed to fire this trigger #define SF_TRIGGER_NOCLIENTS 2// players not allowed to fire this trigger @@ -567,3 +577,7 @@ int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); float UTIL_WeaponTimeBase( void ); + +//++ BulliT +#include +//-- Martin Webrant diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index ff03bbfc..968c4fa4 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -382,6 +382,36 @@ void W_Precache( void ) PRECACHE_SOUND( "weapons/bullet_hit2.wav" ); // hit by bullet PRECACHE_SOUND( "items/weapondrop1.wav" );// weapon falls to the ground + +//++ BulliT +#ifndef AG_NO_CLIENT_DLL + UTIL_PrecacheOther( "item_flag_team1" ); + UTIL_PrecacheOther( "item_flag_team2" ); + +#ifdef AG_USE_CHEATPROTECTION +//Just the visable models forced. +/* + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/flag.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_crowbar.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_9mmhandgun.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_9mmAR.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_357.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_gauss.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_rpg.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_crossbow.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_egon.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_tripmine.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_satchel.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_satchel_radio.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_shotgun.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_grenade.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_squeak.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_hgun.mdl" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/flag.mdl" ); +*/ +#endif +#endif +//-- Martin Webrant } TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] = @@ -574,7 +604,12 @@ void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) if( pOther->AddPlayerItem( this ) ) { AttachToPlayer( pPlayer ); - EMIT_SOUND( ENT( pPlayer->pev ), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); +//++ BulliT + if( pPlayer->m_bInSpawn ) + EMIT_SOUND( ENT( pPlayer->pev ), CHAN_ITEM, "items/gunpickup2.wav", ag_spawn_volume.value, ATTN_NORM ); + else +//-- Martin Webrant + EMIT_SOUND( ENT( pPlayer->pev ), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); } SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? @@ -791,11 +826,13 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) if( bSend ) { +//++ BulliT TESTWEP MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pPlayer->pev ); WRITE_BYTE( state ); WRITE_BYTE( m_iId ); WRITE_BYTE( m_iClip ); MESSAGE_END(); +//-- Martin Webrant TESTWEP m_iClientClip = m_iClip; m_iClientWeaponState = state; diff --git a/dlls/weapons.h b/dlls/weapons.h index 5112254a..379ab9c7 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -657,6 +657,7 @@ public: void EXPORT Revive( void ); static CLaserSpot *CreateSpot( void ); + inline void LiveForTime( float time ) { SetThink( &CLaserSpot::SUB_Remove ); pev->nextthink = gpGlobals->time + time; } }; class CRpg : public CBasePlayerWeapon diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index de855a50..d78d591c 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -2455,8 +2455,9 @@ PM_Jump void PM_Jump( void ) { int i; - qboolean tfc = false; - +//++ BulliT + //qboolean tfc = false; +//-- BulliT qboolean cansuperjump = false; if( pmove->dead ) @@ -2464,15 +2465,15 @@ void PM_Jump( void ) pmove->oldbuttons |= IN_JUMP; // don't jump again until released return; } - - tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? true : false; +//++ BulliT + //tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? true : false; // Spy that's feigning death cannot jump - if( tfc && ( pmove->deadflag == ( DEAD_DISCARDBODY + 1 ) ) ) + /*if( tfc && ( pmove->deadflag == ( DEAD_DISCARDBODY + 1 ) ) ) { return; - } - + }*/ +//-- BulliT // See if we are waterjumping. If so, decrement count and return. if( pmove->waterjumptime ) { @@ -2538,13 +2539,17 @@ void PM_Jump( void ) // In the air now. pmove->onground = -1; - PM_PreventMegaBunnyJumping(); +//++ BulliT + bBunnyJump = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "bj" ) ) == 1 ? true : false; + if( !bBunnyJump ) + PM_PreventMegaBunnyJumping(); - if( tfc ) + /*if( tfc ) { pmove->PM_PlaySound( CHAN_BODY, "player/plyrjmp8.wav", 0.5, ATTN_NORM, 0, PITCH_NORM ); } - else + else*/ +//-- BulliT { PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), 1.0 ); } @@ -2683,14 +2688,15 @@ void PM_CheckFalling( void ) } else if( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED / 2 ) { - qboolean tfc = false; +//++ BulliT + /*qboolean tfc = false; tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? true : false; if( tfc ) { pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - } - + }*/ +//-- BulliT fvol = 0.85; } else if( pmove->flFallVelocity < PLAYER_MIN_BOUNCE_SPEED )