<commit_before>//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31

/*
 * GAMEMODES (by Rastaf0)
 *
 * In the new mode system all special roles are fully supported.
 * You can have proper wizards/traitors/changelings/cultists during any mode.
 * Only two things really depends on gamemode:
 * 1. Starting roles, equipment and preparations
 * 2. Conditions of finishing the round.
 *
 */


/datum/game_mode
	var/name = "invalid"
	var/config_tag = null
	var/votable = 1
	var/probability = 0
	var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
	var/explosion_in_progress = 0 //sit back and relax
	var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
	var/list/datum/mind/modePlayer = new
	var/list/datum/mind/antag_candidates = list()	// List of possible starting antags goes here
	var/list/restricted_jobs = list()	// Jobs it doesn't make sense to be.  I.E chaplain or AI cultist
	var/list/protected_jobs = list()	// Jobs that can't be traitors because
	var/required_players = 0
	var/required_enemies = 0
	var/recommended_enemies = 0
	var/pre_setup_before_jobs = 0
	var/antag_flag = null //preferences flag such as BE_WIZARD that need to be turned on for players to be antag
	var/datum/mind/sacrifice_target = null
	var/mob/living/living_antag_player = null
	var/list/datum/game_mode/replacementmode = null
	var/round_converted = 0 //0: round not converted, 1: round going to convert, 2: round converted
	var/reroll_friendly 	//During mode conversion only these are in the running
	var/enemy_minimum_age = 7 //How many days must players have been playing before they can play this antagonist

	var/const/waittime_l = 600
	var/const/waittime_h = 1800 // started at 1800


/datum/game_mode/proc/announce() //to be calles when round starts
	world << "<B>Notice</B>: [src] did not define announce()"


///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/playerC = 0
	for(var/mob/new_player/player in player_list)
		if((player.client)&&(player.ready))
			playerC++
	if(!Debug2)
		if(playerC < required_players)
			return 0
	antag_candidates = get_players_for_role(antag_flag)
	if(!Debug2)
		if(antag_candidates.len < required_enemies)
			return 0
		return 1
	else
		world << "<span class='notice'>DEBUG: GAME STARTING WITHOUT PLAYER NUMBER CHECKS, THIS WILL PROBABLY BREAK SHIT."
		return 1


///pre_setup()
///Attempts to select players for special roles the mode might have.
/datum/game_mode/proc/pre_setup()
	return 1


///post_setup()
///Everyone should now be on the station and have their normal gear.  This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup(var/report=1)
	spawn (ROUNDSTART_LOGOUT_REPORT_TIME)
		display_roundstart_logout_report()

	feedback_set_details("round_start","[time2text(world.realtime)]")
	if(ticker && ticker.mode)
		feedback_set_details("game_mode","[ticker.mode]")
	if(revdata.revision)
		feedback_set_details("revision","[revdata.revision]")
	feedback_set_details("server_ip","[world.internet_address]:[world.port]")
	if(report)
		spawn (rand(waittime_l, waittime_h))
			send_intercept(0)
	start_state = new /datum/station_state()
	start_state.count(1)
	return 1

///make_antag_chance()
///Handles late-join antag assignments
/datum/game_mode/proc/make_antag_chance(var/mob/living/carbon/human/character)
	if(replacementmode && round_converted == 2)
		replacementmode.make_antag_chance(character)
	return

