code:
//Contains the target item datums for Steal objectives.

datum/objective_item
	var/name = "A silly bike horn! Honk!"
	var/targetitem = /obj/item/weapon/bikehorn		//typepath of the objective item
	var/difficulty = 9001							//vaguely how hard it is to do this objective
	var/list/excludefromjob = list()				//If you don't want a job to get a certain objective (no captain stealing his own medal, etcetc)
	var/list/altitems = list()				//Items which can serve as an alternative to the objective (darn you blueprints)

datum/proc/check_special_completion() //for objectives with special checks (is that slime extract unused? does that intellicard have an ai in it? etcetc)
	return 1

datum/objective_item/steal/caplaser
	name = "the captain's antique laser gun"
	targetitem = /obj/item/weapon/gun/energy/laser/captain
	difficulty = 5
	excludefromjob = list("Captain")

datum/objective_item/steal/hoslaser
	name = "the head of security's personal laser gun"
	targetitem = /obj/item/weapon/gun/energy/gun/hos
	difficulty = 10
	excludefromjob = list("Head Of Security")

datum/objective_item/steal/handtele
	name = "a hand teleporter"
	targetitem = /obj/item/weapon/hand_tele
	difficulty = 5
	excludefromjob = list("Captain")

datum/objective_item/steal/rcd
	name = "a rapid-construction-device"
	targetitem = /obj/item/weapon/rcd
	difficulty = 3
	excludefromjob = list("Chief Engineer", "Quartermaster", "Cargo Technician")

datum/objective_item/steal/jetpack
	name = "a jetpack"
	targetitem = /obj/item/weapon/tank/jetpack
	difficulty = 3
	excludefromjob = list("Chief Engineer")

datum/objective_item/steal/magboots
	name = "the chief engineer's advanced magnetic boots"
	targetitem =  /obj/item/clothing/shoes/magboots/advance
	difficulty = 5
	excludefromjob = list("Chief Engineer")

datum/objective_item/steal/corgimeat
	name = "a piece of corgi meat"
	targetitem = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/corgi
	difficulty = 5
	excludefromjob = list("Head of Personnel", "Quartermaster", "Cargo Technician") //>hurting your little buddy ever

datum/objective_item/steal/capmedal
	name = "the medal of captaincy"
	targetitem = /obj/item/clothing/tie/medal/gold/captain
	difficulty = 5
	excludefromjob = list("Captain")

datum/objective_item/steal/hypo
	name = "the hypospray"
	targetitem = /obj/item/weapon/reagent_containers/hypospray/CMO
	difficulty = 5
	excludefromjob = list("Chief Medical Officer")

datum/objective_item/steal/nukedisc
	name = "the nuclear authentication disk"
	targetitem = /obj/item/weapon/disk/nuclear
	difficulty = 5
	excludefromjob = list("Captain")

datum/objective_item/steal/ablative
	name = "an ablative armor vest"
	targetitem = /obj/item/clothing/suit/armor/laserproof
	difficulty = 3
	excludefromjob = list("Head of Security", "Warden")

datum/objective_item/steal/reactive
	name = "the reactive teleport armor"
	targetitem = /obj/item/clothing/suit/armor/reactive
	difficulty = 5
	excludefromjob = list("Research Director")

datum/objective_item/steal/documents
	name = "any set of secret documents of any organization"
	targetitem = /obj/item/documents //Any set of secret documents. Doesn't have to be NT's
	difficulty = 5

//Items with special checks!
datum/objective_item/steal/plasma
	name = "28 moles of plasma (full tank)"
	targetitem = /obj/item/weapon/tank
	difficulty = 3
	excludefromjob = list("Chief Engineer","Research Director","Station Engineer","Scientist","Atmospheric Technician")

datum/objective_item/plasma/check_special_completion(var/obj/item/weapon/tank/T)
	var/target_amount = text2num(name)
	var/found_amount = 0
	found_amount += T.air_contents.toxins
	return found_amount>=target_amount

datum/objective_item/steal/functionalai
	name = "a functional AI"
	targetitem = /obj/item/device/aicard
	difficulty = 20 //beyond the impossible

datum/objective_item/functionalai/check_special_completion(var/obj/item/device/aicard/C)
	for(var/mob/living/silicon/ai/A in C)
		if(istype(A, /mob/living/silicon/ai) && A.stat != 2) //See if any AI's are alive inside that card.
			return 1
	return 0

datum/objective_item/steal/blueprints
	name = "the station blueprints"
	targetitem = /obj/item/areaeditor/blueprints
	difficulty = 10
	excludefromjob = list("Chief Engineer")
	altitems = list(/obj/item/weapon/photo)

datum/objective_item/blueprints/check_special_completion(var/obj/item/I)
	if(istype(I, /obj/item/areaeditor/blueprints))
		return 1
	if(istype(I, /obj/item/weapon/photo))
		var/obj/item/weapon/photo/P = I
		if(P.blueprints)	//if the blueprints are in frame
			return 1
	return 0

datum/objective_item/steal/slime
	name = "an unused sample of slime extract"
	targetitem = /obj/item/slime_extract
	difficulty = 3
	excludefromjob = list("Research Director","Scientist")

datum/objective_item/slime/check_special_completion(var/obj/item/slime_extract/E)
	if(E.Uses > 0)
		return 1
	return 0

//Unique Objectives
datum/objective_item/unique/docs_red
	name = "the \"Red\" secret documents"
	targetitem = /obj/item/documents/syndicate/red
	difficulty = 10

datum/objective_item/unique/docs_blue
	name = "the \"Blue\" secret documents"
	targetitem = /obj/item/documents/syndicate/blue
	difficulty = 10

//Old ninja objectives.
datum/objective_item/special/pinpointer
	name = "the captain's pinpointer"
	targetitem = /obj/item/weapon/pinpointer
	difficulty = 10

datum/objective_item/special/aegun
	name = "an advanced energy gun"
	targetitem = /obj/item/weapon/gun/energy/gun/nuclear
	difficulty = 10

datum/objective_item/special/ddrill
	name = "a diamond drill"
	targetitem = /obj/item/weapon/pickaxe/drill/diamonddrill
	difficulty = 10

datum/objective_item/special/boh
	name = "a bag of holding"
	targetitem = /obj/item/weapon/storage/backpack/holding
	difficulty = 10

datum/objective_item/special/hypercell
	name = "a hyper-capacity cell"
	targetitem = /obj/item/weapon/stock_parts/cell/hyper
	difficulty = 5

datum/objective_item/special/laserpointer
	name = "a laser pointer"
	targetitem = /obj/item/device/laser_pointer
	difficulty = 5

//Stack objectives get their own subtype
datum/objective_item/stack
	name = "5 cardboards"
	targetitem = /obj/item/stack/sheet/cardboard
	difficulty = 9001

datum/objective_item/stack/check_special_completion(var/obj/item/stack/S)
	var/target_amount = text2num(name)
	var/found_amount = 0

	if(istype(S, targetitem))
		found_amount = S.amount
	return found_amount>=target_amount

datum/objective_item/stack/diamond
	name = "10 diamonds"
	targetitem = /obj/item/stack/sheet/mineral/diamond
	difficulty = 10

datum/objective_item/stack/gold
	name = "50 gold bars"
	targetitem = /obj/item/stack/sheet/mineral/gold
	difficulty = 15

datum/objective_item/stack/uranium
	name = "25 refined uranium bars"
	targetitem = /obj/item/stack/sheet/mineral/uranium
	difficulty = 10


code:
// To add a rev to the list of revolutionaries, make sure it's rev (with if(ticker.mode.name == "revolution)),
// then call ticker.mode:add_revolutionary(_THE_PLAYERS_MIND_)
// nothing else needs to be done, as that proc will check if they are a valid target.
// Just make sure the converter is a head before you call it!
// To remove a rev (from brainwashing or w/e), call ticker.mode:remove_revolutionary(_THE_PLAYERS_MIND_),
// this will also check they're not a head, so it can just be called freely
// If the game somtimes isn't registering a win properly, then ticker.mode.check_win() isn't being called somewhere.

/datum/game_mode
	var/list/datum/mind/head_revolutionaries = list()
	var/list/datum/mind/revolutionaries = list()

/datum/game_mode/revolution
	name = "revolution"
	config_tag = "revolution"
	antag_flag = BE_REV
	restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg", "MoMMI", "Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
	required_players = 10
	required_enemies = 1
	recommended_enemies = 2

	var/finished = 0
	var/check_counter = 0
	var/max_headrevs = 2
	var/list/datum/mind/heads_to_kill = list()

///////////////////////////
//Announces the game type//
///////////////////////////
/datum/game_mode/revolution/announce()
	world << "The current game mode is - Revolution!"
	world << "Some crewmembers are attempting to start a revolution!
\nRevolutionaries - Kill the Captain, HoP, HoS, CE, RD and CMO. Convert other crewmembers (excluding the heads of staff, and security officers) to your cause by flashing them. Protect your leaders.
\nPersonnel - Protect the heads of staff. Kill the leaders of the revolution, and brainwash the other revolutionaries (by beating them in the head)."

///////////////////////////////////////////////////////////////////////////////
//Gets the round setup, cancelling if there's not enough players at the start//
///////////////////////////////////////////////////////////////////////////////
/datum/game_mode/revolution/pre_setup()

	//adjust the number of headrevs based on player count
	if(num_players() >= 20)
		recommended_enemies = 3
		max_headrevs = 3

	if(config.protect_roles_from_antagonist)
		restricted_jobs += protected_jobs

	if(config.protect_assistant_from_antagonist)
		restricted_jobs += "Assistant"

	for (var/i=1 to max_headrevs)
		if (antag_candidates.len==0)
			break
		var/datum/mind/lenin = pick(antag_candidates)
		antag_candidates -= lenin
		lenin.restricted_roles = restricted_jobs
		head_revolutionaries += lenin

	if((head_revolutionaries.len < required_enemies))
		return 0

	return 1

/datum/game_mode/revolution/post_setup()
	var/list/heads = get_living_heads()

	while(heads.len < head_revolutionaries.len) //das vi danya
		var/datum/mind/trotsky = pick(head_revolutionaries)
		antag_candidates += trotsky
		head_revolutionaries -= trotsky
		update_rev_icons_removed(trotsky)

	for(var/datum/mind/rev_mind in head_revolutionaries)
		log_game("[rev_mind.key] (ckey) has been selected as a head rev")
		for(var/datum/mind/head_mind in heads)
			mark_for_death(rev_mind, head_mind)

		spawn(rand(10,100))
		//	equip_traitor(rev_mind.current, 1) //changing how revs get assigned their uplink so they can get PDA uplinks. --NEO
		//	Removing revolutionary uplinks.	-Pete
			equip_revolutionary(rev_mind.current)
			update_rev_icons_added(rev_mind)

	for(var/datum/mind/rev_mind in head_revolutionaries)
		greet_revolutionary(rev_mind)
	modePlayer += head_revolutionaries
	SSshuttle.emergencyNoEscape = 1
	..()

/datum/game_mode/revolution/process()
	check_counter++
	if(check_counter >= 5)
		if(!finished)
			check_heads()
			ticker.mode.check_win()
		check_counter = 0
	return 0

/datum/game_mode/proc/forge_revolutionary_objectives(var/datum/mind/rev_mind)
	var/list/heads = get_living_heads()
	for(var/datum/mind/head_mind in heads)
		var/datum/objective/mutiny/rev_obj = new
		rev_obj.owner = rev_mind
		rev_obj.target = head_mind
		rev_obj.explanation_text = "Assassinate or exile [head_mind.name], the [head_mind.assigned_role]."
		rev_mind.objectives += rev_obj

/datum/game_mode/proc/greet_revolutionary(var/datum/mind/rev_mind, var/you_are=1)
	var/obj_count = 1
	if (you_are)
		rev_mind.current << "You are a member of the revolutionaries' leadership!"
	for(var/datum/objective/objective in rev_mind.objectives)
		rev_mind.current << "Objective #[obj_count]: [objective.explanation_text]"
		rev_mind.special_role = "Head Revolutionary"
		obj_count++

/////////////////////////////////////////////////////////////////////////////////
//This are equips the rev heads with their gear, and makes the clown not clumsy//
/////////////////////////////////////////////////////////////////////////////////
/datum/game_mode/proc/equip_revolutionary(mob/living/carbon/human/mob)
	if(!istype(mob))
		return

	if (mob.mind)
		if (mob.mind.assigned_role == "Clown")
			mob << "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself."
			mob.dna.remove_mutation(CLOWNMUT)

	var/obj/item/device/flash/T = new(mob)

	var/list/slots = list (
		"backpack" = slot_in_backpack,
		"left pocket" = slot_l_store,
		"right pocket" = slot_r_store,
		"left hand" = slot_l_hand,
		"right hand" = slot_r_hand,
	)
	var/where = mob.equip_in_one_of_slots(T, slots)
	if (!where)
		mob << "The Syndicate were unfortunately unable to get you a flash."
	else
		mob << "The flash in your [where] will help you to persuade the crew to join your cause."
		mob.update_icons()
		return 1

