diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp
index 05c00274..f5cc8bcd 100644
--- a/core/TimerSys.cpp
+++ b/core/TimerSys.cpp
@@ -39,9 +39,10 @@ SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallback, SH_NOATTRIB, false, ConVar *
TimerSystem g_Timers;
float g_fUniversalTime = 0.0f;
-float g_fMapStartTime = 0.0f;
+float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */
const float *g_pUniversalTime = &g_fUniversalTime;
ConVar *mp_timelimit = NULL;
+int g_TimeLeftMode = 0;
ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds");
@@ -70,6 +71,11 @@ public:
m_bInUse = false;
}
+ void OnSourceModLevelChange(const char *mapName)
+ {
+ g_fGameStartTime = 0.0f;
+ }
+
int GetMapTimeLimit()
{
return mp_timelimit->GetInt();
@@ -88,18 +94,6 @@ public:
m_bInUse = enabled;
}
- bool GetMapTimeLeft(int *time_left)
- {
- if (GetMapTimeLimit() == 0)
- {
- return false;
- }
-
- *time_left = (int)((g_fMapStartTime + mp_timelimit->GetInt() * 60.0f) - g_fUniversalTime);
-
- return true;
- }
-
void ExtendMapTimeLimit(int extra_time)
{
extra_time /= 60;
@@ -176,6 +170,7 @@ void TimerSystem::OnSourceModAllInitialized()
{
g_ShareSys.AddInterface(NULL, this);
m_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL);
+ m_pOnMapTimeLeftChanged = g_Forwards.CreateForward("OnMapTimeLeftChanged", ET_Ignore, 0, NULL);
}
void TimerSystem::OnSourceModGameInitialized()
@@ -192,6 +187,7 @@ void TimerSystem::OnSourceModShutdown()
{
SetMapTimer(NULL);
g_Forwards.ReleaseForward(m_pOnGameFrame);
+ g_Forwards.ReleaseForward(m_pOnMapTimeLeftChanged);
}
void TimerSystem::OnSourceModLevelChange(const char *mapName)
@@ -216,11 +212,7 @@ void TimerSystem::GameFrame(bool simulating)
}
m_fLastTickedTime = gpGlobals->curtime;
- if (!m_bHasMapTickedYet)
- {
- g_fMapStartTime = g_fUniversalTime;
- m_bHasMapTickedYet = true;
- }
+ m_bHasMapTickedYet = true;
if (g_fUniversalTime - m_LastExecTime >= 0.1)
{
@@ -443,10 +435,28 @@ IMapTimer *TimerSystem::GetMapTimer()
void TimerSystem::MapTimeLeftChanged()
{
+ m_pOnMapTimeLeftChanged->Execute(NULL);
+}
+void TimerSystem::NotifyOfGameStart(float offset)
+{
+ g_fGameStartTime = gpGlobals->curtime + offset;
}
float TimerSystem::GetTickedTime()
{
return g_fUniversalTime;
}
+
+bool TimerSystem::GetMapTimeLeft(float *time_left)
+{
+ int time_limit;
+ if (!m_pMapTimer || (time_limit = m_pMapTimer->GetMapTimeLimit()) < 1)
+ {
+ return false;
+ }
+
+ *time_left = (g_fGameStartTime + time_limit * 60.0f) - gpGlobals->curtime;
+
+ return true;
+}
diff --git a/core/TimerSys.h b/core/TimerSys.h
index 84a3ede8..bc80c17e 100644
--- a/core/TimerSys.h
+++ b/core/TimerSys.h
@@ -77,6 +77,8 @@ public: //ITimerSystem
void MapTimeLeftChanged();
IMapTimer *SetMapTimer(IMapTimer *pTimer);
float GetTickedTime();
+ void NotifyOfGameStart(float offset /* = 0.0f */);
+ bool GetMapTimeLeft(float *pTime);
public:
void RunFrame();
void MapChange(bool real_mapchange);
@@ -96,12 +98,14 @@ private:
*/
IForward *m_pOnGameFrame;
+ IForward *m_pOnMapTimeLeftChanged;
};
time_t GetAdjustedTime(time_t *buf = NULL);
extern const float *g_pUniversalTime;
extern TimerSystem g_Timers;
+extern int g_TimeLeftMode;
#endif //_INCLUDE_SOURCEMOD_CTIMERSYS_H_
diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj
index 17102642..68db9142 100644
--- a/core/msvc8/sourcemod_mm.vcproj
+++ b/core/msvc8/sourcemod_mm.vcproj
@@ -298,6 +298,24 @@
+
+
+
+
+
+
LocalToPhysAddr(params[1], &addr);
- int time_left;
- if (!pMapTimer->GetMapTimeLeft(&time_left))
+ float time_left;
+ int int_time;
+ if (!g_Timers.GetMapTimeLeft(&time_left))
{
- time_left = -1;
+ int_time = -1;
+ }
+ else
+ {
+ int_time = (int)time_left;
}
- *addr = time_left;
+ *addr = int_time;
return true;
}
@@ -312,6 +310,11 @@ static cell_t smn_ExtendMapTimeLimit(IPluginContext *pContext, const cell_t *par
return 1;
}
+static cell_t smn_IsServerTicking(IPluginContext *pContext, const cell_t *params)
+{
+ return (gpGlobals->frametime > 0.0f) ? 1 : 0;
+}
+
REGISTER_NATIVES(timernatives)
{
{"CreateTimer", smn_CreateTimer},
@@ -321,5 +324,6 @@ REGISTER_NATIVES(timernatives)
{"GetMapTimeLeft", smn_GetMapTimeLeft},
{"GetMapTimeLimit", smn_GetMapTimeLimit},
{"ExtendMapTimeLimit", smn_ExtendMapTimeLimit},
+ {"IsServerTicking", smn_IsServerTicking},
{NULL, NULL}
};
diff --git a/extensions/cstrike/extension.cpp b/extensions/cstrike/extension.cpp
index e2787094..3c24e0e5 100644
--- a/extensions/cstrike/extension.cpp
+++ b/extensions/cstrike/extension.cpp
@@ -31,15 +31,20 @@
#include "extension.h"
#include "RegNatives.h"
+#include "timeleft.h"
/**
* @file extension.cpp
* @brief Implement extension code here.
*/
+SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
+
CStrike g_CStrike; /**< Global singleton for extension's main interface */
IBinTools *g_pBinTools = NULL;
IGameConfig *g_pGameConf = NULL;
+IGameEventManager2 *gameevents = NULL;
+bool hooked_everything = false;
SMEXT_LINK(&g_CStrike);
@@ -49,8 +54,13 @@ bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
sharesys->AddDependency(myself, "bintools.ext", true, true);
- if (!gameconfs->LoadGameConfigFile("sm-cstrike.games", &g_pGameConf, error, maxlength))
+ char conf_error[255];
+ if (!gameconfs->LoadGameConfigFile("sm-cstrike.games", &g_pGameConf, conf_error, sizeof(conf_error)))
{
+ if (error)
+ {
+ snprintf(error, maxlength, "Could not read sm-cstrike.games.txt: %s", conf_error);
+ }
return false;
}
@@ -59,14 +69,33 @@ bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late)
return true;
}
+bool CStrike::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
+{
+ GET_V_IFACE_CURRENT(engineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2);
+ GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
+
+ return true;
+}
+
void CStrike::SDK_OnUnload()
{
+ if (hooked_everything)
+ {
+ gameevents->RemoveListener(&g_TimeLeftEvents);
+ SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, &g_TimeLeftEvents, &TimeLeftEvents::LevelInit, true);
+ hooked_everything = false;
+ }
g_RegNatives.UnregisterAll();
gameconfs->CloseGameConfigFile(g_pGameConf);
}
void CStrike::SDK_OnAllLoaded()
{
+ gameevents->AddListener(&g_TimeLeftEvents, "round_start", true);
+ gameevents->AddListener(&g_TimeLeftEvents, "round_end", true);
+ SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, &g_TimeLeftEvents, &TimeLeftEvents::LevelInit, true);
+ hooked_everything = true;
+
SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
}
diff --git a/extensions/cstrike/extension.h b/extensions/cstrike/extension.h
index 0f2b87f1..916bb2d2 100644
--- a/extensions/cstrike/extension.h
+++ b/extensions/cstrike/extension.h
@@ -94,7 +94,7 @@ public:
* @param late Whether or not Metamod considers this a late load.
* @return True to succeed, false to fail.
*/
- //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late);
+ virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late);
/**
* @brief Called when Metamod is detaching, after the extension version is called.
diff --git a/extensions/cstrike/msvc8/cstrike.vcproj b/extensions/cstrike/msvc8/cstrike.vcproj
index 6394bcf6..70ddd817 100644
--- a/extensions/cstrike/msvc8/cstrike.vcproj
+++ b/extensions/cstrike/msvc8/cstrike.vcproj
@@ -1,7 +1,7 @@
+
+
+
+
+
+
.
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id: svn_version.h 1336 2007-08-15 06:19:30Z damagedsoul $
+ */
+
+/**
+ * Autogenerated by build scripts
+ */
+
+#ifndef _INCLUDE_SDKTOOLS_VERSION_H_
+#define _INCLUDE_SDKTOOLS_VERSION_H_
+
+#define SVN_FULL_VERSION "1.0.0.1336"
+#define SVN_FILE_VERSION 1,0,0,1336
+
+#endif //_INCLUDE_SDKTOOLS_VERSION_H_
diff --git a/extensions/cstrike/svn_version.tpl b/extensions/cstrike/svn_version.tpl
new file mode 100644
index 00000000..ad458193
--- /dev/null
+++ b/extensions/cstrike/svn_version.tpl
@@ -0,0 +1,42 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourceMod SDKTools Extension
+ * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id$
+ */
+
+/**
+ * Autogenerated by build scripts
+ */
+
+#ifndef _INCLUDE_SDKTOOLS_VERSION_H_
+#define _INCLUDE_SDKTOOLS_VERSION_H_
+
+#define SVN_FULL_VERSION "$PMAJOR$.$PMINOR$.$PREVISION$.$LOCAL_BUILD$"
+#define SVN_FILE_VERSION $PMAJOR$,$PMINOR$,$PREVISION$,$LOCAL_BUILD$
+
+#endif //_INCLUDE_SDKTOOLS_VERSION_H_
diff --git a/extensions/cstrike/timeleft.cpp b/extensions/cstrike/timeleft.cpp
new file mode 100644
index 00000000..ce0c82b5
--- /dev/null
+++ b/extensions/cstrike/timeleft.cpp
@@ -0,0 +1,43 @@
+#include "extension.h"
+#include "timeleft.h"
+
+TimeLeftEvents g_TimeLeftEvents;
+bool get_new_timeleft_offset = false;
+bool round_end_found = false;
+
+bool TimeLeftEvents::LevelInit(char const *pMapName,
+ char const *pMapEntities,
+ char const *pOldLevel,
+ char const *pLandmarkName,
+ bool loadGame,
+ bool background)
+{
+ round_end_found = true;
+ get_new_timeleft_offset = false;
+
+ return true;
+}
+
+void TimeLeftEvents::FireGameEvent(IGameEvent *event)
+{
+ const char *name = event->GetName();
+
+ if (strcmp(name, "round_start") == 0)
+ {
+ if (get_new_timeleft_offset || !round_end_found)
+ {
+ get_new_timeleft_offset = false;
+ timersys->NotifyOfGameStart();
+ timersys->MapTimeLeftChanged();
+ }
+ round_end_found = false;
+ }
+ else if (strcmp(name, "round_end") == 0)
+ {
+ if (event->GetInt("reason") == 16)
+ {
+ get_new_timeleft_offset = true;
+ }
+ round_end_found = true;
+ }
+}
diff --git a/extensions/cstrike/timeleft.h b/extensions/cstrike/timeleft.h
new file mode 100644
index 00000000..7fa7b60c
--- /dev/null
+++ b/extensions/cstrike/timeleft.h
@@ -0,0 +1,17 @@
+#ifndef _INCLUDE_SOURCEMOD_CSTRIKE_EVENTS_H_
+#define _INCLUDE_SOURCEMOD_CSTRIKE_EVENTS_H_
+
+#include
+#include
+
+class TimeLeftEvents : public IGameEventListener2
+{
+public:
+ bool LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
+ virtual void FireGameEvent(IGameEvent *event);
+};
+
+extern TimeLeftEvents g_TimeLeftEvents;
+
+#endif //_INCLUDE_SOURCEMOD_CSTRIKE_EVENTS_H_
+
diff --git a/extensions/cstrike/version.rc b/extensions/cstrike/version.rc
new file mode 100644
index 00000000..37d14dad
--- /dev/null
+++ b/extensions/cstrike/version.rc
@@ -0,0 +1,104 @@
+// Microsoft Visual C++ generated resource script.
+//
+//#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+#include "svn_version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION SVN_FILE_VERSION
+ PRODUCTVERSION SVN_FILE_VERSION
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "Comments", "SourceMod CS:S Extension"
+ VALUE "FileDescription", "SourceMod CS:S Extension"
+ VALUE "FileVersion", SVN_FULL_VERSION
+ VALUE "InternalName", "SourceMod CS:S Extension"
+ VALUE "LegalCopyright", "Copyright (c) 2004-2007, AlliedModders LLC"
+ VALUE "OriginalFilename", "game.cstrike.ext.dll"
+ VALUE "ProductName", "SourceMod CS:S Extension"
+ VALUE "ProductVersion", SVN_FULL_VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc
index 50c64658..3d7e0e4a 100644
--- a/plugins/include/cstrike.inc
+++ b/plugins/include/cstrike.inc
@@ -39,8 +39,13 @@
#define CS_TEAM_NONE 0 /**< No team yet. */
#define CS_TEAM_SPECTATOR 1 /**< Spectators. */
-#define CS_TEAM_T 2 /**< Terrorists. */
-#define CS_TEAM_CT 3 /**< Counter-Terrorists. */
+#define CS_TEAM_T 2 /**< Terrorists. */
+#define CS_TEAM_CT 3 /**< Counter-Terrorists. */
+
+#define CS_SLOT_PRIMARY 0 /**< Primary weapon slot. */
+#define CS_SLOT_SECONDARY 1 /**< Secondary weapon slot. */
+#define CS_SLOT_GRENADE 3 /**< Grenade slot (will only return one grenade). */
+#define CS_SLOT_C4 4 /**< C4 slot. */
/**
* Respawns a player.
@@ -67,7 +72,7 @@ native CS_SwitchTeam(client, team);
public Extension:__ext_cstrike =
{
name = "CStrike",
- file = "game.cstrike.ext",
+ file = "games/game.cstrike.ext",
#if defined AUTOLOAD_EXTENSIONS
autoload = 1,
#else
@@ -78,4 +83,4 @@ public Extension:__ext_cstrike =
#else
required = 0,
#endif
-};
\ No newline at end of file
+};
diff --git a/plugins/include/timers.inc b/plugins/include/timers.inc
index c1758a0c..81ca5fb9 100644
--- a/plugins/include/timers.inc
+++ b/plugins/include/timers.inc
@@ -160,6 +160,17 @@ native bool:ExtendMapTimeLimit(time);
*/
forward OnMapTimeLeftChanged();
+/**
+ * Returns whether or not the server is processing frames or not.
+ *
+ * The server does not process frames until at least one client joins the game.
+ * Once the first player has in, even if that player, leaves, the server's
+ * timers and entities will work.
+ *
+ * @return True if the server is ticking, false otherwise.
+ */
+native bool:IsServerProcessing();
+
/**
* Creates a timer associated with a new data pack, and returns the datapack.
* @note The datapack is automatically freed when the timer ends.
diff --git a/public/ITimerSystem.h b/public/ITimerSystem.h
index 28eae204..00fa57bb 100644
--- a/public/ITimerSystem.h
+++ b/public/ITimerSystem.h
@@ -42,7 +42,7 @@
#include
#define SMINTERFACE_TIMERSYS_NAME "ITimerSys"
-#define SMINTERFACE_TIMERSYS_VERSION 1
+#define SMINTERFACE_TIMERSYS_VERSION 3
namespace SourceMod
{
@@ -62,15 +62,6 @@ namespace SourceMod
*/
virtual int GetMapTimeLimit() =0;
- /**
- * Returns how much time is left in the map.
- *
- * @param time_left Pointer to store time, in seconds.
- * @return True if there is a time limit, false
- * if the time limit is 0.
- */
- virtual bool GetMapTimeLeft(int *time_left) =0;
-
/**
* Extends the map limit (either positively or negatively) in seconds.
*
@@ -194,6 +185,23 @@ namespace SourceMod
* @return Universal ticked time.
*/
virtual float GetTickedTime() =0;
+
+ /**
+ * @brief Notification that the "starting point" in the game has has
+ * changed. This does not invoke MapTimeLeftChanged() automatically.
+ *
+ * @param offset Optional offset to add to the new time.
+ */
+ virtual void NotifyOfGameStart(float offset = 0.0f) =0;
+
+ /**
+ * @brief Returns the time left in the map.
+ *
+ * @param pTime Pointer to store time left, in seconds.
+ * @return True on success, false if there no time limit
+ * or if the time limit could not be determined.
+ */
+ virtual bool GetMapTimeLeft(float *pTime) =0;
};
}