///convert_roundtype()
///Allows rounds to basically be "rerolled" should the initial premise fall through
/datum/game_mode/proc/convert_roundtype()
	var/list/living_crew = list()

	for(var/mob/Player in mob_list)
		if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player))
			living_crew += Player
	if(living_crew.len / joined_player_list.len <= config.midround_antag_life_check) //If a lot of the player base died, we start fresh
		message_admins("Convert_roundtype failed due to too many dead people. Limit is [config.midround_antag_life_check * 100]% living crew")
		return null

	var/list/datum/game_mode/runnable_modes = config.get_runnable_midround_modes(living_crew.len)
	var/list/datum/game_mode/usable_modes = list()
	for(var/datum/game_mode/G in runnable_modes)
		if(G.reroll_friendly)
			usable_modes += G
		else
			del(G)

	if(!usable_modes)
		message_admins("Convert_roundtype failed due to no valid modes to convert to. Please report this error to the Coders.")
		return null

	replacementmode = pickweight(usable_modes)

	switch(SSshuttle.emergency.mode) //Rounds on the verge of ending don't get new antags, they just run out
		if(SHUTTLE_STRANDED, SHUTTLE_ESCAPE)
			return 1
		if(SHUTTLE_CALL)
			if(SSshuttle.emergency.timeLeft(1) < initial(SSshuttle.emergencyCallTime)*0.5)
				return 1

	if(world.time >= (config.midround_antag_time_check * 600))
		message_admins("Convert_roundtype failed due to round length. Limit is [config.midround_antag_time_check] minutes.")
		return null

	var/list/antag_canadates = list()

	for(var/mob/living/carbon/human/H in living_crew)
		if(H.client && H.client.prefs.allow_midround_antag)
			antag_canadates += H

	if(!antag_canadates)
		message_admins("Convert_roundtype failed due to no antag canadates.")
		return null

	antag_canadates = shuffle(antag_canadates)

	if(config.protect_roles_from_antagonist)
		replacementmode.restricted_jobs += replacementmode.protected_jobs
	if(config.protect_assistant_from_antagonist)
		replacementmode.restricted_jobs += "Assistant"

	message_admins("The roundtype will be converted. If you have other plans for the station or think the round should end <A HREF='?_src_=holder;toggle_midround_antag=\ref[usr]'>stop the creation of antags</A> or <A HREF='?_src_=holder;end_round=\ref[usr]'>end the round now</A>.")

	spawn(rand(1200,3000)) //somewhere between 2 and 5 minutes from now
		if(!config.midround_antag[ticker.mode.config_tag])
			round_converted = 0
			return 1
		for(var/mob/living/carbon/human/H in antag_canadates)
			replacementmode.make_antag_chance(H)
		round_converted = 2
		message_admins("The roundtype has been converted, antagonists may have been created")
	return 1

///process()
///Called by the gameticker
/datum/game_mode/process()
	return 0


/datum/game_mode/proc/check_finished() //to be called by ticker
	if(replacementmode && round_converted == 2)
		return replacementmode.check_finished()
	if(SSshuttle.emergency.mode >= SHUTTLE_ENDGAME || station_was_nuked)
		return 1
	if(!round_converted && (!config.continuous[config_tag] || (config.continuous[config_tag] && config.midround_antag[config_tag]))) //Non-continuous or continous with replacement antags
		if(living_antag_player && living_antag_player.mind && living_antag_player.stat != DEAD && !isnewplayer(living_antag_player) &&!isbrain(living_antag_player))
			return 0 //A resource saver: once we find someone who has to die for all antags to be dead, we can just keep checking them, cycling over everyone only when we lose our mark.

		for(var/mob/living/Player in living_mob_list)
			if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player))
				if(Player.mind.special_role) //Someone's still antaging!
					living_antag_player = Player
					return 0

		if(!config.continuous[config_tag])
			return 1

		else
			round_converted = convert_roundtype()
			if(!round_converted)
				if(round_ends_with_antag_death)
					return 1<commit_msg>Adds sanity checking for configuration settings (or lack there of) that create situations where a round would end immediately because no antags had ever existed. This closes a hole where server owners could experience highly interuptive roundtypes like non-continous extended because they didn't keep their config files up to date.<commit_after>//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31

/*
 * GAMEMODES (by Rastaf0)
 *
 * In the new mode system all special roles are fully supported.
 * You can have proper wizards/traitors/changelings/cultists during any mode.
 * Only two things really depends on gamemode:
 * 1. Starting roles, equipment and preparations
 * 2. Conditions of finishing the round.
 *
 */