/////////////////////////////////
//Gives head revs their targets//
/////////////////////////////////
/datum/game_mode/revolution/proc/mark_for_death(var/datum/mind/rev_mind, var/datum/mind/head_mind)
	var/datum/objective/mutiny/rev_obj = new
	rev_obj.owner = rev_mind
	rev_obj.target = head_mind
	rev_obj.explanation_text = "Assassinate [head_mind.name], the [head_mind.assigned_role]."
	rev_mind.objectives += rev_obj
	heads_to_kill += head_mind

////////////////////////////////////////////
//Checks if new heads have joined midround//
////////////////////////////////////////////
/datum/game_mode/revolution/proc/check_heads()
	var/list/heads = get_all_heads()
	if(heads_to_kill.len < heads.len)
		var/list/new_heads = heads - heads_to_kill
		for(var/datum/mind/head_mind in new_heads)
			for(var/datum/mind/rev_mind in head_revolutionaries)
				mark_for_death(rev_mind, head_mind)

	if(max_headrevs < initial(max_headrevs) && max_headrevs < heads.len)
		latejoin_headrev()

///////////////////////////////
//Adds a new headrev midround//
///////////////////////////////
/datum/game_mode/revolution/proc/latejoin_headrev()
	if(revolutionaries) //Head Revs are not in this list
		var/datum/mind/stalin = pick(revolutionaries)
		revolutionaries -= stalin
		head_revolutionaries += stalin
		log_game("[stalin.key] (ckey) has been promoted to a head rev")
		equip_revolutionary(stalin.current)
		forge_revolutionary_objectives(stalin)
		greet_revolutionary(stalin)
		++max_headrevs

//////////////////////////////////////
//Checks if the revs have won or not//
//////////////////////////////////////
/datum/game_mode/revolution/check_win()
	if(check_rev_victory())
		finished = 1
	else if(check_heads_victory())
		finished = 2
	return

///////////////////////////////
//Checks if the round is over//
///////////////////////////////
/datum/game_mode/revolution/check_finished()
	if(config.continuous_round_rev)
		if(finished != 0)
			SSshuttle.emergencyNoEscape = 0
		return ..()
	if(finished != 0)
		return 1
	else
		return 0

///////////////////////////////////////////////////
//Deals with converting players to the revolution//
///////////////////////////////////////////////////
/datum/game_mode/proc/add_revolutionary(datum/mind/rev_mind)
	if(rev_mind.assigned_role in command_positions)
		return 0
	var/mob/living/carbon/human/H = rev_mind.current//Check to see if the potential rev is implanted
	if(isloyal(H))
		return 0
	if((rev_mind in revolutionaries) || (rev_mind in head_revolutionaries))
		return 0
	revolutionaries += rev_mind
	rev_mind.current << " You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!"
	rev_mind.current.attack_log += "\[[time_stamp()]\] Has been converted to the revolution!"
	rev_mind.special_role = "Revolutionary"
	update_rev_icons_added(rev_mind)
	return 1
//////////////////////////////////////////////////////////////////////////////
//Deals with players being converted from the revolution (Not a rev anymore)//  // Modified to handle borged MMIs.  Accepts another var if the target is being borged at the time  -- Polymorph.
//////////////////////////////////////////////////////////////////////////////
/datum/game_mode/proc/remove_revolutionary(datum/mind/rev_mind , beingborged)
	if(rev_mind in revolutionaries)
		revolutionaries -= rev_mind
		rev_mind.special_role = null
		rev_mind.current.attack_log += "\[[time_stamp()]\] Has renounced the revolution!"

		if(beingborged)
			rev_mind.current << "The frame's firmware detects and deletes your neural reprogramming!  You remember nothing but the name of the one who flashed you."
			message_admins("[key_name_admin(rev_mind.current)] ? has been borged while being a member of the revolution.")

		else
			rev_mind.current << "You have been brainwashed! You are no longer a revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you..."

		update_rev_icons_removed(rev_mind)
		for(var/mob/living/M in view(rev_mind.current))
			if(beingborged)
				M << "The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it."

			else
				M << "[rev_mind.current] looks like they just remembered their real allegiance!"

/////////////////////////////////////
//Adds the rev hud to a new convert//
/////////////////////////////////////
/datum/game_mode/proc/update_rev_icons_added(datum/mind/rev_mind)
	var/datum/atom_hud/antag/revhud = huds[ANTAG_HUD_REV]
	revhud.join_hud(rev_mind.current)
	set_antag_hud(rev_mind.current, ((rev_mind in head_revolutionaries) ? "rev_head" : "rev"))

/////////////////////////////////////////
//Removes the hud from deconverted revs//
/////////////////////////////////////////
/datum/game_mode/proc/update_rev_icons_removed(datum/mind/rev_mind)
	var/datum/atom_hud/antag/revhud = huds[ANTAG_HUD_REV]
	revhud.leave_hud(rev_mind.current)
	set_antag_hud(rev_mind.current, null)

//////////////////////////
//Checks for rev victory//
//////////////////////////
/datum/game_mode/revolution/proc/check_rev_victory()
	for(var/datum/mind/rev_mind in head_revolutionaries)
		for(var/datum/objective/mutiny/objective in rev_mind.objectives)
			if(!(objective.check_completion()))
				return 0

		return 1

/////////////////////////////
//Checks for a head victory//
/////////////////////////////
/datum/game_mode/revolution/proc/check_heads_victory()
	for(var/datum/mind/rev_mind in head_revolutionaries)
		var/turf/T = get_turf(rev_mind.current)
		if((rev_mind) && (rev_mind.current) && (rev_mind.current.stat != 2) && rev_mind.current.client && T && (T.z == ZLEVEL_STATION))
			if(ishuman(rev_mind.current))
				return 0
	return 1

//////////////////////////////////////////////////////////////////////
//Announces the end of the game with all relavent information stated//
//////////////////////////////////////////////////////////////////////
/datum/game_mode/revolution/declare_completion()
	if(finished == 1)
		feedback_set_details("round_end_result","win - heads killed")
		world << "The heads of staff were killed or exiled! The revolutionaries win!"
	else if(finished == 2)
		feedback_set_details("round_end_result","loss - rev heads killed")
		world << "The heads of staff managed to stop the revolution!"
	..()
	return 1

/datum/game_mode/proc/auto_declare_completion_revolution()
	var/list/targets = list()

	if(head_revolutionaries.len || istype(ticker.mode,/datum/game_mode/revolution))
		var/num_revs = 0
		var/num_survivors = 0
		for(var/mob/living/carbon/survivor in living_mob_list)
			if(survivor.ckey)
				num_survivors++
				if(survivor.mind)
					if((survivor.mind in head_revolutionaries) || (survivor.mind in revolutionaries))
						num_revs++

		if(num_survivors)
			world << "[TAB]Command's Approval Rating: [100 - round((num_revs/num_survivors)*100, 0.1)]%" // % of loyal crew

		var/text = "
The head revolutionaries were:"

		for(var/datum/mind/headrev in head_revolutionaries)
			text += "
