Skip to content

Commit a7e3835

Browse files
committed
Add gamemode/subgroup limits and time checks
Add natives and APIs to retrieve player/time limits for gamemodes and subgroups (MultiMode_GetGamemodeLimits, MultiMode_GetSubGroupLimits) and declare them in the include. Implement the natives in multimode_core.sp to return min/max players and min/max time values from GameModeConfig/SubGroupConfig. Add a GESTURE_EXCLUDED_TIME gesture string and update nomination menus to use the new natives, include time-based restriction checks (MMC_IsTimeAllowed), and unify/rename limit handling (exceedsLimit/limitGesture). Map nomination logic now prefers subgroup limits and falls back to gamemode limits. These changes centralize limit retrieval and add support for time-restricted exclusions in the UI.
1 parent 78c5a81 commit a7e3835

4 files changed

Lines changed: 127 additions & 78 deletions

File tree

addons/sourcemod/scripting/include/multimode.inc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,31 @@ native bool MultiMode_IsMapRecentlyPlayed(const char[] gamemode, const char[] ma
363363
*/
364364
native bool MultiMode_IsSubGroupRecentlyPlayed(const char[] gamemode, const char[] subgroup, int excludeCount = 0);
365365

366+
/**
367+
* Gets the player/time limits for a gamemode.
368+
*
369+
* @param gamemode Gamemode name.
370+
* @param minPlayers Reference to store the minimum players (0 = no limit).
371+
* @param maxPlayers Reference to store the maximum players (0 = no limit).
372+
* @param minTime Reference to store the minimum time in HHMM format (-1 = no limit).
373+
* @param maxTime Reference to store the maximum time in HHMM format (-1 = no limit).
374+
* @return True if the gamemode was found, false otherwise.
375+
*/
376+
native bool MultiMode_GetGamemodeLimits(const char[] gamemode, int &minPlayers, int &maxPlayers, int &minTime, int &maxTime);
377+
378+
/**
379+
* Gets the player/time limits for a subgroup.
380+
*
381+
* @param gamemode Gamemode name.
382+
* @param subgroup Subgroup name.
383+
* @param minPlayers Reference to store the minimum players (0 = no limit).
384+
* @param maxPlayers Reference to store the maximum players (0 = no limit).
385+
* @param minTime Reference to store the minimum time in HHMM format (-1 = no limit).
386+
* @param maxTime Reference to store the maximum time in HHMM format (-1 = no limit).
387+
* @return True if the subgroup was found, false otherwise.
388+
*/
389+
native bool MultiMode_GetSubGroupLimits(const char[] gamemode, const char[] subgroup, int &minPlayers, int &maxPlayers, int &minTime, int &maxTime);
390+
366391
/**
367392
* Called when a vote starts.
368393
*

addons/sourcemod/scripting/include/multimode/utils.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define GESTURE_EXCLUDED " (Excluded)" // For global exclusion gesture.
2121
#define GESTURE_EXCLUDED_PLAYERLIMIT_MINIMUM " (Minimum %d Players)" // For global player limit minimum exclusion gesture.
2222
#define GESTURE_EXCLUDED_PLAYERLIMIT_MAX " (Max %d Players)" // For global player limit maximum exclusion gesture.
23+
#define GESTURE_EXCLUDED_TIME " (Time Restricted)" // For global time restriction exclusion gesture.
2324

2425
/**
2526
* Fills buffer with the current map cycle filename (from multimode_mapcycle convar).

addons/sourcemod/scripting/multimode_core.sp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
276276
CreateNative("MultiMode_IsSubGroupRecentlyPlayed", NativeMMC_IsSubGroupRecentlyPlayed);
277277
CreateNative("MultiMode_GetCurrentVoteId", NativeMMC_GetCurrentVoteId);
278278
CreateNative("MultiMode_SetNextMap", NativeMMC_SetNextMap);
279+
CreateNative("MultiMode_GetGamemodeLimits", NativeMMC_GetGamemodeLimits);
280+
CreateNative("MultiMode_GetSubGroupLimits", NativeMMC_GetSubGroupLimits);
279281

280282
RegPluginLibrary("multimode_core");
281283
return APLRes_Success;
@@ -2775,6 +2777,51 @@ public int NativeMMC_SetNextMap(Handle plugin, int numParams)
27752777
return true;
27762778
}
27772779

2780+
public int NativeMMC_GetGamemodeLimits(Handle plugin, int numParams)
2781+
{
2782+
char gamemode[64];
2783+
GetNativeString(1, gamemode, sizeof(gamemode));
2784+
2785+
int index = MMC_FindGameModeIndex(gamemode);
2786+
if (index == -1)
2787+
return false;
2788+
2789+
GameModeConfig config;
2790+
GetGameModesList().GetArray(index, config);
2791+
2792+
SetNativeCellRef(2, config.minplayers);
2793+
SetNativeCellRef(3, config.maxplayers);
2794+
SetNativeCellRef(4, config.mintime);
2795+
SetNativeCellRef(5, config.maxtime);
2796+
return true;
2797+
}
2798+
2799+
public int NativeMMC_GetSubGroupLimits(Handle plugin, int numParams)
2800+
{
2801+
char gamemode[64], subgroup[64];
2802+
GetNativeString(1, gamemode, sizeof(gamemode));
2803+
GetNativeString(2, subgroup, sizeof(subgroup));
2804+
2805+
int gIndex = MMC_FindGameModeIndex(gamemode);
2806+
if (gIndex == -1)
2807+
return false;
2808+
2809+
int sIndex = MMC_FindSubGroupIndex(gamemode, subgroup);
2810+
if (sIndex == -1)
2811+
return false;
2812+
2813+
GameModeConfig config;
2814+
GetGameModesList().GetArray(gIndex, config);
2815+
SubGroupConfig subConfig;
2816+
config.subGroups.GetArray(sIndex, subConfig);
2817+
2818+
SetNativeCellRef(3, subConfig.minplayers);
2819+
SetNativeCellRef(4, subConfig.maxplayers);
2820+
SetNativeCellRef(5, subConfig.mintime);
2821+
SetNativeCellRef(6, subConfig.maxtime);
2822+
return true;
2823+
}
2824+
27782825
void NativeMMC_OnVoteStart(int initiator)
27792826
{
27802827
Call_StartForward(g_OnVoteStartForward);

addons/sourcemod/scripting/multimode_nominations.sp

Lines changed: 54 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -329,20 +329,21 @@ void ShowNominateGamemodeMenu(int client)
329329
bool isRecentlyPlayed = (groupExclude > 0 && MultiMode_IsGamemodeRecentlyPlayed(gamemode, groupExclude));
330330
bool canNominate = MMC_CanClientNominate(client, gamemode);
331331

332+
int minP = 0, maxP = 0, minT = -1, maxT = -1;
333+
MultiMode_GetGamemodeLimits(gamemode, minP, maxP, minT, maxT);
332334
int players = GetRealClientCount();
333-
bool exceedsPlayerLimit = false;
334-
char playerLimitGesture[32];
335-
int gIndex = MMC_FindGameModeIndex(gamemode);
336-
if (gIndex != -1) {
337-
GameModeConfig gmCfg;
338-
GetGameModesList().GetArray(gIndex, gmCfg);
339-
if (gmCfg.minplayers > 0 && players < gmCfg.minplayers) {
340-
exceedsPlayerLimit = true;
341-
Format(playerLimitGesture, sizeof(playerLimitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MINIMUM, gmCfg.minplayers);
342-
} else if (gmCfg.maxplayers > 0 && players > gmCfg.maxplayers) {
343-
exceedsPlayerLimit = true;
344-
Format(playerLimitGesture, sizeof(playerLimitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MAX, gmCfg.maxplayers);
345-
}
335+
bool exceedsLimit = false;
336+
char limitGesture[32];
337+
338+
if (!MMC_IsTimeAllowed(minT, maxT)) {
339+
exceedsLimit = true;
340+
strcopy(limitGesture, sizeof(limitGesture), GESTURE_EXCLUDED_TIME);
341+
} else if (minP > 0 && players < minP) {
342+
exceedsLimit = true;
343+
Format(limitGesture, sizeof(limitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MINIMUM, minP);
344+
} else if (maxP > 0 && players > maxP) {
345+
exceedsLimit = true;
346+
Format(limitGesture, sizeof(limitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MAX, maxP);
346347
}
347348

348349
char display[128];
@@ -352,9 +353,9 @@ void ShowNominateGamemodeMenu(int client)
352353
Format(display, sizeof(display), "%s%s", gamemode, GESTURE_EXCLUDED);
353354
menu.AddItem(gamemode, display, ITEMDRAW_DISABLED);
354355
}
355-
else if (exceedsPlayerLimit)
356+
else if (exceedsLimit)
356357
{
357-
Format(display, sizeof(display), "%s%s", gamemode, playerLimitGesture);
358+
Format(display, sizeof(display), "%s%s", gamemode, limitGesture);
358359
menu.AddItem(gamemode, display, ITEMDRAW_DISABLED);
359360
}
360361
else if (g_Cvar_Nominate_NominateSelectedGroupExclude.BoolValue && isNominated)
@@ -447,23 +448,21 @@ void ShowNominateSubGroupMenu(int client, const char[] gamemode)
447448
bool isRecentlyPlayed = (subgroupExclude > 0 && MultiMode_IsSubGroupRecentlyPlayed(gamemode, subgroup, subgroupExclude));
448449
bool canNominate = MMC_CanClientNominate(client, gamemode, subgroup);
449450

451+
int minP = 0, maxP = 0, minT = -1, maxT = -1;
452+
MultiMode_GetSubGroupLimits(gamemode, subgroup, minP, maxP, minT, maxT);
450453
int players = GetRealClientCount();
451-
bool exceedsPlayerLimit = false;
452-
char playerLimitGesture[32];
453-
int gIdx = MMC_FindGameModeIndex(gamemode);
454-
int sIdx = MMC_FindSubGroupIndex(gamemode, subgroup);
455-
if (gIdx != -1 && sIdx != -1) {
456-
GameModeConfig gmCfg;
457-
GetGameModesList().GetArray(gIdx, gmCfg);
458-
SubGroupConfig subCfg;
459-
gmCfg.subGroups.GetArray(sIdx, subCfg);
460-
if (subCfg.minplayers > 0 && players < subCfg.minplayers) {
461-
exceedsPlayerLimit = true;
462-
Format(playerLimitGesture, sizeof(playerLimitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MINIMUM, subCfg.minplayers);
463-
} else if (subCfg.maxplayers > 0 && players > subCfg.maxplayers) {
464-
exceedsPlayerLimit = true;
465-
Format(playerLimitGesture, sizeof(playerLimitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MAX, subCfg.maxplayers);
466-
}
454+
bool exceedsLimit = false;
455+
char limitGesture[32];
456+
457+
if (!MMC_IsTimeAllowed(minT, maxT)) {
458+
exceedsLimit = true;
459+
strcopy(limitGesture, sizeof(limitGesture), GESTURE_EXCLUDED_TIME);
460+
} else if (minP > 0 && players < minP) {
461+
exceedsLimit = true;
462+
Format(limitGesture, sizeof(limitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MINIMUM, minP);
463+
} else if (maxP > 0 && players > maxP) {
464+
exceedsLimit = true;
465+
Format(limitGesture, sizeof(limitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MAX, maxP);
467466
}
468467

469468
char display[128];
@@ -473,9 +472,9 @@ void ShowNominateSubGroupMenu(int client, const char[] gamemode)
473472
Format(display, sizeof(display), "%s%s", subgroup, GESTURE_EXCLUDED);
474473
menu.AddItem(subgroup, display, ITEMDRAW_DISABLED);
475474
}
476-
else if (exceedsPlayerLimit)
475+
else if (exceedsLimit)
477476
{
478-
Format(display, sizeof(display), "%s%s", subgroup, playerLimitGesture);
477+
Format(display, sizeof(display), "%s%s", subgroup, limitGesture);
479478
menu.AddItem(subgroup, display, ITEMDRAW_DISABLED);
480479
}
481480
else if (g_Cvar_Nominate_NominateSelectedGroupExclude.BoolValue && isNominated)
@@ -579,52 +578,29 @@ void ShowNominateMapMenu(int client, const char[] gamemode, const char[] subgrou
579578
bool isRecentlyPlayed = (mapExclude > 0 && MultiMode_IsMapRecentlyPlayed(gamemode, map, subgroup, mapExclude));
580579
bool canNominate = MMC_CanClientNominate(client, gamemode, subgroup, map) && !MMC_IsMapAdminOnly(gamemode, map, subgroup);
581580

582-
int players = GetRealClientCount();
583-
bool exceedsPlayerLimit = false;
584-
char playerLimitGesture[32];
585-
int minP = 0, maxP = 0;
586-
587-
KeyValues mapKv = null;
588-
if (strlen(subgroup) > 0)
589-
mapKv = MMC_GetSubGroupMapKv(g_kvGameModes, gamemode, subgroup, map);
590-
else
591-
mapKv = MMC_GetMapKv(g_kvGameModes, gamemode, map);
592-
593-
if (mapKv != null) {
594-
minP = mapKv.GetNum(MAPCYCLE_KEY_MINPLAYERS, 0);
595-
maxP = mapKv.GetNum(MAPCYCLE_KEY_MAXPLAYERS, 0);
596-
delete mapKv;
597-
}
598-
599-
if (minP == 0 && maxP == 0 && strlen(subgroup) > 0) {
600-
int sgIdx = MMC_FindSubGroupIndex(gamemode, subgroup);
601-
int gIdx = MMC_FindGameModeIndex(gamemode);
602-
if (gIdx != -1 && sgIdx != -1) {
603-
GameModeConfig gmCfg;
604-
GetGameModesList().GetArray(gIdx, gmCfg);
605-
SubGroupConfig subCfg;
606-
gmCfg.subGroups.GetArray(sgIdx, subCfg);
607-
minP = subCfg.minplayers;
608-
maxP = subCfg.maxplayers;
609-
}
610-
}
611-
612-
if (minP == 0 && maxP == 0) {
613-
int gIdx = MMC_FindGameModeIndex(gamemode);
614-
if (gIdx != -1) {
615-
GameModeConfig gmCfg;
616-
GetGameModesList().GetArray(gIdx, gmCfg);
617-
if (minP == 0) minP = gmCfg.minplayers;
618-
if (maxP == 0) maxP = gmCfg.maxplayers;
619-
}
581+
int minP = 0, maxP = 0, minT = -1, maxT = -1;
582+
bool hasLimits = false;
583+
if (strlen(subgroup) > 0) {
584+
if (!MultiMode_GetSubGroupLimits(gamemode, subgroup, minP, maxP, minT, maxT))
585+
MultiMode_GetGamemodeLimits(gamemode, minP, maxP, minT, maxT);
586+
hasLimits = true;
587+
} else {
588+
hasLimits = MultiMode_GetGamemodeLimits(gamemode, minP, maxP, minT, maxT);
620589
}
621590

622-
if (minP > 0 && players < minP) {
623-
exceedsPlayerLimit = true;
624-
Format(playerLimitGesture, sizeof(playerLimitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MINIMUM, minP);
591+
int players = GetRealClientCount();
592+
bool exceedsLimit = false;
593+
char limitGesture[32];
594+
595+
if (hasLimits && !MMC_IsTimeAllowed(minT, maxT)) {
596+
exceedsLimit = true;
597+
strcopy(limitGesture, sizeof(limitGesture), GESTURE_EXCLUDED_TIME);
598+
} else if (minP > 0 && players < minP) {
599+
exceedsLimit = true;
600+
Format(limitGesture, sizeof(limitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MINIMUM, minP);
625601
} else if (maxP > 0 && players > maxP) {
626-
exceedsPlayerLimit = true;
627-
Format(playerLimitGesture, sizeof(playerLimitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MAX, maxP);
602+
exceedsLimit = true;
603+
Format(limitGesture, sizeof(limitGesture), GESTURE_EXCLUDED_PLAYERLIMIT_MAX, maxP);
628604
}
629605

630606
char displayName[256];
@@ -635,9 +611,9 @@ void ShowNominateMapMenu(int client, const char[] gamemode, const char[] subgrou
635611
Format(displayName, sizeof(displayName), "%s%s", displayName, GESTURE_EXCLUDED);
636612
menu.AddItem(map, displayName, ITEMDRAW_DISABLED);
637613
}
638-
else if (exceedsPlayerLimit)
614+
else if (exceedsLimit)
639615
{
640-
Format(displayName, sizeof(displayName), "%s%s", displayName, playerLimitGesture);
616+
Format(displayName, sizeof(displayName), "%s%s", displayName, limitGesture);
641617
menu.AddItem(map, displayName, ITEMDRAW_DISABLED);
642618
}
643619
else if (g_Cvar_Nominate_NominateSelectedMapExclude.BoolValue && isNominated)

0 commit comments

Comments
 (0)