/datum/game_mode
	var/name = "invalid"
	var/config_tag = null
	var/votable = 1
	var/probability = 0
	var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
	var/explosion_in_progress = 0 //sit back and relax
	var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
	var/list/datum/mind/modePlayer = new
	var/list/datum/mind/antag_candidates = list()	// List of possible starting antags goes here
	var/list/restricted_jobs = list()	// Jobs it doesn't make sense to be.  I.E chaplain or AI cultist
	var/list/protected_jobs = list()	// Jobs that can't be traitors because
	var/required_players = 0
	var/required_enemies = 0
	var/recommended_enemies = 0
	var/pre_setup_before_jobs = 0
	var/antag_flag = null //preferences flag such as BE_WIZARD that need to be turned on for players to be antag
	var/datum/mind/sacrifice_target = null
	var/mob/living/living_antag_player = null
	var/list/datum/game_mode/replacementmode = null
	var/round_converted = 0 //0: round not converted, 1: round going to convert, 2: round converted
	var/reroll_friendly 	//During mode conversion only these are in the running
	var/continuous_sanity_checked	//Catches some cases where config options could be used to suggest that modes without antagonists should end when all antagonists die
	var/enemy_minimum_age = 7 //How many days must players have been playing before they can play this antagonist

	var/const/waittime_l = 600
	var/const/waittime_h = 1800 // started at 1800


/datum/game_mode/proc/announce() //to be calles when round starts
	world << "<B>Notice</B>: [src] did not define announce()"


///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/playerC = 0
	for(var/mob/new_player/player in player_list)
		if((player.client)&&(player.ready))
			playerC++
	if(!Debug2)
		if(playerC < required_players)
			return 0
	antag_candidates = get_players_for_role(antag_flag)
	if(!Debug2)
		if(antag_candidates.len < required_enemies)
			return 0
		return 1
	else
		world << "<span class='notice'>DEBUG: GAME STARTING WITHOUT PLAYER NUMBER CHECKS, THIS WILL PROBABLY BREAK SHIT."
		return 1


///pre_setup()
///Attempts to select players for special roles the mode might have.
/datum/game_mode/proc/pre_setup()
	return 1


///post_setup()
///Everyone should now be on the station and have their normal gear.  This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup(var/report=1)
	spawn (ROUNDSTART_LOGOUT_REPORT_TIME)
		display_roundstart_logout_report()

	feedback_set_details("round_start","[time2text(world.realtime)]")
	if(ticker && ticker.mode)
		feedback_set_details("game_mode","[ticker.mode]")
	if(revdata.revision)
		feedback_set_details("revision","[revdata.revision]")
	feedback_set_details("server_ip","[world.internet_address]:[world.port]")
	if(report)
		spawn (rand(waittime_l, waittime_h))
			send_intercept(0)
	start_state = new /datum/station_state()
	start_state.count(1)
	return 1

///make_antag_chance()
///Handles late-join antag assignments
/datum/game_mode/proc/make_antag_chance(var/mob/living/carbon/human/character)
	if(replacementmode && round_converted == 2)
		replacementmode.make_antag_chance(character)
	return