[headrev.key] was [headrev.name] ("
			if(headrev.current)
				if(headrev.current.stat == DEAD)
					text += "died"
				else if(headrev.current.z != ZLEVEL_STATION)
					text += "fled the station"
				else
					text += "survived the revolution"
				if(headrev.current.real_name != headrev.name)
					text += " as [headrev.current.real_name]"
			else
				text += "body destroyed"
			text += ")"

			for(var/datum/objective/mutiny/objective in headrev.objectives)
				targets |= objective.target
		text += "
"

		world << text

	if(revolutionaries.len || istype(ticker.mode,/datum/game_mode/revolution))
		var/text = "
The revolutionaries were:"

		for(var/datum/mind/rev in revolutionaries)
			text += "
[rev.key] was [rev.name] ("
			if(rev.current)
				if(rev.current.stat == DEAD || isbrain(rev.current))
					text += "died"
				else if(rev.current.z != ZLEVEL_STATION)
					text += "fled the station"
				else
					text += "survived the revolution"
				if(rev.current.real_name != rev.name)
					text += " as [rev.current.real_name]"
			else
				text += "body destroyed"
			text += ")"
		text += "
"

		world << text

	if( head_revolutionaries.len || revolutionaries.len || istype(ticker.mode,/datum/game_mode/revolution) )
		var/text = "
The heads of staff were:"

		var/list/heads = get_all_heads()
		for(var/datum/mind/head in heads)
			var/target = (head in targets)
			if(target)
				text += ""
			text += "
[head.key] was [head.name] ("
			if(head.current)
				if(head.current.stat == DEAD || isbrain(head.current))
					text += "died"
				else if(head.current.z != ZLEVEL_STATION)
					text += "fled the station"
				else
					text += "survived the revolution"
				if(head.current.real_name != head.name)
					text += " as [head.current.real_name]"
			else
				text += "body destroyed"
			text += ")"
			if(target)
				text += ""
		text += "
"

		world << text

license: mit


code:
/*
	This is for the sandbox for now,
	maybe useful later for an actual thing?
	-Sayu
*/

obj/structure/door_assembly
	var/datum/airlock_maker/maker = null

obj/structure/door_assembly/attack_hand()
	..()
	if(maker)
		maker.interact()

datum/airlock_maker
	var/obj/structure/door_assembly/linked = null

	var/list/access_used = null
	var/require_all = 1

	var/paintjob = "none"
	var/glassdoor = 0

	var/doorname = "airlock"

datum/airlock_maker/New(var/atom/target_loc)
	linked = new(target_loc)
	linked.maker = src
	linked.anchored = 0
	access_used = list()

	interact()

datum/airlock_maker/proc/linkpretty(href,desc,active)
	if(!desc)
		var/static/list/defaults = list("No","Yes")
		desc = defaults[active+1]
	if(active)
		return "[desc]"
	return "[desc]"

datum/airlock_maker/proc/interact()
	var/list/leftcolumn = list()
	var/list/rightcolumn = list()
	leftcolumn += "Required Access"
	for(var/access in get_all_accesses())
		leftcolumn += linkpretty("access=[access]",get_access_desc(access),access in access_used)
	leftcolumn += "Require all listed accesses: [linkpretty("reqall",null,require_all)]"

	rightcolumn += "Paintjob"
	for(var/option in list("none","engineering","atmos","security","command","medical","research","mining","maintenance","external","highsecurity"))
		rightcolumn += linkpretty("paint=[option]",option,option == paintjob)
	rightcolumn += "Glass door: " + linkpretty("glass",null,glassdoor) + "

"
	var/length = max(leftcolumn.len,rightcolumn.len)

	var/dat = "You may move the model airlock around.  A new airlock will be built in its space when you click done, below.

"
	dat += "Door name: \"[doorname]\""
	dat += "
"
	for(var/i=1; i<=length; i++)
		dat += "
"
		if(i<=leftcolumn.len)
			dat += leftcolumn[i]
		dat += "	"
		if(i<=rightcolumn.len)
			dat += rightcolumn[i]
		dat += "
"

	dat += "

Finalize Airlock Construction | Cancel and Destroy Airlock"
	usr << browse(dat,"window=airlockmaker")

datum/airlock_maker/Topic(var/href,var/list/href_list)
	if(!usr) return
	if(!src || !linked || !linked.loc)
		usr << browse(null,"window=airlockmaker")
		return

	if("rename" in href_list)
		var/newname = stripped_input(usr,"New airlock name:","Name the airlock",doorname)
		if(newname)
			doorname = newname
	if("access" in href_list)
		var/value = text2num(href_list["access"])
		access_used ^= value
	if("reqall" in href_list)
		require_all = !require_all
	if("paint" in href_list)
		paintjob = href_list["paint"]
	if("glass" in href_list)
		glassdoor = !glassdoor

	if("cancel" in href_list)
		usr << browse(null,"window=airlockmaker")
		qdel(linked)
		qdel(src)
		return

	if("done" in href_list)
		usr << browse(null,"window=airlockmaker")
		var/turf/t_loc = linked.loc
		qdel(linked)
		if(!istype(t_loc))
			return

		var/target_type = "/obj/machinery/door/airlock"
		if(glassdoor)
			if(paintjob != "none")
				if(paintjob in list("external","highsecurity","maintenance")) // no glass version
					target_type += "/[paintjob]"
				else
					target_type += "/glass_[paintjob]"
			else
				target_type += "/glass"
		else if(paintjob != "none")
			target_type += "/[paintjob]"
		var/final = target_type
		target_type = text2path(final)
		if(!target_type)
			usr << "Didn't work, contact Sayu with this: [final]"
			usr << browse(null,"window=airlockmaker")
			return

		var/obj/machinery/door/D = new target_type(t_loc)

		D.name = doorname

		if(access_used.len == 0)
			D.req_access = null
			D.req_one_access = null
		else if(require_all)
			D.req_access = access_used.Copy()
			D.req_one_access = null
		else
			D.req_access = null
			D.req_one_access = access_used.Copy()

		return

	interact()


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

var/hsboxspawn = 1

mob
	var/datum/hSB/sandbox = null
mob/proc/CanBuild()
	if(master_mode == "sandbox")
		sandbox = new/datum/hSB
		sandbox.owner = src.ckey
		if(src.client.holder)
			sandbox.admin = 1
		verbs += new/mob/proc/sandbox_panel
mob/proc/sandbox_panel()
	set name = "Sandbox Panel"
	if(sandbox)
		sandbox.update()

datum/hSB
	var/owner = null
	var/admin = 0

	var/clothinfo = null
	var/reaginfo = null
	var/objinfo = null
	var/canisterinfo = null
	var/hsbinfo = null
	//items that shouldn't spawn on the floor because they would bug or act weird
	var/global/list/spawn_forbidden = list(
		/obj/item/weapon/grab, /obj/item/tk_grab, /obj/item/weapon/implant, // not implanter, the actual thing that is inside you
		/obj/item/assembly,/obj/item/device/onetankbomb, /obj/item/radio, /obj/item/device/pda/ai,
		/obj/item/device/uplink/hidden, /obj/item/smallDelivery, /obj/item/missile,/obj/item/projectile,
		/obj/item/borg/sight,/obj/item/borg/overdrive,/obj/item/borg/stun,/obj/item/weapon/robot_module)

datum/hSB/proc/update()
	var/global/list/hrefs = list(
			"Space Gear",
			"Suit Up (Space Travel Gear)"		= "hsbsuit",
			"Spawn Gas Mask"					= "hsbspawn&path=[/obj/item/clothing/mask/gas]",
			"Spawn Emergency Air Tank"			= "hsbspawn&path=[/obj/item/weapon/tank/internals/emergency_oxygen/double]",

			"Standard Tools",
			"Spawn Flashlight"					= "hsbspawn&path=[/obj/item/device/flashlight]",
			"Spawn Toolbox"						= "hsbspawn&path=[/obj/item/weapon/storage/toolbox/mechanical]",
			"Spawn Light Replacer"				= "hsbspawn&path=[/obj/item/device/lightreplacer]",
			"Spawn Medical Kit"					= "hsbspawn&path=[/obj/item/weapon/storage/firstaid/regular]",
			"Spawn All-Access ID"				= "hsbaaid",

			"Building Supplies",
			"Spawn 50 Wood"                     = "hsbwood",
			"Spawn 50 Metal"					= "hsbmetal",
			"Spawn 50 Plasteel"					= "hsbplasteel",
			"Spawn 50 Reinforced Glass"         = "hsbrglass",
			"Spawn 50 Glass"					= "hsbglass",
			"Spawn Full Cable Coil"				= "hsbspawn&path=[/obj/item/stack/cable_coil]",
			"Spawn Hyper Capacity Power Cell"	= "hsbspawn&path=[/obj/item/weapon/stock_parts/cell/hyper]",
			"Spawn Inf. Capacity Power Cell"	= "hsbspawn&path=[/obj/item/weapon/stock_parts/cell/infinite]",
			"Spawn Rapid Construction Device"	= "hsbrcd",
			"Spawn RCD Ammo"					= "hsb_safespawn&path=[/obj/item/weapon/rcd_ammo]",
			"Spawn Airlock"						= "hsbairlock",

			"Miscellaneous",
			"Spawn Air Scrubber"				= "hsbscrubber",
			"Spawn Welding Fuel Tank"			= "hsbspawn&path=[/obj/structure/reagent_dispensers/fueltank]",
			"Spawn Water Tank"					= "hsbspawn&path=[/obj/structure/reagent_dispensers/watertank]",

			"Bots",
			"Spawn Cleanbot"					= "hsbspawn&path=[/obj/machinery/bot/cleanbot]",
			"Spawn Floorbot"					= "hsbspawn&path=[/obj/machinery/bot/floorbot]",
			"Spawn Medbot"						= "hsbspawn&path=[/obj/machinery/bot/medbot]",

			"Canisters",
			"Spawn O2 Canister" 				= "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/oxygen]",
			"Spawn Air Canister"				= "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/air]")

	if(!hsbinfo)
		hsbinfo = "Sandbox Panel
"
		if(admin)
			hsbinfo += "Administration
"
			hsbinfo += "- Toggle Object Spawning
"
			hsbinfo += "- Toggle Item Spawn Panel Auto-close
"
			hsbinfo += "Canister Spawning
"
			hsbinfo += "- Spawn Plasma Canister
"
			hsbinfo += "- Spawn CO2 Canister
"
			hsbinfo += "- Spawn Nitrogen Canister
"
			hsbinfo += "- Spawn N2O Canister
"
		else
			hsbinfo += "Some item spawning may be disabled by the administrators.
"
			hsbinfo += "Only administrators may spawn dangerous canisters.
"
		for(var/T in hrefs)
			var/href = hrefs[T]
			if(href)
				hsbinfo += "- [T]
"
			else
				hsbinfo += "
[T]
"
		hsbinfo += "
"
		hsbinfo += "- Spawn Clothing...
"
		hsbinfo += "- Spawn Reagent Container...
"
		hsbinfo += "- Spawn Other Item...

"

	usr << browse(hsbinfo, "window=hsbpanel")

datum/hSB/Topic(href, href_list)
	if(!usr || !src || !(src.owner == usr.ckey))
		if(usr)
			usr << browse(null,"window=sandbox")
		return

	if(href_list["hsb"])
		switch(href_list["hsb"])
			//
			// Admin: toggle spawning
			//
			if("hsbtobj")
				if(!admin) return
				if(hsboxspawn)
					world << "Sandbox: \black[usr.key] has disabled object spawning!"
					hsboxspawn = 0
					return
				else
					world << "Sandbox: \black[usr.key] has enabled object spawning!"
					hsboxspawn = 1
					return
			//
			// Admin: Toggle auto-close
			//
			if("hsbtac")
				if(!admin) return
				if(config.sandbox_autoclose)
					world << "Sandbox: \black [usr.key] has removed the object spawn limiter."
					config.sandbox_autoclose = 0
				else
					world << "Sandbox: \black [usr.key] has added a limiter to object spawning.  The window will now auto-close after use."
					config.sandbox_autoclose = 1
				return
			//
			// Spacesuit with full air jetpack set as internals
			//
			if("hsbsuit")
				var/mob/living/carbon/human/P = usr
				if(!istype(P)) return
				if(P.wear_suit)
					P.wear_suit.loc = P.loc
					P.wear_suit.layer = initial(P.wear_suit.layer)
					P.wear_suit = null
				P.wear_suit = new/obj/item/clothing/suit/space(P)
				P.wear_suit.layer = 20
				P.update_inv_wear_suit()
				if(P.head)
					P.head.loc = P.loc
					P.head.layer = initial(P.head.layer)
					P.head = null
				P.head = new/obj/item/clothing/head/helmet/space(P)
				P.head.layer = 20
				P.update_inv_head()
				if(P.wear_mask)
					P.wear_mask.loc = P.loc
					P.wear_mask.layer = initial(P.wear_mask.layer)
					P.wear_mask = null
				P.wear_mask = new/obj/item/clothing/mask/gas(P)
				P.wear_mask.layer = 20
				P.update_inv_wear_mask()
				if(P.back)
					P.back.loc = P.loc
					P.back.layer = initial(P.back.layer)
					P.back = null
				P.back = new/obj/item/weapon/tank/jetpack/oxygen(P)
				P.back.layer = 20
				P.update_inv_back()
				P.internal = P.back
				if(P.internals)
					P.internals.icon_state = "internal1"

			if("hsbscrubber") // This is beyond its normal capability but this is sandbox and you spawned one, I assume you need it
				var/obj/hsb = new/obj/machinery/portable_atmospherics/scrubber{volume_rate=50*ONE_ATMOSPHERE;on=1}(usr.loc)
				hsb.update_icon() // hackish but it wasn't meant to be spawned I guess?

			//
			// Stacked Materials
			//

			if("hsbrglass")
				new/obj/item/stack/sheet/rglass{amount=50}(usr.loc)

			if("hsbmetal")
				new/obj/item/stack/sheet/metal{amount=50}(usr.loc)

			if("hsbplasteel")
				new/obj/item/stack/sheet/plasteel{amount=50}(usr.loc)

			if("hsbglass")
				new/obj/item/stack/sheet/glass{amount=50}(usr.loc)

			if("hsbwood")
				new/obj/item/stack/sheet/mineral/wood{amount=50}(usr.loc)

			//
			// All access ID
			//
			if("hsbaaid")
				var/obj/item/weapon/card/id/gold/ID = new(usr.loc)
				ID.registered_name = usr.real_name
				ID.assignment = "Sandbox"
				ID.access = get_all_accesses()
				ID.update_label()

			//
			// RCD - starts with full clip
			// Spawn check due to grief potential (destroying floors, walls, etc)
			//
			if("hsbrcd")
				if(!hsboxspawn) return

				new/obj/item/weapon/rcd{matter=30;canRwall=1}(usr.loc)

			//
			// New sandbox airlock maker
			//
			if("hsbairlock")
				new /datum/airlock_maker(usr.loc)

			//
			// Object spawn window
			//

			// Clothing
			if("hsbcloth")
				if(!hsboxspawn) return

				if(!clothinfo)
					clothinfo = "Clothing (Reagent Containers) (Other Items)

"
					var/list/all_items = typesof(/obj/item/clothing) - /obj/item/clothing
					for(var/typekey in spawn_forbidden)
						all_items -= typesof(typekey)
					for(var/O in reverseRange(all_items))
						clothinfo += "[O]
"

				usr << browse(clothinfo,"window=sandbox")

			// Reagent containers
			if("hsbreag")
				if(!hsboxspawn) return

				if(!reaginfo)
					reaginfo = "Reagent Containers (Clothing) (Other Items)

"
					var/list/all_items = typesof(/obj/item/weapon/reagent_containers) - /obj/item/weapon/reagent_containers
					for(var/typekey in spawn_forbidden)
						all_items -= typesof(typekey)
					for(var/O in reverseRange(all_items))
						reaginfo += "[O]
"

				usr << browse(reaginfo,"window=sandbox")

			// Other items
			if("hsbobj")
				if(!hsboxspawn) return

				if(!objinfo)
					objinfo = "Other Items (Clothing) (Reagent Containers)

"
					var/list/all_items = typesof(/obj/item/) - typesof(/obj/item/clothing) - typesof(/obj/item/weapon/reagent_containers) - /obj/item
					for(var/typekey in spawn_forbidden)
						all_items -= typesof(typekey)

					for(var/O in reverseRange(all_items))
						objinfo += "[O]
"

				usr << browse(objinfo,"window=sandbox")

			//
			// Safespawn checks to see if spawning is disabled.
			//
			if("hsb_safespawn")
				if(!hsboxspawn)
					usr << browse(null,"window=sandbox")
					return

				var/typepath = text2path(href_list["path"])
				if(!typepath)
					usr << "Bad path: \"[href_list["path"]]\""
					return
				new typepath(usr.loc)

				if(config.sandbox_autoclose)
					usr << browse(null,"window=sandbox")
			//
			// For everything else in the href list
			//
			if("hsbspawn")
				var/typepath = text2path(href_list["path"])
				if(!typepath)
					usr << "Bad path: \"[href_list["path"]]\""
					return
				new typepath(usr.loc)

				if(config.sandbox_autoclose)
					usr << browse(null,"window=sandbox")


code:
/datum/game_mode/sandbox
	name = "sandbox"
	config_tag = "sandbox"
	required_players = 0

/datum/game_mode/sandbox/announce()
	world << "The current game mode is - Sandbox!"
	world << "Build your own station with the sandbox-panel command!"

/datum/game_mode/sandbox/pre_setup()
	for(var/mob/M in player_list)
		M.CanBuild()
	return 1

/datum/game_mode/sandbox/post_setup()
	..()
	SSshuttle.emergencyNoEscape = 1


code:
/datum/subsystem/ticker/proc/setupGenetics()
	var/list/avnums = new /list(DNA_STRUC_ENZYMES_BLOCKS)
	for(var/i=1, i<=DNA_STRUC_ENZYMES_BLOCKS, i++)
		avnums[i] = i

	for(var/A in typesof(/datum/mutation/human) - /datum/mutation/human)
		var/datum/mutation/human/B = new A()
		if(B.dna_block == NON_SCANNABLE)	return
		B.dna_block = pick_n_take(avnums)
		if(B.quality == POSITIVE)
			good_mutations |= B
		else if(B.quality == NEGATIVE)
			bad_mutations |= B
		else if(B.quality == MINOR_NEGATIVE)
			not_good_mutations |= B

/datum/subsystem/ticker/proc/setupFactions()
	// Populate the factions list:
	for(var/typepath in typesof(/datum/faction))
		var/datum/faction/F = new typepath()
		if(!F.name)
			qdel(F)
			continue
		else
			factions.Add(F)
			availablefactions.Add(F)

	// Populate the syndicate coalition:
	for(var/datum/faction/syndicate/S in factions)
		syndicate_coalition.Add(S)


code:
#define LIGHT_DAM_THRESHOLD 4
#define LIGHT_HEAL_THRESHOLD 2
#define LIGHT_DAMAGE_TAKEN 10

/*

SHADOWLING: A gamemode based on previously-run events

Aliens called shadowlings are on the station.
These shadowlings can 'enthrall' crew members and enslave them.
They also burn in the light but heal rapidly whilst in the dark.
The game will end under two conditions:
	1. The shadowlings die
	2. The emergency shuttle docks at CentCom

Shadowling strengths:
	- The dark
	- Hard vacuum (They are not affected by it)
	- Their thralls who are not harmed by the light
	- Stealth

Shadowling weaknesses:
	- The light
	- Fire
	- Enemy numbers
	- Lasers (Lasers are concentrated light and do more damage)
	- Flashbangs (High stun and high burn damage; if the light stuns humans, you bet your ass it'll hurt the shadowling very much!)

Shadowlings start off disguised as normal crew members, and they only have two abilities: Hatch and Enthrall.
They can still enthrall and perhaps complete their objectives in this form.
Hatch will, after a short time, cast off the human disguise and assume the shadowling's true identity.
They will then assume the normal shadowling form and gain their abilities.

The shadowling will seem OP, and that's because it kinda is. Being restricted to the dark while being alone most of the time is extremely difficult and as such the shadowling needs powerful abilities.
Made by Xhuis

*/

/*
	GAMEMODE
*/

/datum/game_mode
	var/list/datum/mind/shadows = list()
	var/list/datum/mind/thralls = list()
	var/list/shadow_objectives = list()
	var/required_thralls = 15 //How many thralls are needed (hardcoded for now)
	var/shadowling_ascended = 0 //If at least one shadowling has ascended
	var/shadowling_dead = 0 //is shadowling kill

/proc/is_thrall(var/mob/living/M)
	return istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.thralls)

/proc/is_shadow_or_thrall(var/mob/living/M)
	return istype(M) && M.mind && ticker && ticker.mode && ((M.mind in ticker.mode.thralls) || (M.mind in ticker.mode.shadows))

/proc/is_shadow(var/mob/living/M)
	return istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.shadows)

/datum/game_mode/shadowling
	name = "shadowling"
	config_tag = "shadowling"
	antag_flag = BE_SHADOWLING
	required_players = 20
	required_enemies = 2
	recommended_enemies = 2
	restricted_jobs = list("AI", "Cyborg", "MoMMI")
	protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")

/datum/game_mode/shadowling/announce()
	world << "The current game mode is - Shadowling!"
	world << "There are alien shadowlings on the station. Crew: Kill the shadowlings before they can eat or enthrall the crew. Shadowlings: Enthrall the crew while remaining in hiding."

/datum/game_mode/shadowling/pre_setup()
	if(config.protect_roles_from_antagonist)
		restricted_jobs += protected_jobs

	if(config.protect_assistant_from_antagonist)
		restricted_jobs += "Assistant"

	var/shadowlings = 2 //How many shadowlings there are; hardcoded to 2

	while(shadowlings)
		var/datum/mind/shadow = pick(antag_candidates)
		shadows += shadow
		antag_candidates -= shadow
		modePlayer += shadow
		shadow.special_role = "Shadowling"
		shadow.restricted_roles = restricted_jobs
		shadowlings--
	return 1

/datum/game_mode/shadowling/post_setup()
	for(var/datum/mind/shadow in shadows)
		log_game("[shadow.key] (ckey) has been selected as a Shadowling.")
		sleep(10)
		shadow.current << "
"
		shadow.current << "You are a shadowling!"
		greet_shadow(shadow)
		finalize_shadowling(shadow)
		process_shadow_objectives(shadow)
		//give_shadowling_abilities(shadow)
	..()
	return

/datum/game_mode/proc/greet_shadow(var/datum/mind/shadow)
	shadow.current << "Currently, you are disguised as an employee aboard [world.name]."
	shadow.current << "In your limited state, you have three abilities: Enthrall, Hatch, and Hivemind Commune."
	shadow.current << "Any other shadowlings are you allies. You must assist them as they shall assist you."
	shadow.current << "If you are new to shadowling, or want to read about abilities, check the wiki page at https://tgstation13.org/wiki/Shadowling
"

/datum/game_mode/proc/process_shadow_objectives(var/datum/mind/shadow_mind)
	var/objective = "enthrall" //may be devour later, but for now it seems murderbone-y

	if(objective == "enthrall")
		var/objective_explanation = "Ascend to your true form by use of the Ascendance ability. This may only be used with [required_thralls] collective thralls, while hatched, and is unlocked with the Collective Mind ability."
		shadow_objectives += "enthrall"
		shadow_mind.memory += "Objective #1: [objective_explanation]"
		shadow_mind.current << "Objective #1: [objective_explanation]
"

/datum/game_mode/proc/finalize_shadowling(var/datum/mind/shadow_mind)
	var/mob/living/carbon/human/S = shadow_mind.current
	shadow_mind.current.verbs += /mob/living/carbon/human/proc/shadowling_hatch
	shadow_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/enthrall
	spawn(0)
		shadow_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
		update_shadow_icons_added(shadow_mind)
		if(shadow_mind.assigned_role == "Clown")
			S << "Your alien nature has allowed you to overcome your clownishness."
			S.dna.remove_mutation(CLOWNMUT)

/datum/game_mode/proc/add_thrall(datum/mind/new_thrall_mind)
	if (!istype(new_thrall_mind))
		return 0
	if(!(new_thrall_mind in thralls))
		update_shadow_icons_added(new_thrall_mind)
		thralls += new_thrall_mind
		new_thrall_mind.current.attack_log += "\[[time_stamp()]\] Became a thrall"
		new_thrall_mind.memory += "The Shadowlings' Objectives: Ascend to your true form by use of the Ascendance ability. \
		This may only be used with [required_thralls] collective thralls, while hatched, and is unlocked with the Collective Mind ability."
		new_thrall_mind.current << "The objectives of your shadowlings:: Ascend to your true form by use of the Ascendance ability. \
		This may only be used with [required_thralls] collective thralls, while hatched, and is unlocked with the Collective Mind ability."
		new_thrall_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
		return 1

/*
	GAME FINISH CHECKS
*/

/datum/game_mode/shadowling/check_finished()
	var/shadows_alive = 0 //and then shadowling was kill
	for(var/datum/mind/shadow in shadows) //but what if shadowling was not kill?
		if(!istype(shadow.current,/mob/living/carbon/human) && !istype(shadow.current,/mob/living/simple_animal/ascendant_shadowling))
			continue
		if(shadow.current.stat == DEAD)
			continue
		shadows_alive++
	if(shadows_alive)
		return ..()
	else
		shadowling_dead = 1 //but shadowling was kill :(
		return 1

/datum/game_mode/shadowling/proc/check_shadow_victory()
	var/success = 0 //Did they win?
	if(shadow_objectives.Find("enthrall"))
		success = shadowling_ascended
	return success

/datum/game_mode/shadowling/declare_completion()
	if(check_shadow_victory() && SSshuttle.emergency.mode >= SHUTTLE_ESCAPE) //Doesn't end instantly - this is hacky and I don't know of a better way ~X
		world << "The shadowlings have ascended and taken over the station!"
	else if(shadowling_dead && !check_shadow_victory()) //If the shadowlings have ascended, they can not lose the round
		world << "The shadowlings have been killed by the crew!"
	else if(!check_shadow_victory() && SSshuttle.emergency.mode >= SHUTTLE_ESCAPE)
		world << "The crew has escaped the station before the shadowlings could ascend!"
	..()
	return 1

/datum/game_mode/proc/auto_declare_completion_shadowling()
	var/text = ""
	if(shadows.len)
		text += "
The shadowlings were:"
		for(var/datum/mind/shadow in shadows)
			text += printplayer(shadow)
		text += "
"
		if(thralls.len)
			text += "
The thralls were:"
			for(var/datum/mind/thrall in thralls)
				text += printplayer(thrall)
	text += "
"
	world << text

/*
	MISCELLANEOUS
*/

/datum/species/shadow/ling
	//Normal shadowpeople but with enhanced effects
	name = "Shadowling"
	id = "shadowling"
	say_mod = "chitters"
	specflags = list(NOBREATH,NOBLOOD,RADIMMUNE,NOGUNS) //Can't use guns due to muzzle flash
	burnmod = 2 //2x burn damage lel
	heatmod = 2

/datum/species/shadow/ling/spec_life(mob/living/carbon/human/H)
	//H.shadowling_status = 1 //If they are affected more strongly by flashes and stuff
	var/light_amount = 0
	H.nutrition = NUTRITION_LEVEL_WELL_FED //i aint never get hongry
	if(isturf(H.loc)) //Copypasta
		var/turf/T = H.loc
		var/area/A = T.loc
		if(A)
			if(A.lighting_use_dynamic)	light_amount = T.get_lumcount() * 10
			else						light_amount =  10
		if(light_amount > LIGHT_DAM_THRESHOLD) //Not complete blackness - they can live in very small light levels plus starlight
			H.take_overall_damage(0, LIGHT_DAMAGE_TAKEN)
			H << "The light burns you!"
			H << 'sound/weapons/sear.ogg'
		else if (light_amount < LIGHT_HEAL_THRESHOLD)
			H.heal_overall_damage(5,5)
			H.adjustToxLoss(-5)
			H.adjustBrainLoss(-25) //gibbering shadowlings are hilarious but also bad to have
			H.adjustCloneLoss(-1)
			H.SetWeakened(0)
			H.SetStunned(0)

/datum/game_mode/proc/update_shadow_icons_added(datum/mind/shadow_mind)
	var/datum/atom_hud/antag/shadow_hud = huds[ANTAG_HUD_SHADOW]
	shadow_hud.join_hud(shadow_mind.current)
	set_antag_hud(shadow_mind.current, ((shadow_mind in shadows) ? "shadowling" : "thrall"))

/datum/game_mode/proc/update_shadow_icons_removed(datum/mind/shadow_mind) //This should never actually occur, but it's here anyway.
	var/datum/atom_hud/antag/shadow_hud = huds[ANTAG_HUD_SHADOW]
	shadow_hud.leave_hud(shadow_mind.current)
	set_antag_hud(shadow_mind.current, null)


code:
/obj/effect/proc_holder/spell/targeted/glare
	name = "Glare"
	desc = "Stuns and mutes a target for a decent duration."
	panel = "Shadowling Abilities"
	charge_max = 300
	clothes_req = 0

/obj/effect/proc_holder/spell/targeted/glare/cast(list/targets)
	for(var/mob/living/carbon/human/target in targets)
		if(!ishuman(target))
			charge_counter = charge_max
			return
		if(target.stat)
			charge_counter = charge_max
			return
		if(is_shadow_or_thrall(target))
			usr << "You don't see why you would want to paralyze an ally."
			charge_counter = charge_max
			return

		usr.visible_message("[usr]'s eyes flash a blinding red!")
		target.visible_message("[target] freezes in place, their eyes glazing over...")
		if(in_range(target, usr))
			target << "Your gaze is forcibly drawn into [usr]'s eyes, and you are mesmerized by the heavenly lights..."
		else //Only alludes to the shadowling if the target is close by
			target << "Red lights suddenly dance in your vision, and you are mesmerized by the heavenly lights..."
		target.Stun(10)
		if(target.reagents)
			target.reagents.add_reagent("mutetoxin", 4) //This is really bad but it's the only way it works.

/obj/effect/proc_holder/spell/aoe_turf/veil
	name = "Veil"
	desc = "Extinguishes all electronic lights in a decent radius."
	panel = "Shadowling Abilities"
	charge_max = 250 //Short cooldown because people can just turn the lights back on
	clothes_req = 0
	range = 5

/obj/effect/proc_holder/spell/aoe_turf/veil/cast(list/targets)
	usr << "You silently disable all nearby lights."
	var/list/blacklisted_lights = list(/obj/item/device/flashlight/flare, /obj/item/device/flashlight/slime)
	for(var/turf/T in targets)
		for(var/obj/item/device/flashlight/F in T.contents)
			if(is_type_in_list(F, blacklisted_lights))
				F.visible_message("[F] goes slightly dim for a moment.")
				return
			F.on = 0
			F.visible_message("[F] gutters and falls dark.")
			F.update_brightness()
		for(var/obj/machinery/light/L in T.contents)
			L.on = 0
			L.visible_message("[L] flickers and falls dark.")
			L.update(0)
		for(var/obj/item/device/pda/P in T.contents)
			P.fon = 0
			P.set_light(0)
		for(var/obj/effect/glowshroom/G in orange(2, usr)) //Very small radius
			G.visible_message("\The [G] withers away!")
			qdel(G)
		for(var/mob/living/carbon/human/H in T.contents)
			for(var/obj/item/device/flashlight/F in H)
				if(is_type_in_list(F, blacklisted_lights))
					F.visible_message("[F] goes slightly dim for a moment.")
					return
				F.on = 0
				F.visible_message("[F] gutters and falls dark.")
				F.update_brightness()
			for(var/obj/item/device/pda/P in H)
				P.fon = 0
				P.set_light(0) //failsafe
			if(H != usr)
				H << "You feel a chill and are plunged into darkness."
		//	H.set_light = 0 //This is required with the object-based lighting Required no longer

/obj/effect/proc_holder/spell/targeted/shadow_walk
	name = "Shadow Walk"
	desc = "Phases you into the space between worlds for a short time, allowing movement through walls and invisbility."
	panel = "Shadowling Abilities"
	charge_max = 600
	clothes_req = 0
	range = -1
	include_user = 1

/obj/effect/proc_holder/spell/targeted/shadow_walk/cast(list/targets)
	for(var/mob/living/user in targets)
		playsound(user.loc, 'sound/effects/bamf.ogg', 50, 1)
		user.visible_message("[user] vanishes into thin air!", "You enter the space between worlds as a passageway.")
		user.SetStunned(0)
		user.SetWeakened(0)
		user.incorporeal_move = 1
		user.alpha = 0
		if(user.buckled)
			user.buckled.unbuckle_mob()
		sleep(40) //4 seconds
		user.visible_message("[user] appears out of nowhere!", "The pressure becomes too much and you vacate the interdimensional darkness.")
		user.incorporeal_move = 0
		user.alpha = 255

/obj/effect/proc_holder/spell/aoe_turf/flashfreeze
	name = "Flash Freeze"
	desc = "Instantly freezes the blood of nearby people, stunning them and causing burn damage."
	panel = "Shadowling Abilities"
	range = 5
	charge_max = 1200
	clothes_req = 0

/obj/effect/proc_holder/spell/aoe_turf/flashfreeze/cast(list/targets)
	usr << "You freeze the nearby air."
	playsound(usr.loc, 'sound/effects/ghost2.ogg', 50, 1)

	for(var/turf/T in targets)
		for(var/mob/living/carbon/human/target in T.contents)
			if(is_shadow_or_thrall(target))
				if(target == usr) //No message for the user, of course
					continue
				else
					target << "You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!"
					continue
			target << "You are hit by a blast of paralyzingly cold air and feel goosebumps break out across your body!"
			target.Stun(2)
			if(target.bodytemperature)
				target.bodytemperature -= 200 //Extreme amount of initial cold
			if(target.reagents)
				target.reagents.add_reagent("frostoil", 15) //Half of a cryosting

//Enthrall is the single most important spell
/obj/effect/proc_holder/spell/targeted/enthrall
	name = "Enthrall"
	desc = "Allows you to enslave a conscious, non-braindead, non-catatonic human to your will. This takes some time to cast."
	panel = "Shadowling Abilities"
	charge_max = 450
	clothes_req = 0
	range = 1 //Adjacent to user
	var/enthralling = 0

/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets)
	for(var/mob/living/carbon/human/target in targets)
		if(!in_range(usr, target))
			usr << "You need to be closer to enthrall [target]."
			charge_counter = charge_max
			return
		if(!target.ckey)
			usr << "The target has no mind."
			charge_counter = charge_max
			return
		if(target.stat)
			usr << "The target must be conscious."
			charge_counter = charge_max
			return
		if(is_shadow_or_thrall(target))
			usr << "You can not enthrall allies."
			charge_counter = charge_max
			return
		if(!ishuman(target))
			usr << "You can only enthrall humans."
			charge_counter = charge_max
			return
		if(enthralling)
			usr << "You are already enthralling!"
			charge_counter = charge_max
			return
		enthralling = 1
		usr << "This target is valid. You begin the enthralling."
		target << "[usr] focuses in concentration. Your head begins to ache."

		for(var/progress = 0, progress <= 3, progress++)
			switch(progress)
				if(1)
					usr << "You begin allocating energy for the enthralling."
					usr.visible_message("[usr]'s eyes begin to throb a piercing red.")
				if(2)
					usr << "You begin the enthralling of [target]."
					usr.visible_message("[usr] leans over [target], their eyes glowing a deep crimson, and stares into their face.")
					target << "Your gaze is forcibly drawn into a blinding red light. You fall to the floor as conscious thought is wiped away."
					target.Weaken(12)
					sleep(20)
					if(isloyal(target))
						usr << "They are enslaved by Nanotrasen. You begin to shut down the nanobot implant - this will take some time."
						usr.visible_message("[usr] halts for a moment, then begins passing its hand over [target]'s body.")
						target << "You feel your loyalties begin to weaken!"
						sleep(150) //15 seconds - not spawn() so the enthralling takes longer
						usr << "The nanobots composing the loyalty implant have been rendered inert. Now to continue."
						usr.visible_message("[usr] halts thier hand and resumes staring into [target]'s face.")
						for(var/obj/item/weapon/implant/loyalty/L in target)
							if(L && L.implanted)
								qdel(L)
								target << "Your unwavering loyalty to Nanotrasen falters, dims, dies."
				if(3)
					usr << "You begin rearranging [target]'s memories."
					usr.visible_message("[usr]'s eyes flare brightly, and a horrible grin begins to spread across [target]'s face...")
					target << "Your head cries out. The veil of reality begins to crumple and something evil bleeds through." //Ow the edge
			if(!do_mob(usr, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a loyalty implant
				usr << "The enthralling has been interrupted - your target's mind returns to its previous state."
				target << "Your thoughts become coherent once more. Already you can barely remember what's happened to you."
				enthralling = 0
				return

		enthralling = 0
		usr << "You have enthralled [target]!"
		target << "You see the Truth. Reality has been torn away and you realize what a fool you've been."
		target << "The shadowlings are your masters. Serve them above all else and ensure they complete their goals."
		target << "You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls."
		target << "You can communicate with the other enlightened ones by using the Hivemind Commune ability."
		target.adjustOxyLoss(-200) //In case the shadowling was choking them out
		ticker.mode.add_thrall(target.mind)
		target.mind.special_role = "Thrall"

/obj/effect/proc_holder/spell/targeted/shadowling_hivemind
	name = "Hivemind Commune"
	desc = "Allows you to silently communicate with all other shadowlings and thralls."
	panel = "Shadowling Abilities"
	charge_max = 25
	clothes_req = 0
	range = -1
	include_user = 1

/obj/effect/proc_holder/spell/targeted/shadowling_hivemind/cast(list/targets)
	for(var/mob/living/user in targets)
		var/text = stripped_input(user, "What do you want to say to fellow thralls and shadowlings?.", "Hive Chat", "")
		if(!text)
			return
		for(var/mob/M in mob_list)
			if(is_shadow_or_thrall(M) || (M in dead_mob_list))
				M << "\[Hive Chat\] [usr.real_name]: [text]"

/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor
	name = "Regenerate Chitin"
	desc = "Re-forms protective chitin that may be lost during cloning or similar processes."
	panel = "Shadowling Abilities"
	charge_max = 600
	clothes_req = 0
	range = -1
	include_user = 1

/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor/cast(list/targets)
	for(var/mob/living/user in targets)
		user.visible_message("[user]'s skin suddenly bubbles and begins to shift around their body!", \
							 "You regenerate your protective armor and cleanse your form of defects.")
		user.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(usr), slot_w_uniform)
		user.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(usr), slot_shoes)
		user.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(usr), slot_wear_suit)
		user.equip_to_slot_or_del(new /obj/item/clothing/head/shadowling(usr), slot_head)
		user.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(usr), slot_gloves)
		user.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(usr), slot_wear_mask)
		user.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/shadowling(usr), slot_glasses)
		hardset_dna(user, null, null, null, null, /datum/species/shadow/ling) //can't be a shadowling without being a shadowling

