This repository has been archived by the owner on Feb 2, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
xms.sp
350 lines (304 loc) · 14.8 KB
/
xms.sp
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#pragma dynamic 2097152
#pragma semicolon 1
#pragma newdecls required
#define PLUGIN_VERSION "1.95"
#define PLUGIN_URL "www.hl2dm.community"
#define PLUGIN_UPDATE "http://raw.githubusercontent.com/utharper/sourcemod-hl2dm/master/addons/sourcemod/xms.upd"
#define PLUGIN_CONFLICT {"mapchooser", "nominations", "rockthevote", "randomcycle"}
public Plugin myinfo = {
name = "XMS - eXtended Match System",
version = PLUGIN_VERSION,
description = "Multi-gamemode server plugin for competitive HL2DM servers",
author = "harper",
url = PLUGIN_URL
};
/**************************************************************
* INCLUDES
*************************************************************/
#include <sourcemod>
#include <clientprefs>
#include <steamtools>
#include <smlib>
#include <sdkhooks>
#include <entitylump>
#include <vphysics>
#include <morecolors>
#include <basecomm>
#undef REQUIRE_PLUGIN
#include <updater>
#include <gameme_hud>
#define REQUIRE_PLUGIN
#include <jhl2dm>
#include <xms>
/**************************************************************
* GLOBAL VARS
*************************************************************/
enum struct _gConVar
{
ConVar sv_tags;
ConVar mp_timelimit;
ConVar mp_teamplay;
ConVar mp_chattime;
ConVar mp_friendlyfire;
ConVar sv_pausable;
ConVar tv_enable;
ConVar sm_nextmap;
ConVar mp_restartgame;
ConVar mp_forcerespawn;
}
_gConVar gConVar;
enum struct _gPath
{
char sConfig [PLATFORM_MAX_PATH];// Path to XMS.cfg
char sFeedback [PLATFORM_MAX_PATH];// Path to feedback.log
char sDemo [PLATFORM_MAX_PATH];// Path to demos folder
char sDemoWeb [PLATFORM_MAX_PATH];// URL of demos folder on webserver
char sDemoWebExt [8]; // File extension for demos on webserver
}
_gPath gPath;
enum struct _gCore
{
bool bLan; // Server is running on LAN?
char sIPAddr[16]; // IP address of server
int iPort; // Primary port of server (typically 27015)
KeyValues kConfig; // Raw values of xms.cfg
char sServerName [32]; // Name of the server.
char sServerMessage [192]; // Custom message shown in menu
char sGamemodes [512]; // Comma-seperated list of available modes
char sRetainModes [512]; // Never revert to default map when changing between these modes
char sDefaultMode [MAX_MODE_LENGTH]; // Default mode
int iRevertTime; // How long after last player disconnects to reset server (seconds)
char sEmptyMapcycle [PLATFORM_MAX_PATH];// Mapcycle override when server is empty
bool bReady; // Plugin is properly initialised ?
bool bChangingTags; // Plugin is setting sv_tags value ?
bool bRanked; // gameME stats integration active ?
int iAdFrequency; // How often to display chat advertisements (seconds)
int iMapChanges; // Total number of map changes since plugin loaded.
char sRemoveMapPrefix[512]; // Hide these map prefixes (eg dm_) for simplicity and to save text space.
}
_gCore gCore;
enum struct _gForward
{
Handle hGamestateChanged; // OnGamestateChanged
Handle hMatchStarted; // OnMatchStart
Handle hMatchEnded; // OnMatchEnd
Handle hFeedback; // OnClientFeedback
}
_gForward gForward;
enum struct _gSounds
{
Cookie cMusic; // End of round music cookie (enabled/disabled)
Cookie cMisc; // General sounds cookie (enabled/disabled)
}
_gSounds gSounds;
enum struct _gVoting
{
int iMinPlayers; // Minimum clients to enable manual voting
int iMaxTime; // Maximum voting period (seconds)
int iElapsed; // Current vote time elapsed (seconds)
int iCooldown; // Seconds until a client can call a new vote
int iType; // Current vote type
int iStatus; // Current vote status
int iOptions;
bool bAutomatic; // Automatically call a vote after round ?
}
_gVoting gVoting;
enum struct _gHud
{
bool bSelfKeys; // Show keys HUD to non-spectators ?
Handle hTime; // Timeleft HUD element
Handle hKeys; // Pressed Keys HUD element
Handle hVote; // Voting HUD element
Handle cColors [3]; // HUD color cookies {r,g,b}
}
_gHud gHud;
enum struct _gRound
{
char sUID [128]; // Unique game ID from timestamp and map.
char sMap [MAX_MAP_LENGTH]; // Map name
char sMode [MAX_MODE_LENGTH]; // Mode name
char sModeDescription[32]; // Full mode name
float fStartTime; // GameTime at start of round
float fEndTime; // GameTime at end of round (set at chattime)
bool bTeamplay; // Safe teamplay check
int iState; // Current gamestate (see xms.inc)
bool bRecording; // Is SourceTV recording ?
int iSpawnHealth; // Custom spawn health value (-1 if not defined)
int iSpawnArmor; // Custom spawn suit value (-1 if not defined)
bool bReplenish; // Replenish health/suit to (at least) spawn values on player kill?
bool bDisableProps; // Remove props from map ?
bool bDisableCollisions; // Disable player collisions ?
bool bUnlimitedAux; // Unlimited player aux (sprint) power ?
bool bOvertime; // Overtime enabled ?
Handle hOvertime; // Handle for Overtime timer
StringMap mTeams; // Map client SteamIDs to their team
char sNextMap [MAX_MAP_LENGTH]; // Next map if chosen
char sNextMode [MAX_MODE_LENGTH]; // Next mode
}
_gRound gRound;
enum struct _gClient
{
bool bReady; // Client initalised (post team assignment) ?
bool bForceKilled; // Player killed by plugin ?
int iMenuStatus; // Client menu status (0 = none, 1 = attempting, 2 = loaded)
int iMenuRefresh; // Time in seconds until next menu refresh attempt
StringMap mMenu; // Current values for XMenuDisplay
int iVote; // Choice for the current vote
int iVoteTick; // Tick when client last called a vote (to comply with gVoting.iCooldown)
}
_gClient gClient [MAXPLAYERS + 1];
enum struct _gSpecialClient
{
int iAllowed; // Client allowed to switch teams during match.
int iPauser; // Client with ownership of pause state.
}
_gSpecialClient gSpecialClient;
/**************************************************************
* COMPONENTS
*************************************************************/
#include "xms/natives_forwards.sp" // Natives and forwards for extending functionality (custom gamemodes, etc)
#include "xms/sounds.sp" // Sound functions
#include "xms/gamemod.sp" // Functions to modify game/engine behaviour
#include "xms/mapmode.sp" // Map and gamemode management functions
#include "xms/round.sp" // Game round & overtime functions
#include "xms/clients.sp" // General client functions
#include "xms/teams.sp" // Team management functions
#include "xms/voting.sp" // Voting functions
#include "xms/xconfig.sp" // Natives and functions to read and parse the XMS config.
#include "xms/xmenu.sp" // Natives and functions to manage the custom XMS menu system.
#include "xms/legacy_menu.sp" // SourceMod menu functions for voting and !model popups (no way found to force-update XMenu)
#include "xms/hud.sp" // HUD text elements (timeleft, pressed keys, etc)
#include "xms/sourcetv.sp" // SourceTV management
#include "xms/announcements.sp" // Plugin announcements and advertisements.
#include "xms/commands.sp" // Plugin commands and command overrides.
/**************************************************************
* CORE
*************************************************************/
public APLRes AskPluginLoad2(Handle hPlugin, bool bLate, char[] sError, int iLen)
{
CreateNative("GetConfigKeys", Native_GetConfigKeys);
CreateNative("GetConfigString", Native_GetConfigString);
CreateNative("GetConfigInt", Native_GetConfigInt);
CreateNative("GetGamestate", Native_GetGamestate);
CreateNative("GetGamemode", Native_GetGamemode);
CreateNative("GetTimeRemaining", Native_GetTimeRemaining);
CreateNative("GetTimeElapsed", Native_GetTimeElapsed);
CreateNative("GetGameID", Native_GetGameID);
CreateNative("XMenu", Native_XMenu);
CreateNative("XMenuQuick", Native_XMenuQuick);
CreateNative("XMenuBox", Native_XMenuBox);
gForward.hMatchStarted = CreateGlobalForward("OnMatchStart", ET_Event);
gForward.hMatchEnded = CreateGlobalForward("OnMatchEnd", ET_Event, Param_Cell);
gForward.hGamestateChanged = CreateGlobalForward("OnGamestateChanged", ET_Event, Param_Cell , Param_Cell);
gForward.hFeedback = CreateGlobalForward("OnClientFeedback", ET_Event, Param_String, Param_String, Param_String, Param_String);
RegPluginLibrary("xms");
return APLRes_Success;
}
public void OnPluginStart()
{
CreateConVar("xms_version", PLUGIN_VERSION, _, FCVAR_NOTIFY);
BuildPath(Path_SM, gPath.sConfig, PLATFORM_MAX_PATH, "configs/xms.cfg");
BuildPath(Path_SM, gPath.sFeedback, PLATFORM_MAX_PATH, "logs/feedback.log");
LoadTranslations("common.phrases.txt");
LoadTranslations("xms.phrases.txt");
LoadTranslations("xms_menu.phrases.txt");
FindConVar("ip").GetString(gCore.sIPAddr, sizeof(gCore.sIPAddr));
gCore.iPort = FindConVar("hostport").IntValue;
gCore.bLan = FindConVar("sv_lan").BoolValue;
gConVar.tv_enable = FindConVar("tv_enable");
gConVar.sv_pausable = FindConVar("sv_pausable");
gConVar.mp_teamplay = FindConVar("mp_teamplay");
gConVar.mp_chattime = FindConVar("mp_chattime");
gConVar.mp_friendlyfire = FindConVar("mp_friendlyfire");
gConVar.mp_restartgame = FindConVar("mp_restartgame");
gConVar.mp_forcerespawn = FindConVar("mp_forcerespawn");
gConVar.sm_nextmap = FindConVar("sm_nextmap");
gConVar.sv_tags = FindConVar("sv_tags");
gConVar.mp_timelimit = FindConVar("mp_timelimit");
gConVar.mp_restartgame . AddChangeHook(OnGameRestarting);
gConVar.sm_nextmap . AddChangeHook(OnNextmapChanged);
gConVar.sv_tags . AddChangeHook(OnTagsChanged);
gConVar.mp_timelimit . AddChangeHook(OnTimelimitChanged);
gHud.cColors[0] = RegClientCookie("hudcolor_r", "HUD color red value", CookieAccess_Public);
gHud.cColors[1] = RegClientCookie("hudcolor_g", "HUD color green value", CookieAccess_Public);
gHud.cColors[2] = RegClientCookie("hudcolor_b", "HUD color blue value", CookieAccess_Public);
gSounds.cMusic = RegClientCookie("xms_endmusic", "Enable end of game music", CookieAccess_Public);
gSounds.cMisc = RegClientCookie("xms_miscsounds", "Enable beeps & misc XMS sounds", CookieAccess_Public);
gRound.hOvertime = INVALID_HANDLE;
gRound.mTeams = CreateTrie();
gHud.hKeys = CreateHudSynchronizer();
gHud.hTime = CreateHudSynchronizer();
gHud.hVote = CreateHudSynchronizer();
LoadConfigValues();
MC_AddJColors();
HookEvents();
RegisterCommands();
CreateTimer(0.1, T_KeysHud, _, TIMER_REPEAT);
CreateTimer(0.1, T_TimeHud, _, TIMER_REPEAT);
CreateTimer(1.0, T_Voting, _, TIMER_REPEAT);
CreateTimer(1.0, T_MenuRefresh, _, TIMER_REPEAT);
AddPluginTags();
if (gCore.iAdFrequency) {
CreateTimer(float(gCore.iAdFrequency), T_Adverts, _, TIMER_REPEAT);
}
if (LibraryExists("updater")) {
Updater_AddPlugin(PLUGIN_UPDATE);
}
if (LibraryExists("gameme_hud")) {
gCore.bRanked = true;
}
}
public void OnTagsChanged(Handle hConvar, const char[] sOldValue, const char[] sNewValue)
{
if (!gCore.bChangingTags) {
AddPluginTags();
}
}
void AddPluginTags()
{
char sTags[128];
gConVar.sv_tags.GetString(sTags, sizeof(sTags));
if (StrContains(sTags, "XMS") == -1)
{
Format(sTags, sizeof(sTags), "%s%sXMS,%s", sTags, sTags[0] != 0 ? "," : "", gCore.sGamemodes);
gCore.bChangingTags = true;
gConVar.sv_tags.SetString(sTags);
gCore.bChangingTags = false;
}
}
public void OnLibraryAdded(const char[] sName)
{
if (StrEqual(sName, "updater")) {
Updater_AddPlugin(PLUGIN_UPDATE);
}
if (StrEqual(sName, "gameme_hud")) {
gCore.bRanked = true;
}
}
public void OnLibraryRemoved(const char[] sName)
{
if (StrEqual(sName, "gameme_hud")) {
gCore.bRanked = false;
}
}
public void OnAllPluginsLoaded()
{
if (!LibraryExists("xfix")) {
LogError("xFix is not loaded !");
}
if (!gCore.bReady)
{
// Warn about conflicting plugins.
char sConflict[][32] = PLUGIN_CONFLICT;
for (int i = 0; i < sizeof(sConflict); i++)
{
char sPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, sizeof(sPath), "plugins/%s.smx", sConflict[i]);
if (FileExists(sPath)) {
LogError("Plugin %s conflicts with xms and should be disabled!", sConflict[i]);
}
}
// Restart on first load - avoids issues with SourceTV (etc)
CreateTimer(2.0, T_RestartMap, _, TIMER_FLAG_NO_MAPCHANGE);
}
}