///convert_roundtype()
///Allows rounds to basically be "rerolled" should the initial premise fall through
/datum/game_mode/proc/convert_roundtype()
	var/list/living_crew = list()

	for(var/mob/Player in mob_list)
		if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player))
			living_crew += Player
	if(living_crew.len / joined_player_list.len <= config.midround_antag_life_check) //If a lot of the player base died, we start fresh
		message_admins("Convert_roundtype failed due to too many dead people. Limit is [config.midround_antag_life_check * 100]% living crew")
		return null

	var/list/datum/game_mode/runnable_modes = config.get_runnable_midround_modes(living_crew.len)
	var/list/datum/game_mode/usable_modes = list()
	for(var/datum/game_mode/G in runnable_modes)
		if(G.reroll_friendly)
			usable_modes += G
		else
			del(G)

	if(!usable_modes)
		message_admins("Convert_roundtype failed due to no valid modes to convert to. Please report this error to the Coders.")
		return null

	replacementmode = pickweight(usable_modes)

	switch(SSshuttle.emergency.mode) //Rounds on the verge of ending don't get new antags, they just run out
		if(SHUTTLE_STRANDED, SHUTTLE_ESCAPE)
			return 1
		if(SHUTTLE_CALL)
			if(SSshuttle.emergency.timeLeft(1) < initial(SSshuttle.emergencyCallTime)*0.5)
				return 1

	if(world.time >= (config.midround_antag_time_check * 600))
		message_admins("Convert_roundtype failed due to round length. Limit is [config.midround_antag_time_check] minutes.")
		return null

	var/list/antag_canadates = list()

	for(var/mob/living/carbon/human/H in living_crew)
		if(H.client && H.client.prefs.allow_midround_antag)
			antag_canadates += H

	if(!antag_canadates)
		message_admins("Convert_roundtype failed due to no antag canadates.")
		return null

	antag_canadates = shuffle(antag_canadates)

	if(config.protect_roles_from_antagonist)
		replacementmode.restricted_jobs += replacementmode.protected_jobs
	if(config.protect_assistant_from_antagonist)
		replacementmode.restricted_jobs += "Assistant"

	message_admins("The roundtype will be converted. If you have other plans for the station or think the round should end <A HREF='?_src_=holder;toggle_midround_antag=\ref[usr]'>stop the creation of antags</A> or <A HREF='?_src_=holder;end_round=\ref[usr]'>end the round now</A>.")

	spawn(rand(1200,3000)) //somewhere between 2 and 5 minutes from now
		if(!config.midround_antag[ticker.mode.config_tag])
			round_converted = 0
			return 1
		for(var/mob/living/carbon/human/H in antag_canadates)
			replacementmode.make_antag_chance(H)
		round_converted = 2
		message_admins("The roundtype has been converted, antagonists may have been created")
	return 1

///process()
///Called by the gameticker
/datum/game_mode/process()
	return 0


/datum/game_mode/proc/check_finished() //to be called by ticker
	if(replacementmode && round_converted == 2)
		return replacementmode.check_finished()
	if(SSshuttle.emergency.mode >= SHUTTLE_ENDGAME || station_was_nuked)
		return 1
	if(!round_converted && (!config.continuous[config_tag] || (config.continuous[config_tag] && config.midround_antag[config_tag]))) //Non-continuous or continous with replacement antags
		if(!continuous_sanity_checked) //make sure we have antags to be checking in the first place
			for(var/mob/living/Player in mob_list)
				if(Player.mind)
					if(Player.mind.special_role)
						continuous_sanity_checked = 1
			if(!continuous_sanity_checked)
				message_admins("The roundtype ([config_tag]) is reporting that it should end because no antagonists exist. This is PROBABLY a configuration error.")
				message_admins("Please alert a server owner to check the game_options.txt to be sure that it is up to date with all toggles relating to CONTINUOUS and MIDROUND_ANTAG.")
				message_admins("If after checking the settings it doesn't appear to be a configuration problem, create an issue report that [config_tag] isn't reporting its antagonists correctly.")
				config.continuous[config_tag] = 1
				config.midround_antag[config_tag] = 0
				return 0


		if(living_antag_player && living_antag_player.mind && living_antag_player.stat != DEAD && !isnewplayer(living_antag_player) &&!isbrain(living_antag_player))
			return 0 //A resource saver: once we find someone who has to die for all antags to be dead, we can just keep checking them, cycling over everyone only when we lose our mark.

		for(var/mob/living/Player in living_mob_list)
			if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player))
				if(Player.mind.special_role) //Someone's still antaging!
					living_antag_player = Player
					return 0

		if(!config.continuous[config_tag])
			return 1

		else
			round_converted = convert_roundtype()
			if(!round_converted)
				if(round_ends_with_antag_death)
					return 1
{'fraction_non_alphanumeric': 0.09738514173998045, 'fraction_numerical': 0.010874877810361682, 'mean_word_length': 4.771861777150916, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '646218', 'n_tokens_mistral': 6061, 'n_tokens_neox': 5379, 'n_words': 1482}