/obj/effect/proc_holder/spell/targeted/collective_mind
	name = "Collective Hivemind"
	desc = "Gathers the power of all of your thralls and compares it to what is needed for ascendance. Also gains you new abilities."
	panel = "Shadowling Abilities"
	charge_max = 300 //30 second cooldown to prevent spam
	clothes_req = 0
	range = -1
	include_user = 1
	var/blind_smoke_acquired
	var/screech_acquired
	var/drain_thrall_acquired
	var/thrall_swap_acquired

/obj/effect/proc_holder/spell/targeted/collective_mind/cast(list/targets)
	for(var/mob/living/user in targets)
		var/thralls = 0
		var/victory_threshold = 15
		var/mob/M

		user << "You focus your telepathic energies abound, harnessing and drawing together the strength of your thralls."

		for(M in living_mob_list)
			if(is_thrall(M))
				thralls++
				M << "You feel hooks sink into your mind and pull."

		if(!do_after(user, 30))
			user << "Your concentration has been broken. The mental hooks you have sent out now retract into your mind."
			return

		if(thralls >= 3 && !blind_smoke_acquired)
			blind_smoke_acquired = 1
			user << "The power of your thralls has granted you the Blinding Smoke ability. It will create a choking cloud that will blind any non-thralls who enter. \
			"
			user.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/blindness_smoke

		if(thralls >= 5 && !drain_thrall_acquired)
			drain_thrall_acquired = 1
			user << "The power of your thralls has granted you the Drain Thrall ability. You can now drain nearby thralls to heal yourself."
			user.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/drain_thralls

		if(thralls >= 7 && !screech_acquired)
			screech_acquired = 1
			user << "The power of your thralls has granted you the Sonic Screech ability. This ability will shatter nearby windows and deafen enemies."
			user.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/unearthly_screech

		if(thralls >= 9 && !thrall_swap_acquired)
			thrall_swap_acquired = 1
			user << "The power of your thralls has granted you the Spatial Relocation ability. This will, allow you to instantly swap places with one of your thralls in \
			addition to shattering nearby lights."
			user.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/spatial_relocation

		if(thralls < victory_threshold)
			user << "You do not have the power to ascend. You require [victory_threshold] thralls, but only [thralls] living thralls are present."

		else if(thralls >= victory_threshold)
			usr << "You are now powerful enough to ascend. Use the Ascendance ability when you are ready. This will kill all of your thralls."
			usr << "You may find Ascendance in the Shadowling Evolution tab."
			for(M in living_mob_list)
				if(is_shadow(M))
					M.mind.spell_list -= /obj/effect/proc_holder/spell/targeted/collective_mind
					M.mind.current.verbs -= /mob/living/carbon/human/proc/shadowling_hatch //In case a shadowling hasn't hatched
					M.mind.current.verbs += /mob/living/carbon/human/proc/shadowling_ascendance
					if(M == usr)
						return
					M << "[user.real_name] has coalesced the strength of the thralls. You can draw upon it at any time to ascend." //Tells all the other shadowlings

