diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm index c43bb0922a6..0b247328679 100644 --- a/code/__defines/gamemode.dm +++ b/code/__defines/gamemode.dm @@ -3,6 +3,11 @@ #define GAME_STATE_PLAYING 3 #define GAME_STATE_FINISHED 4 +#define GAME_FAILURE_NONE 0x0 //WHAT'S THIS???? +#define GAME_FAILURE_NO_ANTAGS 0x1 +#define GAME_FAILURE_NO_PLAYERS 0x2 +#define GAME_FAILURE_TOO_MANY_PLAYERS 0x4 + // Security levels. #define SEC_LEVEL_GREEN 0 #define SEC_LEVEL_YELLOW 1 diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 2396d504cfc..1ae9f1a2f36 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -987,7 +987,7 @@ var/list/gamemode_cache = list() var/list/runnable_modes = list() for(var/game_mode in gamemode_cache) var/datum/game_mode/M = gamemode_cache[game_mode] - if(M && M.can_start() && probabilities[M.config_tag] && probabilities[M.config_tag] > 0) + if(M && M.can_start() == GAME_FAILURE_NONE && probabilities[M.config_tag] && probabilities[M.config_tag] > 0) runnable_modes |= M return runnable_modes diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm index 417249393d1..9aae5e55d3c 100644 --- a/code/controllers/subsystems/ticker.dm +++ b/code/controllers/subsystems/ticker.dm @@ -393,21 +393,36 @@ var/datum/controller/subsystem/ticker/SSticker src.mode.pre_setup() SSjobs.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly. - if(!src.mode.can_start()) + var/fail_reasons = list() + + var/can_start = src.mode.can_start() + + if(can_start & GAME_FAILURE_NO_PLAYERS) var/list/voted_not_ready = list() for(var/mob/abstract/new_player/player in player_list) if((player.client)&&(!player.ready)) voted_not_ready += player.ckey message_admins("The following players voted for [mode.name], but did not ready up: [jointext(voted_not_ready, ", ")]") log_game("Ticker: Players voted for [mode.name], but did not ready up: [jointext(voted_not_ready, ", ")]") - world << "Unable to start [mode.name]. Not enough players, [mode.required_players] players needed. Reverting to pre-game lobby." + fail_reasons += "Not enough players, [mode.required_players] player(s) needed" + + if(can_start & GAME_FAILURE_NO_ANTAGS) + fail_reasons += "Not enough antagonists, [mode.required_enemies] antagonist(s) needed" + + if(can_start & GAME_FAILURE_TOO_MANY_PLAYERS) + fail_reasons += "Too many players, less than [mode.max_players] antagonist(s) needed" + + if(can_start != GAME_FAILURE_NONE) + world << "Unable to start [mode.name]. [english_list(fail_reasons,"No reason specified",". ",". ")]" current_state = GAME_STATE_PREGAME mode.fail_setup() mode = null SSjobs.ResetOccupations() if(master_mode in list(ROUNDTYPE_STR_RANDOM, ROUNDTYPE_STR_SECRET, ROUNDTYPE_STR_MIXED_SECRET)) + world << "Reselecting gamemode..." return SETUP_REATTEMPT else + world << "Reverting to pre-game lobby." return SETUP_REVOTE var/starttime = REALTIMEOFDAY diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index e575a74fa45..402269e5160 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -10,6 +10,7 @@ var/global/list/additional_antag_types = list() var/probability = 0 var/required_players = 0 // Minimum players for round to start if voted in. + var/max_players = 0 // Maximum players for round to start for secret voting. 0 means "doesn't matter" var/required_enemies = 0 // Minimum antagonists for round to start. var/newscaster_announcements = null var/end_on_antag_death = 0 // Round will end when all antagonists are dead. @@ -146,35 +147,43 @@ var/global/list/additional_antag_types = list() ///can_start() ///Checks to see if the game can be setup and ran with the current number of players or whatnot. /datum/game_mode/proc/can_start(var/do_not_spawn) + + var/returning = GAME_FAILURE_NONE + var/playerC = 0 for(var/mob/abstract/new_player/player in player_list) if((player.client)&&(player.ready)) playerC++ - if(playerC < required_players) - return 0 + if(playerC < required_players && required_players != 0) + returning |= GAME_FAILURE_NO_PLAYERS - if(!(antag_templates && antag_templates.len)) - return 1 + if(playerC > max_players && max_players != 0) + returning |= GAME_FAILURE_TOO_MANY_PLAYERS - var/enemy_count = 0 - if(antag_tags && antag_tags.len) - for(var/antag_tag in antag_tags) - var/datum/antagonist/antag = all_antag_types[antag_tag] - if(!antag) - continue - var/list/potential = list() - if(antag.flags & ANTAG_OVERRIDE_JOB) - potential = antag.pending_antagonists - else - potential = antag.candidates - if(islist(potential)) - if(require_all_templates && potential.len < antag.initial_spawn_req) - return 0 - enemy_count += potential.len - if(enemy_count >= required_enemies) - return 1 - return 0 + if(antag_templates && antag_templates.len) + var/enemy_count = 0 + if(antag_tags && antag_tags.len) + for(var/antag_tag in antag_tags) + var/datum/antagonist/antag = all_antag_types[antag_tag] + if(!antag) + continue + var/list/potential = list() + if(antag.flags & ANTAG_OVERRIDE_JOB) + potential = antag.pending_antagonists + else + potential = antag.candidates + if(islist(potential)) + + if(potential.len) + enemy_count += potential.len + if(require_all_templates && potential.len < antag.initial_spawn_req) + returning |= GAME_FAILURE_NO_ANTAGS + + if(enemy_count < required_enemies) + returning |= GAME_FAILURE_NO_ANTAGS + + return returning /datum/game_mode/proc/refresh_event_modifiers() if(event_delay_mod_moderate || event_delay_mod_major) diff --git a/code/game/gamemodes/meme/meme.dm b/code/game/gamemodes/meme/meme.dm index 4e0c0d8caa9..00cdbff6c9c 100644 --- a/code/game/gamemodes/meme/meme.dm +++ b/code/game/gamemodes/meme/meme.dm @@ -39,8 +39,11 @@ world << "An unknown creature has infested the mind of a crew member. Find and destroy it by any means necessary." /datum/game_mode/meme/can_start() - if(!..()) - return 0 + + . = ..() + + if(. != "true") + return . // for every 10 players, get 1 meme, and for each meme, get a host // also make sure that there's at least one meme and one host @@ -50,7 +53,7 @@ if(possible_memes.len < 2) log_admin("MODE FAILURE: MEME. NOT ENOUGH MEME CANDIDATES.") - return 0 // not enough candidates for meme + return GAME_FAILURE_NO_ANTAGS // for each 2 possible memes, add one meme and one host while(possible_memes.len >= 2) @@ -68,7 +71,7 @@ meme.assigned_role = "MODE" //So they aren't chosen for other jobs. meme.special_role = "Meme" - return 1 + return GAME_FAILURE_NONE /datum/game_mode/meme/pre_setup() return 1 diff --git a/code/game/gamemodes/ninja/ninja.dm b/code/game/gamemodes/ninja/ninja.dm index 046fdd5a53e..a3b37d657d2 100644 --- a/code/game/gamemodes/ninja/ninja.dm +++ b/code/game/gamemodes/ninja/ninja.dm @@ -10,6 +10,7 @@ only hope this unknown assassin isn't here for you." config_tag = "ninja" required_players = 2 + max_players = 15 required_enemies = 1 end_on_antag_death = 1 antag_tags = list(MODE_NINJA) diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index 200b112b3f5..e33cb908648 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -4,6 +4,7 @@ extended_round_description = "A powerful entity capable of manipulating the elements around him, most commonly referred to as a 'wizard', has infiltrated the station. They have a wide variety of powers and spells available to them that makes your own simple moral self tremble with fear and excitement. Ultimately, their purpose is unknown. However, it is up to you and your crew to decide if their powers can be used for good or if their arrival foreshadows the destruction of the entire station." config_tag = "wizard" required_players = 3 + max_players = 20 required_enemies = 1 end_on_antag_death = 1 antag_tags = list(MODE_WIZARD) diff --git a/html/changelogs/burgerbb - limiter.yml b/html/changelogs/burgerbb - limiter.yml new file mode 100644 index 00000000000..fa142619a79 --- /dev/null +++ b/html/changelogs/burgerbb - limiter.yml @@ -0,0 +1,38 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +################################# + +# Your name. +author: BurgerBB + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - tweak: "Improved the gamemode start fail messages to better explain why a gamemode failed to start." + - tweak: "Ninja requires at least 15 players to start on secret. Wizard requires at least 15 players to start on secret as well."