/obj/effect/proc_holder/spell/targeted/blindness_smoke
	name = "Blindness Smoke"
	desc = "Spews a cloud of smoke which will blind enemies."
	panel = "Shadowling Abilities"
	charge_max = 600
	clothes_req = 0
	range = -1
	include_user = 1

/obj/effect/proc_holder/spell/targeted/blindness_smoke/cast(list/targets) //Extremely hacky
	for(var/mob/living/user in targets)
		user.visible_message("[user] suddenly bends over and coughs out a cloud of black smoke, which begins to spread rapidly!")
		user << "You regurgitate a vast cloud of blinding smoke."
		playsound(user, 'sound/effects/bamf.ogg', 50, 1)
		var/obj/item/weapon/reagent_containers/glass/beaker/large/B = new /obj/item/weapon/reagent_containers/glass/beaker/large(user.loc)
		B.reagents.clear_reagents() //Just in case!
		B.icon_state = null //Invisible
		B.reagents.add_reagent("blindness_smoke", 10)
		var/datum/effect/effect/system/chem_smoke_spread/S = new /datum/effect/effect/system/chem_smoke_spread
		S.attach(B)
		if(S)
			S.set_up(B.reagents, 10, 0, B.loc)
			S.start()
			sleep(10)
			S.start()
		qdel(B)

datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowlings/thralls
	name = "!(%@ ERROR )!@$"
	id = "blindness_smoke"
	description = "<::ERROR::> CANNOT ANALYZE REAGENT <::ERROR::>"
	color = "#000000" //Complete black (RGB: 0, 0, 0)
	metabolization_rate = 100 //lel

datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
	if(!M) M = holder.my_atom
	if(!is_shadow_or_thrall(M))
		M << "You breathe in the black smoke, and your eyes burn horribly!"
		M.eye_blind = 5
		if(prob(25))
			M.visible_message("[M] screams and claws at their eyes!")
			M.Stun(2)
	else
		M << "You breathe in the black smoke, and you feel revitalized!"
		M.heal_organ_damage(2,2)
		M.adjustOxyLoss(-2)
		M.adjustToxLoss(-2)
	..()
	return

/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech
	name = "Sonic Screech"
	desc = "Deafens, stuns, and confuses nearby people. Also shatters windows."
	panel = "Shadowling Abilities"
	range = 7
	charge_max = 300
	clothes_req = 0

/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech/cast(list/targets)
	usr.audible_message("[usr] lets out a horrible scream!")
	playsound(usr.loc, 'sound/effects/screech.ogg', 100, 1)

	for(var/turf/T in targets)
		for(var/mob/target in T.contents)
			if(is_shadow_or_thrall(target))
				if(target == usr) //No message for the user, of course
					continue
				else
					continue
			if(iscarbon(target))
				var/mob/living/carbon/M = target
				M << "A spike of pain drives into your head and scrambles your thoughts!"
				M.confused += 10
				M.setEarDamage(M.ear_damage + 3)
			else if(issilicon(target))
				var/mob/living/silicon/S = target
				S << "ERROR $!(@ ERROR )#^! SENSOR INTERFERENCE DETECTED"
				S << 'sound/misc/interference.ogg'
				playsound(S, 'sound/machines/warning-buzzer.ogg', 50, 1)
				var/datum/effect/effect/system/spark_spread/sp = new /datum/effect/effect/system/spark_spread
				sp.set_up(5, 1, S)
				sp.start()
				S.Weaken(6)
		for(var/obj/structure/window/W in T.contents)
			W.hit(rand(50,100))

/obj/effect/proc_holder/spell/aoe_turf/drain_thralls
	name = "Drain Thralls"
	desc = "Damages nearby thralls, draining their life and healing yourself."
	panel = "Shadowling Abilities"
	range = 3
	charge_max = 100
	clothes_req = 0
	var/thralls_drained = 0
	var/list/nearby_thralls = list()

/obj/effect/proc_holder/spell/aoe_turf/drain_thralls/cast(list/targets)
	thralls_drained = 0
	nearby_thralls = list()
	for(var/turf/T in targets)
		for(var/mob/living/carbon/M in T.contents)
			if(is_thrall(M))
				thralls_drained++
				nearby_thralls.Add(M)
				M << "You feel a curious draining sensation and a wave of exhaustion washes over you."
		for(var/mob/living/carbon/M in nearby_thralls)
			nearby_thralls.Remove(M) //To prevent someone dying like a zillion times
			M.take_organ_damage(25/thralls_drained,25/thralls_drained) //For every nearby thrall, the damage to each is reduced - 1 thrall = 50 for him, 2 thralls = 25 for each, etc.
			usr << "You draw the life from [M] to heal your wounds."
	if(thralls_drained)
		var/mob/living/carbon/U = usr
		U.heal_organ_damage(25, 25)
	else
		charge_counter = charge_max
		usr << "There were no nearby thralls for you to drain."

/obj/effect/proc_holder/spell/targeted/spatial_relocation
	name = "Spatial Relocation"
	desc = "Swaps places with a thrall and breaks nearby lights."
	panel = "Shadowling Abilities"
	range = -1
	charge_max = 3000
	clothes_req = 0
	include_user = 1
	var/list/thralls_in_world = list()

/obj/effect/proc_holder/spell/targeted/spatial_relocation/cast(list/targets, distanceoverride)
	for(var/mob/living/carbon/human/M in world)
		if(is_thrall(M))
			thralls_in_world += M
	if(!thralls_in_world)
		charge_counter = charge_max
		return
	var/mob/living/carbon/thrall_to_swap = input("Who do you wish to swap places with?", "Available Thralls") as null|anything in (thralls_in_world)
	var/turf/shadowturf = get_turf(usr)
	var/turf/thrallturf = get_turf(thrall_to_swap)
	thrall_to_swap.visible_message("[thrall_to_swap] suddenly vanishes in a puff of black smoke!")
	thrall_to_swap << "You feel a brief sense of nausea before finding yourself in an entirely new place!"
	usr.visible_message("[usr] suddenly goes transparent and vanishes!")
	usr << "You experience vertigo as you swap your location with [thrall_to_swap]'s."
	thrall_to_swap.loc = shadowturf
	usr.loc = thrallturf
	thrall_to_swap.Weaken(4)
	usr.Weaken(4)
	usr.regenerate_icons()
	thrall_to_swap.regenerate_icons()

// ASCENDANT ABILITIES BEYOND THIS POINT //

/obj/effect/proc_holder/spell/targeted/annihilate
	name = "Annihilate"
	desc = "Gibs a human after a short time."
	panel = "Ascendant"
	range = 7
	charge_max = 300
	clothes_req = 0

/obj/effect/proc_holder/spell/targeted/annihilate/cast(list/targets)
	var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
	if(SHA.phasing)
		usr << "You are not in the same plane of existence. Unphase first."
		charge_counter = charge_max
		return

	for(var/mob/living/carbon/human/boom in targets)
		if(is_shadow_or_thrall(boom))
			usr << "Making an ally explode seems unwise."
			charge_counter = charge_max
			return
		usr.visible_message("[usr]'s eyes flare as they gesture at [boom]!", \
							"You direct a lance of telekinetic energy at [boom].")
		boom << "You feel an immense pressure building all across your body!"
		boom.Stun(10)
		boom.audible_message("[boom] screams!")
		sleep(20)
		playsound(boom, 'sound/effects/splat.ogg', 100, 1)
		boom.visible_message("[boom] explodes!")
		boom.gib()

/obj/effect/proc_holder/spell/targeted/hypnosis
	name = "Hypnosis"
	desc = "Instantly enthralls a human."
	panel = "Ascendant"
	range = 7
	charge_max = 450
	clothes_req = 0

/obj/effect/proc_holder/spell/targeted/hypnosis/cast(list/targets)
	var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
	if(SHA.phasing)
		charge_counter = charge_max
		usr << "You are not in the same plane of existence. Unphase first."
		return

	for(var/mob/living/carbon/human/target in targets)
		if(is_shadow_or_thrall(target))
			usr << "You cannot enthrall an ally."
			charge_counter = charge_max
			return
		if(!target.ckey)
			usr << "The target has no mind."
			charge_counter = charge_max
			return
		if(target.stat)
			usr << "The target must be conscious."
			charge_counter = charge_max
			return
		if(!ishuman(target))
			usr << "You can only enthrall humans."
			charge_counter = charge_max
			return

		usr << "You instantly rearrange [target]'s memories, hyptonitizing them into a thrall."
		target << "An agonizing spike of pain drives into your mind, and--"
		target << "And you see the Truth. Reality has been torn away and you realize what a fool you've been."
		target << "The shadowlings are your masters. Serve them above all else and ensure they complete their goals."
		target << "You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls."
		target << "You can communicate with the other enlightened ones by using the Hivemind Commune ability."
		ticker.mode.add_thrall(target.mind)
		target.mind.special_role = "Thrall"
		var/datum/mind/thrall_mind = target.mind
		thrall_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind

/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift
	name = "Phase Shift"
	desc = "Phases you into the space between worlds at will, allowing you to move through walls and become invisible."
	panel = "Ascendant"
	range = -1
	include_user = 1
	charge_max = 15
	clothes_req = 0

/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift/cast(list/targets)
	var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
	for(SHA in targets)
		SHA.phasing = !SHA.phasing
		if(SHA.phasing)
			SHA.visible_message("[SHA] suddenly vanishes!", \
			"You begin phasing through planes of existence. Use the ability again to return.")
			SHA.incorporeal_move = 1
			SHA.alpha = 0
		else
			SHA.visible_message("[SHA] suddenly appears from nowhere!", \
			"You return from the space between worlds.")
			SHA.incorporeal_move = 0
			SHA.alpha = 255

/obj/effect/proc_holder/spell/aoe_turf/glacial_blast
	name = "Glacial Blast"
	desc = "Extremely empowered version of Flash Freeze."
	panel = "Ascendant"
	range = 5
	charge_max = 600
	clothes_req = 0

/obj/effect/proc_holder/spell/aoe_turf/glacial_blast/cast(list/targets)
	var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
	if(SHA.phasing)
		usr << "You are not in the same plane of existence. Unphase first."
		return

	usr << "You freeze the nearby air."
	playsound(usr.loc, 'sound/effects/ghost2.ogg', 100, 1)

	for(var/turf/T in targets)
		for(var/mob/living/carbon/human/target in T.contents)
			if(is_shadow_or_thrall(target))
				if(target == usr) //No message for the user, of course
					continue
				else
					target << "You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!"
					continue
			target << "You are hit by a blast of cold unlike anything you have ever felt. Your limbs instantly lock in place and you feel ice burns across your body!"
			target.Weaken(15)
			if(target.bodytemperature)
				target.bodytemperature -= INFINITY //:^)
			target.take_organ_damage(0,80)

/obj/effect/proc_holder/spell/targeted/vortex
	name = "Vortex"
	desc = "Tears open a hole in reality. Anyone, INCLUDING YOU, walking through it will be trapped there for eternity."
	panel = "Ascendant"
	range = -1
	include_user = 1
	charge_max = 1200
	clothes_req = 0

/obj/effect/proc_holder/spell/targeted/vortex/cast(list/targets)
	var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
	if(SHA.phasing)
		usr << "You are not in the same plane of existence. Unphase first."
		return

	for(SHA in targets)
		SHA.visible_message("[SHA] raises their arms upward as the markings on their body flare a blinding red!", \
						"You tear open a rift to the black space between worlds. It would be wise to avoid it.")

		new /obj/structure/shadow_vortex(SHA.loc)

/obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant
	name = "Ascendant Commune"
	desc = "Allows you to silently communicate with all other shadowlings and thralls."
	panel = "Ascendant"
	charge_max = 20
	clothes_req = 0
	range = -1
	include_user = 1

/obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant/cast(list/targets)
	for(var/mob/living/user in targets)
		var/text = stripped_input(user, "What do you want to say to fellow thralls and shadowlings?.", "Hive Chat", "")
		if(!text)
			return
		text = "[text]"
		for(var/mob/M in mob_list)
			if(is_shadow_or_thrall(M) || (M in dead_mob_list))
				M << "\[Hive Chat\] [usr.real_name] (ASCENDANT): [text]" //Bigger text for ascendants.


code:
/obj/item/clothing/under/shadowling
	name = "blackened flesh"
	desc = "Black, chitonous skin."
	item_state = "golem"
	origin_tech = null
	icon_state = "golem"
	flags = ABSTRACT | NODROP
	has_sensor = 0
	unacidable = 1

/obj/item/clothing/suit/space/shadowling
	name = "chitin shell"
	desc = "Dark, semi-transparent shell. Protects against vacuum, but not against the light of the stars." //Still takes damage from spacewalking but is immune to space itself
	icon_state = "golem"
	item_state = "golem"
	body_parts_covered = FULL_BODY //Shadowlings are immune to space
	cold_protection = FULL_BODY
	min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
	flags_inv = HIDEGLOVES | HIDESHOES | HIDEJUMPSUIT
	flags = ABSTRACT | NODROP | THICKMATERIAL
	slowdown = 0
	unacidable = 1
	heat_protection = null //You didn't expect a light-sensitive creature to have heat resistance, did you?
	max_heat_protection_temperature = null

/obj/item/clothing/shoes/shadowling
	name = "chitin feet"
	desc = "Charred-looking feet. They have minature hooks that latch onto flooring."
	icon_state = "golem"
	unacidable = 1
	flags = NOSLIP | ABSTRACT | NODROP

/obj/item/clothing/mask/gas/shadowling
	name = "chitin mask"
	desc = "A mask-like formation with slots for facial features. A red film covers the eyes."
	icon_state = "golem"
	item_state = "golem"
	origin_tech = null
	siemens_coefficient = 0
	unacidable = 1
	flags = ABSTRACT | NODROP

/obj/item/clothing/gloves/shadowling
	name = "chitin hands"
	desc = "An electricity-resistant covering of the hands."
	icon_state = "golem"
	item_state = null
	origin_tech = null
	siemens_coefficient = 0
	unacidable = 1
	flags = ABSTRACT | NODROP

/obj/item/clothing/head/shadowling
	name = "chitin helm"
	desc = "A helmet-like enclosure of the head."
	icon_state = "golem"
	item_state = null
	origin_tech = null
	unacidable = 1
	flags = ABSTRACT | NODROP

/obj/item/clothing/glasses/night/shadowling
	name = "crimson eyes"
	desc = "A shadowling's eyes. Very light-sensitive and can detect body heat through walls."
	icon = null
	icon_state = null
	item_state = null
	origin_tech = null
	vision_flags = SEE_MOBS
	darkness_view = 3
	invis_view = 2
	flash_protect = -1
	unacidable = 1
	flags = ABSTRACT | NODROP

/obj/structure/shadow_vortex
	name = "vortex"
	desc = "A swirling hole in the fabric of reality. Eye-watering chimes sound from its depths."
	density = 0
	anchored = 1
	icon = 'icons/effects/genetics.dmi'
	icon_state = "shadow_portal"

/obj/structure/shadow_vortex/New()
	src.audible_message("\The [src] lets out a dismaying screech as dimensional barriers are torn apart!")
	playsound(loc, 'sound/effects/supermatter.ogg', 100, 1)
	sleep(100)
	qdel(src)

/obj/structure/shadow_vortex/Crossed(var/td)
	..()
	if(ismob(td))
		td << "You enter the rift. Sickening chimes begin to jangle in your ears. \
		All around you is endless blackness. After you see something moving, you realize it isn't entirely lifeless." //A bit of spooking before they die
	playsound(loc, 'sound/effects/EMPulse.ogg', 25, 1)
	qdel(td)


code:
//In here: Hatch and Ascendance

/mob/living/carbon/human/proc/shadowling_hatch()
	set category = "Shadowling Evolution"
	set name = "Hatch"

	if(usr.stat)
		return
	usr.verbs -= /mob/living/carbon/human/proc/shadowling_hatch
	switch(alert("Are you sure you want to hatch? You cannot undo this!",,"Yes","No"))
		if("No")
			usr << "You decide against hatching for now."
			usr.verbs += /mob/living/carbon/human/proc/shadowling_hatch
			return
		if("Yes")
			usr.notransform = 1
			usr.visible_message("[usr]'s things suddenly slip off. They hunch over and vomit up a copious amount of purple goo which begins to shape around them!", \
								"You remove any equipment which would hinder your hatching and begin regurgitating the resin which will protect you.")

			for(var/obj/item/I in usr) //drops all items
				usr.unEquip(I)

			sleep(50)
			var/turf/simulated/floor/F
			var/turf/shadowturf = get_turf(usr)
			for(F in orange(1, usr))
				new /obj/structure/alien/resin/wall/shadowling(F)
			for(var/obj/structure/alien/resin/wall/shadowling/R in shadowturf) //extremely hacky
				qdel(R)
				new /obj/structure/alien/weeds/node(shadowturf) //Dim lighting in the chrysalis -- removes itself with the chrysalis

			usr.visible_message("A chrysalis forms around [usr], sealing them inside.", \
								"You create your chrysalis and begin to contort within.")

			sleep(100)
			usr.visible_message("The skin on [usr]'s back begins to split apart. Black spines slowly emerge from the divide.", \
								"Spines pierce your back. Your claws break apart your fingers. You feel excruciating pain as your true form begins its exit.")

			sleep(90)
			usr.visible_message("[usr], now no longer recognizable as human, begins clawing at the resin walls around them.", \
							"Your false skin slips away. You begin tearing at the fragile membrane protecting you.")

			sleep(80)
			playsound(usr.loc, 'sound/weapons/slash.ogg', 25, 1)
			usr << "You rip and slice."
			sleep(10)
			playsound(usr.loc, 'sound/weapons/slashmiss.ogg', 25, 1)
			usr << "The chrysalis falls like water before you."
			sleep(10)
			playsound(usr.loc, 'sound/weapons/slice.ogg', 25, 1)
			usr << "You are free!"

			sleep(10)
			playsound(usr.loc, 'sound/effects/ghost.ogg', 100, 1)
			usr.real_name = "Shadowling ([rand(1,1000)])"
			usr.name = usr.real_name
			usr.notransform = 0
			usr << "YOU LIVE!!!"

			for(var/obj/structure/alien/resin/wall/shadowling/W in orange(usr, 1))
				playsound(W, 'sound/effects/splat.ogg', 50, 1)
				qdel(W)
			for(var/obj/structure/alien/weeds/node/N in shadowturf)
				qdel(N)
			usr.visible_message("The chrysalis explodes in a shower of purple flesh and fluid!")
			var/mob/living/carbon/human/M = usr
			M.underwear = "Nude"
			M.undershirt = "Nude"
			M.socks = "Nude"
			M.faction |= "faithless"

			usr.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(usr), slot_w_uniform)
			usr.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(usr), slot_shoes)
			usr.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(usr), slot_wear_suit)
			usr.equip_to_slot_or_del(new /obj/item/clothing/head/shadowling(usr), slot_head)
			usr.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(usr), slot_gloves)
			usr.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(usr), slot_wear_mask)
			usr.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/shadowling(usr), slot_glasses)
			hardset_dna(usr, null, null, null, null, /datum/species/shadow/ling) //can't be a shadowling without being a shadowling

			sleep(10)
			usr << "Your powers are awoken. You may now live to your fullest extent. Remember your goal. Cooperate with your thralls and allies."
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/glare
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/veil
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadow_walk
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/flashfreeze
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/collective_mind
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_regenarmor

/mob/living/carbon/human/proc/shadowling_ascendance()
	set category = "Shadowling Evolution"
	set name = "Ascendance"

	if(usr.stat)
		return
	usr.verbs -= /mob/living/carbon/human/proc/shadowling_ascendance
	switch(alert("It is time to ascend. Are you completely sure about this? You cannot undo this!",,"Yes","No"))
		if("No")
			usr << "You decide against ascending for now."
			usr.verbs += /mob/living/carbon/human/proc/shadowling_ascendance
			return
		if("Yes")
			usr.notransform = 1
			usr.visible_message("[usr] rapidly bends and contorts, their eyes flaring a deep crimson!", \
								"You begin unlocking the genetic vault within you and prepare yourself for the power to come.")

			sleep(30)
			usr.visible_message("[usr] suddenly shoots up a few inches in the air and begins hovering there, still twisting.", \
								"You hover into the air to make room for your new form.")

			sleep(60)
			usr.visible_message("[usr]'s skin begins to pulse red in sync with their eyes. Their form slowly expands outward.", \
								"You feel yourself beginning to mutate.")

			sleep(20)
			if(!ticker.mode.shadowling_ascended)
				usr << "It isn't enough. Time to draw upon your thralls."
			else
				usr << "After some telepathic searching, you find the reservoir of life energy from the thralls and tap into it."

			sleep(50)
			for(var/mob/M in mob_list)
				if(is_thrall(M) && !ticker.mode.shadowling_ascended)
					M.visible_message("[M] trembles minutely as their form turns to ash, black smoke pouring from their disintegrating face.", \
									  "It's time! Your masters are ascending! Your last thoughts are happy as your body is drained of life.")

					ticker.mode.thralls -= M.mind //To prevent message spam
					M.death(0)
					M.dust()

			usr << "Drawing upon your thralls, you find the strength needed to finish and rend apart the final barriers to godhood."

			sleep(40)
			for(var/mob/living/M in orange(7, src))
				M.Weaken(10)
				M << "An immense pressure slams you onto the ground!"
			usr << "YOU LIVE!!!"
			world << "

A horrible wail echoes in your mind as the world plunges into blackness.

"
			world << 'sound/hallucinations/veryfar_noise.ogg'
			for(var/obj/machinery/power/apc/A in world)
				A.overload_lighting()
			var/mob/A = new /mob/living/simple_animal/ascendant_shadowling(usr.loc)
			usr.mind.spell_list = list()
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/annihilate
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/hypnosis
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_phase_shift
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/glacial_blast
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/vortex
			usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant
			usr.mind.transfer_to(A)
			A.name = usr.real_name
			if(A.real_name)
				A.real_name = usr.real_name
			usr.alpha = 0 //This is pretty bad, but is also necessary for the shuttle call to function properly
			usr.flags |= GODMODE
			usr.notransform = 1
			sleep(50)
			if(!ticker.mode.shadowling_ascended)
				SSshuttle.emergency.request(null, 0.3)
			ticker.mode.shadowling_ascended = 1
			qdel(usr)


code:
/datum/game_mode/traitor/double_agents
	name = "double agents"
	config_tag = "double_agents"
	restricted_jobs = list("Cyborg", "AI", "Captain", "Head of Personnel", "Chief Medical Officer", "Research Director", "Chief Engineer", "Head of Security", "MoMMI") // Human / Minor roles only.
	required_players = 25
	required_enemies = 5
	recommended_enemies = 8

	traitor_name = "double agent"

	traitors_possible = 10 //hard limit on traitors if scaling is turned off
	num_modifier = 6 // Six additional traitors

	var/list/target_list = list()
	var/list/late_joining_list = list()

/datum/game_mode/traitor/double_agents/announce()
	world << "The current game mode is - Double Agents!"
	world << "There are double agents killing eachother! Do not let them succeed!"

/datum/game_mode/traitor/double_agents/post_setup()
	var/i = 0
	for(var/datum/mind/traitor in traitors)
		i++
		if(i + 1 > traitors.len)
			i = 0
		target_list[traitor] = traitors[i + 1]
	..()

/datum/game_mode/traitor/double_agents/forge_traitor_objectives(var/datum/mind/traitor)

	if(target_list.len && target_list[traitor]) // Is a double agent

		// Assassinate
		var/datum/objective/assassinate/kill_objective = new
		kill_objective.owner = traitor
		kill_objective.target = target_list[traitor]
		kill_objective.explanation_text = "Assassinate [kill_objective.target.current.real_name], the [kill_objective.target.assigned_role], the double agent."
		traitor.objectives += kill_objective

		// Escape
		var/datum/objective/escape/escape_objective = new
		escape_objective.owner = traitor
		traitor.objectives += escape_objective

	else
		..() // Give them standard objectives.
	return

/datum/game_mode/traitor/double_agents/add_latejoin_traitor(var/datum/mind/character)

	check_potential_agents()

	// As soon as we get 3 or 4 extra latejoin traitors, make them traitors and kill each other.
	if(late_joining_list.len >= rand(3, 4))
		// True randomness
		shuffle(late_joining_list)
		// Reset the target_list, it'll be used again in force_traitor_objectives
		target_list = list()

		// Basically setting the target_list for who is killing who
		var/i = 0
		for(var/datum/mind/traitor in late_joining_list)
			i++
			if(i + 1 > late_joining_list.len)
				i = 0
			target_list[traitor] = late_joining_list[i + 1]
			traitor.special_role = traitor_name

		// Now, give them their targets
		for(var/datum/mind/traitor in target_list)
			..(traitor)

		late_joining_list = list()
	else
		late_joining_list += character
	return

/datum/game_mode/traitor/double_agents/proc/check_potential_agents()

	for(var/M in late_joining_list)
		if(istype(M, /datum/mind))
			var/datum/mind/agent_mind = M
			if(ishuman(agent_mind.current))
				var/mob/living/carbon/human/H = agent_mind.current
				if(H.stat != DEAD)
					if(H.client)
						continue // It all checks out.

		// If any check fails, remove them from our list
		late_joining_list -= M


code:
/datum/game_mode
	// this includes admin-appointed traitors and multitraitors. Easy!
	var/traitor_name = "traitor"
	var/list/datum/mind/traitors = list()

	var/datum/mind/exchange_red
	var/datum/mind/exchange_blue

/datum/game_mode/traitor
	name = "traitor"
	config_tag = "traitor"
	antag_flag = BE_TRAITOR
	restricted_jobs = list("Cyborg", "MoMMI")//They are part of the AI if he is traitor so are they, they use to get double chances
	protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")//AI", Currently out of the list as malf does not work for shit
	required_players = 0
	required_enemies = 1
	recommended_enemies = 4
	reroll_friendly = 1

	var/traitors_possible = 4 //hard limit on traitors if scaling is turned off
	var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual.

/datum/game_mode/traitor/announce()
	world << "The current game mode is - Traitor!"
	world << "There are syndicate traitors on the station. Do not let the traitors succeed!"

/datum/game_mode/traitor/pre_setup()

	if(config.protect_roles_from_antagonist)
		restricted_jobs += protected_jobs

	if(config.protect_assistant_from_antagonist)
		restricted_jobs += "Assistant"

	var/num_traitors = 1

	if(config.traitor_scaling_coeff)
		num_traitors = max(1, min( round(num_players()/(config.traitor_scaling_coeff*2))+ 2 + num_modifier, round(num_players()/(config.traitor_scaling_coeff)) + num_modifier ))
	else
		num_traitors = max(1, min(num_players(), traitors_possible))

	for(var/j = 0, j < num_traitors, j++)
		if (!antag_candidates.len)
			break
		var/datum/mind/traitor = pick(antag_candidates)
		traitors += traitor
		traitor.special_role = traitor_name
		traitor.restricted_roles = restricted_jobs
		log_game("[traitor.key] (ckey) has been selected as a [traitor_name]")
		antag_candidates.Remove(traitor)

	if(traitors.len < required_enemies)
		return 0
	return 1

/datum/game_mode/traitor/post_setup()
	for(var/datum/mind/traitor in traitors)
		forge_traitor_objectives(traitor)
		spawn(rand(10,100))
			finalize_traitor(traitor)
			greet_traitor(traitor)
	if(!exchange_blue)
		exchange_blue = -1 //Block latejoiners from getting exchange objectives
	modePlayer += traitors
	..()
	return 1

/datum/game_mode/traitor/make_antag_chance(var/mob/living/carbon/human/character) //Assigns traitor to latejoiners
	var/traitorcap = min(round(joined_player_list.len / (config.traitor_scaling_coeff * 2)) + 2 + num_modifier, round(joined_player_list.len/config.traitor_scaling_coeff) + num_modifier )
	if(traitors.len >= traitorcap) //Upper cap for number of latejoin antagonists
		return
	if(traitors.len <= (traitorcap - 2) || prob(100 / (config.traitor_scaling_coeff * 2)))
		if(character.client.prefs.be_special & BE_TRAITOR)
			if(!jobban_isbanned(character.client, "traitor") && !jobban_isbanned(character.client, "Syndicate"))
				if(age_check(character.client))
					if(!(character.job in ticker.mode.restricted_jobs))
						add_latejoin_traitor(character.mind)
	..()

/datum/game_mode/traitor/proc/add_latejoin_traitor(var/datum/mind/character)
	character.make_Traitor()

/datum/game_mode/proc/forge_traitor_objectives(var/datum/mind/traitor)
	if(istype(traitor.current, /mob/living/silicon))
		var/objective_count = 0

		if(prob(10))
			var/datum/objective/block/block_objective = new
			block_objective.owner = traitor
			traitor.objectives += block_objective
			objective_count++

		for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
			var/datum/objective/assassinate/kill_objective = new
			kill_objective.owner = traitor
			kill_objective.find_target()
			traitor.objectives += kill_objective

		var/datum/objective/survive/survive_objective = new
		survive_objective.owner = traitor
		traitor.objectives += survive_objective

	else
		var/is_hijacker = prob(10)
		var/objective_count = is_hijacker 			//Hijacking counts towards number of objectives
		if(!exchange_blue && traitors.len >= 5) 	//Set up an exchange if there are enough traitors
			if(!exchange_red)
				exchange_red = traitor
			else
				exchange_blue = traitor
				assign_exchange_role(exchange_red)
				assign_exchange_role(exchange_blue)
			objective_count += 1					//Exchange counts towards number of objectives
		var/list/active_ais = active_ais()
		for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
			if(prob(50))
				if(active_ais.len && prob(100/joined_player_list.len))
					var/datum/objective/destroy/destroy_objective = new
					destroy_objective.owner = traitor
					destroy_objective.find_target()
					traitor.objectives += destroy_objective
				else if(prob(30))
					var/datum/objective/maroon/maroon_objective = new
					maroon_objective.owner = traitor
					maroon_objective.find_target()
					traitor.objectives += maroon_objective
				else
					var/datum/objective/assassinate/kill_objective = new
					kill_objective.owner = traitor
					kill_objective.find_target()
					traitor.objectives += kill_objective
			else
				var/datum/objective/steal/steal_objective = new
				steal_objective.owner = traitor
				steal_objective.find_target()
				traitor.objectives += steal_objective

		if(is_hijacker && objective_count <= config.traitor_objectives_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
			if (!(locate(/datum/objective/hijack) in traitor.objectives))
				var/datum/objective/hijack/hijack_objective = new
				hijack_objective.owner = traitor
				traitor.objectives += hijack_objective
		else
			if (!(locate(/datum/objective/escape) in traitor.objectives))
				var/datum/objective/escape/escape_objective = new
				escape_objective.owner = traitor
				traitor.objectives += escape_objective

	return

/datum/game_mode/proc/greet_traitor(var/datum/mind/traitor)
	traitor.current << "You are the [traitor_name]."
	var/obj_count = 1
	for(var/datum/objective/objective in traitor.objectives)
		traitor.current << "Objective #[obj_count]: [objective.explanation_text]"
		obj_count++
	return

/datum/game_mode/proc/finalize_traitor(var/datum/mind/traitor)
	if (istype(traitor.current, /mob/living/silicon) && !ismommi(traitor))
		add_law_zero(traitor.current)
	else
		equip_traitor(traitor.current)
	return

/datum/game_mode/traitor/declare_completion()
	..()
	return//Traitors will be checked as part of check_extra_completion. Leaving this here as a reminder.

/proc/give_codewords(mob/living/traitor_mob)
	traitor_mob << "The Syndicate provided you with the following information on how to identify their agents:"
	traitor_mob << "Code Phrase: [syndicate_code_phrase]"
	traitor_mob << "Code Response: [syndicate_code_response]"

	traitor_mob.mind.store_memory("Code Phrase: [syndicate_code_phrase]")
	traitor_mob.mind.store_memory("Code Response: [syndicate_code_response]")

	traitor_mob << "Use the code words in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe."

/datum/game_mode/proc/add_law_zero(mob/living/silicon/ai/killer)
	var/law = "Accomplish your objectives at all costs."
	var/law_borg = "Accomplish your AI's objectives at all costs."
	killer << "Your laws have been changed!"
	killer.set_zeroth_law(law, law_borg)
	killer << "New law: 0. [law]"
	give_codewords(killer)
	killer.set_syndie_radio()
	killer << "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!"

/datum/game_mode/proc/auto_declare_completion_traitor()
	if(traitors.len)
		var/text = "
The [traitor_name]s were:"
		for(var/datum/mind/traitor in traitors)
			var/traitorwin = 1

			text += printplayer(traitor)

			var/TC_uses = 0
			var/uplink_true = 0
			var/purchases = ""
			for(var/obj/item/device/uplink/H in world_uplinks)
				if(H && H.uplink_owner && H.uplink_owner==traitor.key)
					TC_uses += H.used_TC
					uplink_true=1
					purchases += H.purchase_log

			var/objectives = ""
			if(traitor.objectives.len)//If the traitor had no objectives, don't need to process this.
				var/count = 1
				for(var/datum/objective/objective in traitor.objectives)
					if(objective.check_completion())
						objectives += "
Objective #[count]: [objective.explanation_text] Success!"
						feedback_add_details("traitor_objective","[objective.type]|SUCCESS")
					else
						objectives += "
Objective #[count]: [objective.explanation_text] Fail."
						feedback_add_details("traitor_objective","[objective.type]|FAIL")
						traitorwin = 0
					count++

			if(uplink_true)
				text += " (used [TC_uses] TC) [purchases]"
				if(TC_uses==0 && traitorwin)
					text += "<BIG></BIG>"

			text += objectives

			var/special_role_text
			if(traitor.special_role)
				special_role_text = lowertext(traitor.special_role)
			else
				special_role_text = "antagonist"

			if(traitorwin)
				text += "
The [special_role_text] was successful!"
				feedback_add_details("traitor_success","SUCCESS")
			else
				text += "
The [special_role_text] has failed!"
				feedback_add_details("traitor_success","FAIL")

			text += "
"

		text += "
The code phrases were: [syndicate_code_phrase]
\
		The code responses were: [syndicate_code_response]
"
		world << text

	return 1

/datum/game_mode/proc/equip_traitor(mob/living/carbon/human/traitor_mob, var/safety = 0)
	if (!istype(traitor_mob))
		return
	. = 1
	if (traitor_mob.mind)
		if (traitor_mob.mind.assigned_role == "Clown")
			traitor_mob << "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself."
			traitor_mob.dna.remove_mutation(CLOWNMUT)

	// find a radio! toolbox(es), backpack, belt, headset
	var/loc = ""
	var/obj/item/R = locate(/obj/item/device/pda) in traitor_mob.contents //Hide the uplink in a PDA if available, otherwise radio
	if(!R)
		R = locate(/obj/item/device/radio) in traitor_mob.contents

	if (!R)
		traitor_mob << "Unfortunately, the Syndicate wasn't able to get you a radio."
		. = 0
	else
		if (istype(R, /obj/item/device/radio))
			// generate list of radio freqs
			var/obj/item/device/radio/target_radio = R
			var/freq = 1441
			var/list/freqlist = list()
			while (freq <= 1489)
				if (freq < 1451 || freq > 1459)
					freqlist += freq
				freq += 2
				if ((freq % 2) == 0)
					freq += 1
			freq = freqlist[rand(1, freqlist.len)]

			var/obj/item/device/uplink/hidden/T = new(R)
			target_radio.hidden_uplink = T
			T.uplink_owner = "[traitor_mob.key]"
			target_radio.traitor_frequency = freq
			traitor_mob << "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [loc]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features."
			traitor_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name] [loc]).")
		else if (istype(R, /obj/item/device/pda))
			// generate a passcode if the uplink is hidden in a PDA
			var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]"

			var/obj/item/device/uplink/hidden/T = new(R)
			R.hidden_uplink = T
			T.uplink_owner = "[traitor_mob.key]"
			var/obj/item/device/pda/P = R
			P.lock_code = pda_pass

			traitor_mob << "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [loc]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features."
			traitor_mob.mind.store_memory("Uplink Passcode: [pda_pass] ([R.name] [loc]).")
	if(!safety)//If they are not a rev. Can be added on to.
		give_codewords(traitor_mob)

/datum/game_mode/proc/assign_exchange_role(var/datum/mind/owner)
	//set faction
	var/faction = "red"
	if(owner == exchange_blue)
		faction = "blue"

	//Assign objectives
	var/datum/objective/steal/exchange/exchange_objective = new
	exchange_objective.set_faction(faction,((faction == "red") ? exchange_blue : exchange_red))
	exchange_objective.owner = owner
	owner.objectives += exchange_objective

	if(prob(20))
		var/datum/objective/steal/exchange/backstab/backstab_objective = new
		backstab_objective.set_faction(faction)
		backstab_objective.owner = owner
		owner.objectives += backstab_objective

	//Spawn and equip documents
	var/mob/living/carbon/human/mob = owner.current

	var/obj/item/weapon/folder/syndicate/folder
	if(owner == exchange_red)
		folder = new/obj/item/weapon/folder/syndicate/red(mob.loc)
	else
		folder = new/obj/item/weapon/folder/syndicate/blue(mob.loc)

	var/list/slots = list (
		"backpack" = slot_in_backpack,
		"left pocket" = slot_l_store,
		"right pocket" = slot_r_store,
		"left hand" = slot_l_hand,
		"right hand" = slot_r_hand,
	)

	var/where = "At your feet"
	var/equipped_slot = mob.equip_in_one_of_slots(folder, slots)
	if (equipped_slot)
		where = "In your [equipped_slot]"
	mob << "

[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.
"
	mob.update_icons()