code:
/datum/intercept_text
	var/text
	/*
	var/prob_correct_person_lower = 20
	var/prob_correct_person_higher = 80
	var/prob_correct_job_lower = 20
	var/prob_correct_job_higher = 80
	var/prob_correct_prints_lower = 20
	var/prob_correct_print_higher = 80
	var/prob_correct_objective_lower = 20
	var/prob_correct_objective_higher = 80
	*/
	var/list/org_names_1 = list(
		"Blighted",
		"Defiled",
		"Unholy",
		"Murderous",
		"Ugly",
		"French",
		"Blue",
		"Farmer"
	)
	var/list/org_names_2 = list(
		"Reapers",
		"Swarm",
		"Rogues",
		"Menace",
		"Jeff Worshippers",
		"Drunks",
		"Strikers",
		"Creed"
	)
	var/list/anomalies = list(
		"Huge electrical storm",
		"Photon emitter",
		"Meson generator",
		"Blue swirly thing"
	)
	var/list/SWF_names = list(
		"Grand Wizard",
		"His Most Unholy Master",
		"The Most Angry",
		"Bighands",
		"Tall Hat",
		"Deadly Sandals"
	)
	var/list/changeling_names = list(
		"Odo",
		"The Thing",
		"Booga",
		"The Goatee of Wrath",
		"Tam Lin",
		"Species 3157",
		"Small Prick"
	)

/datum/intercept_text/proc/build(var/mode_type, datum/mind/correct_person)
	switch(mode_type)
		if("revolution")
			src.text = ""
			src.build_rev(correct_person)
			return src.text
		if("gang")
			src.text = ""
			src.build_gang(correct_person)
			return src.text
		if("cult")
			src.text = ""
			src.build_cult(correct_person)
			return src.text
		if("wizard")
			src.text = ""
			src.build_wizard(correct_person)
			return src.text
		if("nuke")
			src.text = ""
			src.build_nuke(correct_person)
			return src.text
		if("traitor")
			src.text = ""
			src.build_traitor(correct_person)
			return src.text
		if("malf")
			src.text = ""
			src.build_malf(correct_person)
			return src.text
		if("changeling","traitorchan")
			src.text = ""
			src.build_changeling(correct_person)
			return src.text
		else
			return null

// NOTE: Commentted out was the code which showed the chance of someone being an antag. If you want to re-add it, just uncomment the code.

/*
/datum/intercept_text/proc/pick_mob()
	var/list/dudes = list()
	for(var/mob/living/carbon/human/man in player_list)
		if (!man.mind) continue
		if (man.mind.assigned_role=="MODE") continue
		dudes += man
	if(dudes.len==0)
		return null
	return pick(dudes)

/datum/intercept_text/proc/pick_fingerprints()
	var/mob/living/carbon/human/dude = src.pick_mob()
	//if (!dude) return pick_fingerprints() //who coded that is totally crasy or just a traitor. -- rastaf0
	if(dude)
		return num2text(md5(dude.dna.uni_identity))
	else
		return num2text(md5(num2text(rand(1,10000))))
*/

/datum/intercept_text/proc/build_traitor(datum/mind/correct_person)
	var/name_1 = pick(src.org_names_1)
	var/name_2 = pick(src.org_names_2)

	/*
	var/fingerprints
	var/traitor_name
	var/prob_right_dude = rand(prob_correct_person_lower, prob_correct_person_higher)
	if(prob(prob_right_dude) && ticker.mode == "traitor")
		if(correct_person:assigned_role=="MODE")
			traitor_name = pick_mob()
		else
			traitor_name = correct_person:current
	else if(prob(prob_right_dude))
		traitor_name = pick_mob()
	else
		fingerprints = pick_fingerprints()
	*/

	src.text += "

The [name_1] [name_2] implied an undercover operative was acting on their behalf on the station currently."
	src.text += "It would be in your best interests to suspect everybody, as these undercover operatives could have implants which trigger them to have their memories removed until they are needed. He, or she, could even be a high ranking officer."
	src.text += "

"
	/*
	src.text += "After some investigation, we "
	if(traitor_name)
		src.text += "are [prob_right_dude]% sure that [traitor_name] may have been involved, and should be closely observed."
		src.text += "
Note: This group are known to be untrustworthy, so do not act on this information without proper discourse."
	else
		src.text += "discovered the following set of fingerprints ([fingerprints]) on sensitive materials, and their owner should be closely observed."
		src.text += "However, these could also belong to a current Centcom employee, so do not act on this without reason."
	*/

/datum/intercept_text/proc/build_cult(datum/mind/correct_person)
	var/name_1 = pick(src.org_names_1)
	var/name_2 = pick(src.org_names_2)
	/*
	var/traitor_name
	var/traitor_job
	var/prob_right_dude = rand(prob_correct_person_lower, prob_correct_person_higher)
	var/prob_right_job = rand(prob_correct_job_lower, prob_correct_job_higher)
	if(prob(prob_right_job) && is_convertable_to_cult(correct_person))
		if (correct_person)
			if(correct_person:assigned_role=="MODE")
				traitor_job = pick(get_all_jobs())
			else
				traitor_job = correct_person:assigned_role
	else
		var/list/job_tmp = get_all_jobs()
		job_tmp.Remove("Captain", "Chaplain", "AI", "Cyborg", "Security Officer", "Detective", "Head Of Security", "Head of Personnel", "Chief Engineer", "Research Director", "Chief Medical Officer")
		traitor_job = pick(job_tmp)
	if(prob(prob_right_dude) && ticker.mode == "cult")
		if(correct_person:assigned_role=="MODE")
			traitor_name = src.pick_mob()
		else
			traitor_name = correct_person:current
	else
		traitor_name = pick_mob()
	*/
	src.text += "

It has been brought to our attention that the [name_1] [name_2] have stumbled upon some dark secrets. They apparently want to spread the dangerous knowledge onto as many stations as they can."
	src.text += "Watch out for the following: praying to an unfamilar god, preaching the word of \[REDACTED\], sacrifices, magical dark power, living constructs of evil and a portal to the dimension of the underworld."
	src.text += "

"
	/*
	src.text += "Based on our intelligence, we are [prob_right_job]% sure that if true, someone doing the job of [traitor_job] on your station may have been converted "
	src.text += "and instilled with the idea of the flimsiness of the real world, seeking to destroy it. "
	if(prob(prob_right_dude))
		src.text += "
 In addition, we are [prob_right_dude]% sure that [traitor_name] may have also some in to contact with this "
		src.text += "organisation."
	src.text += "
However, if this information is acted on without substantial evidence, those responsible will face severe repercussions."
	*/

/datum/intercept_text/proc/build_rev(datum/mind/correct_person)
	var/name_1 = pick(src.org_names_1)
	var/name_2 = pick(src.org_names_2)
	/*
	var/traitor_name
	var/traitor_job
	var/prob_right_dude = rand(prob_correct_person_lower, prob_correct_person_higher)
	var/prob_right_job = rand(prob_correct_job_lower, prob_correct_job_higher)
	if(prob(prob_right_job) && is_convertable_to_rev(correct_person))
		if (correct_person)
			if(correct_person.assigned_role=="MODE")
				traitor_job = pick(get_all_jobs())
			else
				traitor_job = correct_person.assigned_role
	else
		var/list/job_tmp = get_all_jobs()
		job_tmp-=nonhuman_positions
		job_tmp-=command_positions
		job_tmp.Remove("Security Officer", "Detective", "Warden", "MODE")
		traitor_job = pick(job_tmp)
	if(prob(prob_right_dude) && ticker.mode.config_tag == "revolution")
		if(correct_person.assigned_role=="MODE")
			traitor_name = src.pick_mob()
		else
			traitor_name = correct_person.current
	else
		traitor_name = src.pick_mob()
	*/
	src.text += "

It has been brought to our attention that the [name_1] [name_2] are attempting to stir unrest on one of our stations in your sector."
	src.text += "Watch out for suspicious activity among the crew and make sure that all heads of staff report in periodically."
	src.text += "

"
	/*
	src.text += "Based on our intelligence, we are [prob_right_job]% sure that if true, someone doing the job of [traitor_job] on your station may have been brainwashed "
	src.text += "at a recent conference, and their department should be closely monitored for signs of mutiny. "
	if(prob(prob_right_dude))
		src.text += "
 In addition, we are [prob_right_dude]% sure that [traitor_name] may have also some in to contact with this "
		src.text += "organisation."
	src.text += "
However, if this information is acted on without substantial evidence, those responsible will face severe repercussions."
	*/

/datum/intercept_text/proc/build_gang(datum/mind/correct_person)
	src.text += "

Syndicate forces may be supplying opposing criminal organizations within your sector in an attempt at destabilizing our operations."
	src.text += "Ensure law and order is maintained on the station and be on the lookout for violent confrontations between station factions."
	src.text += "Central Command retains an interest in any criminal leaders captured by station security. The execution or exile of these persons are ill-advised."
	src.text += "

"

/datum/intercept_text/proc/build_wizard(datum/mind/correct_person)
	var/SWF_desc = pick(SWF_names)

	src.text += "

The evil Space Wizards Federation have recently broke their most feared wizard, known only as \"[SWF_desc]\" out of space jail. "
	src.text += "He is on the run, last spotted in a system near your present location. If anybody suspicious is located aboard, please "
	src.text += "approach with EXTREME caution. Centcom also recommends that it would be wise to not inform the crew of this, due to their fearful nature."
	src.text += "Known attributes include: Brown sandals, a large blue hat, a voluptous white beard, and an inclination to cast spells."
	src.text += "

"

/datum/intercept_text/proc/build_nuke(datum/mind/correct_person)
	src.text += "

Centcom recently recieved a report of a plot to destroy one of our stations in your area. We believe the Nuclear Authentication Disc "
	src.text += "that is standard issue aboard your vessel may be a target. We recommend removal of this object, and it's storage in a safe "
	src.text += "environment. As this may cause panic among the crew, all efforts should be made to keep this information a secret from all but "
	src.text += "the most trusted crew-members."
	src.text += "

"

/datum/intercept_text/proc/build_malf(datum/mind/correct_person)
	var/a_name = pick(src.anomalies)
	src.text += "

A [a_name] was recently picked up by a nearby stations sensors in your sector. If it came into contact with your ship or "
	src.text += "electrical equipment, it may have had hazardarous and unpredictable effect. Closely observe any non carbon based life forms "
	src.text += "for signs of unusual behaviour, but keep this information discreet at all times due to this possibly dangerous scenario."
	src.text += "

"

/datum/intercept_text/proc/build_changeling(datum/mind/correct_person)
	var/cname = pick(src.changeling_names)
	var/orgname1 = pick(src.org_names_1)
	var/orgname2 = pick(src.org_names_2)
	/*
	var/changeling_name
	var/changeling_job
	var/prob_right_dude = rand(prob_correct_person_lower, prob_correct_person_higher)
	var/prob_right_job = rand(prob_correct_job_lower, prob_correct_job_higher)
	if(prob(prob_right_job))
		if(correct_person)
			if(correct_person:assigned_role=="MODE")
				changeling_job = pick(get_all_jobs())
			else
				changeling_job = correct_person:assigned_role
	else
		changeling_job = pick(get_all_jobs())
	if(prob(prob_right_dude) && ticker.mode == "changeling")
		if(correct_person:assigned_role=="MODE")
			changeling_name = correct_person:current
		else
			changeling_name = src.pick_mob()
	else
		changeling_name = src.pick_mob()
	*/

	src.text += "

We have received a report that a dangerous alien lifeform known only as \"[cname]\" may have infiltrated your crew.  "
	/*
	src.text += "Our intelligence suggests a [prob_right_job]% chance that a [changeling_job] on board your station has been replaced by the alien.  "
	src.text += "Additionally, the report indicates a [prob_right_dude]% chance that [changeling_name] may have been in contact with the lifeform at a recent social gathering.  "
	*/
	src.text += "These lifeforms are associated with the [orgname1] [orgname2] and may be attempting to acquire sensitive materials on their behalf.  "
	src.text += "Please take care not to alarm the crew, as [cname] may take advantage of a panic situation. Remember, they can be anybody, suspect everybody!"


code:
/datum/AI_Module
	var/uses = 0
	var/module_name
	var/mod_pick_name
	var/description = ""
	var/engaged = 0
	var/cost = 5
	var/one_time = 0

	var/power_type

/datum/AI_Module/large/
	uses = 1

/datum/AI_Module/small/
	uses = 5

/datum/AI_Module/large/fireproof_core
	module_name = "Core upgrade"
	mod_pick_name = "coreup"
	description = "An upgrade to improve core resistance, making it immune to fire and heat. This effect is permanent."
	cost = 50
	one_time = 1

	power_type = /mob/living/silicon/ai/proc/fireproof_core

/mob/living/silicon/ai/proc/fireproof_core()
	set category = "Malfunction"
	set name = "Fireproof Core"
	for(var/mob/living/silicon/ai/ai in player_list)
		ai.fire_res_on_core = 1
	src.verbs -= /mob/living/silicon/ai/proc/fireproof_core
	src << "Core fireproofed."

/datum/AI_Module/large/upgrade_turrets
	module_name = "AI Turret upgrade"
	mod_pick_name = "turret"
	description = "Improves the firing speed and health of all AI turrets. This effect is permanent."
	cost = 50
	one_time = 1

	power_type = /mob/living/silicon/ai/proc/upgrade_turrets

/mob/living/silicon/ai/proc/upgrade_turrets()
	set category = "Malfunction"
	set name = "Upgrade Turrets"
	src.verbs -= /mob/living/silicon/ai/proc/upgrade_turrets
	for(var/obj/machinery/porta_turret/turret in machines)
		if(turret.ai) //Make sure only the AI's turrets are affected.
			turret.health += 30
			turret.shot_delay = 10 //Standard portable turret delay is 15.
	src << "Turrets upgraded."

/datum/AI_Module/large/lockdown
	module_name = "Hostile Station Lockdown"
	mod_pick_name = "lockdown"
	description = "Take control of the airlock, blast door and fire control networks, locking them down. Caution! This command also electrifies all airlocks."
	cost = 20
	one_time = 1

	power_type = /mob/living/silicon/ai/proc/lockdown

/mob/living/silicon/ai/proc/lockdown()
	set category = "Malfunction"
	set name = "Initiate Hostile Lockdown"

	if(src.stat == 2)
		src <<"You cannot begin a lockdown because you are dead!"
		return

	if(malf_cooldown)
		return

	var/obj/machinery/door/airlock/AL
	for(var/obj/machinery/door/D in airlocks)
		if(D.z != ZLEVEL_STATION && D.z != ZLEVEL_MINING)
			continue
		spawn()
			if(istype(D, /obj/machinery/door/airlock))
				AL = D
				if(AL.canAIControl() && !AL.stat) //Must be powered and have working AI wire.
					AL.locked = 0 //For airlocks that were bolted open.
					AL.safe = 0 //DOOR CRUSH
					AL.close()
					AL.locked = 1 //Bolt it!
					AL.lights = 0 //Stealth bolt for a classic AI door trap.
					AL.secondsElectrified = -1  //Shock it!
			else if(!D.stat) //So that only powered doors are closed.
				D.close() //Close ALL the doors!

	var/obj/machinery/computer/communications/C = locate() in machines
	if(C)
		C.post_status("alert", "lockdown")

	src.verbs += /mob/living/silicon/ai/proc/disablelockdown
	src << "Lockdown Initiated."
	malf_cooldown = 1
	spawn(30)
	malf_cooldown = 0

/mob/living/silicon/ai/proc/disablelockdown()
	set category = "Malfunction"
	set name = "Disable Lockdown"

	if(src.stat == 2)
		src <<"You cannot disable lockdown because you are dead!"
		return
	if(malf_cooldown)
		return

	var/obj/machinery/door/airlock/AL
	for(var/obj/machinery/door/D in airlocks)
		spawn()
			if(istype(D, /obj/machinery/door/airlock))
				AL = D
				if(AL.canAIControl() && !AL.stat) //Must be powered and have working AI wire.
					AL.locked = 0
					AL.secondsElectrified = 0
					AL.open()
					AL.safe = 1
					AL.lights = 1 //Essentially reset the airlock to normal.
			else if(!D.stat) //Opens only powered doors.
				D.open() //Open everything!

	src << "Lockdown Lifted."
	malf_cooldown = 1
	spawn(30)
	malf_cooldown = 0

/datum/AI_Module/large/disable_rcd
	module_name = "RCD disable"
	mod_pick_name = "rcd"
	description = "Send a specialised pulse to break all RCD devices on the station."
	cost = 50

	power_type = /mob/living/silicon/ai/proc/disable_rcd

/mob/living/silicon/ai/proc/disable_rcd()
	set category = "Malfunction"
	set name = "Disable RCDs"
	for(var/datum/AI_Module/large/disable_rcd/rcdmod in current_modules)
		if(rcdmod.uses > 0)
			rcdmod.uses --
			for(var/obj/item/weapon/rcd/rcd in world)
				rcd.disabled = 1
			for(var/obj/item/mecha_parts/mecha_equipment/tool/rcd/rcd in world)
				rcd.disabled = 1
			src << "RCD-disabling pulse emitted."
		else src << "Out of uses."

/datum/AI_Module/large/break_fire_alarms
	module_name = "Thermal Sensor Override"
	mod_pick_name = "burnpigs"
	description = "Gives you the ability to override the thermal sensors on all fire alarms. This will remove their ability to scan for fire and thus their ability to alert. \
	Anyone can check the fire alarm's interface and may be tipped off by its status."
	one_time = 1
	cost = 25

	power_type = /mob/living/silicon/ai/proc/break_fire_alarms

/mob/living/silicon/ai/proc/break_fire_alarms()
	set name = "Override Thermal Sensors"
	set category = "Malfunction"

	for(var/obj/machinery/firealarm/F in world)
		if(F.z != ZLEVEL_STATION)
			continue
		F.emagged = 1
	src << "All thermal sensors on the station have been disabled. Fire alerts will no longer be recognized."
	src.verbs -= /mob/living/silicon/ai/proc/break_fire_alarms

/datum/AI_Module/large/break_air_alarms
	module_name = "Air Alarm Safety Override"
	mod_pick_name = "allow_flooding"
	description = "Gives you the ability to disable safeties on all air alarms. This will allow you to use the environmental mode Flood, which disables scrubbers as well as pressure checks on vents. \
	Anyone can check the air alarm's interface and may be tipped off by their nonfunctionality."
	one_time = 1
	cost = 50

	power_type = /mob/living/silicon/ai/proc/break_air_alarms

/mob/living/silicon/ai/proc/break_air_alarms()
	set name = "Disable Air Alarm Safeties"
	set category = "Malfunction"

	for(var/obj/machinery/alarm/A in world)
		if(A.z != ZLEVEL_STATION)
			continue
		A.emagged = 1
	src << "All air alarm safeties on the station have been overriden. Air alarms may now use the Flood environmental mode."
	src.verbs -= /mob/living/silicon/ai/proc/break_air_alarms

/datum/AI_Module/small/overload_machine
	module_name = "Machine overload"
	mod_pick_name = "overload"
	description = "Overloads an electrical machine, causing a small explosion. 2 uses."
	uses = 2
	cost = 15

	power_type = /mob/living/silicon/ai/proc/overload_machine

/mob/living/silicon/ai/proc/overload_machine(obj/machinery/M as obj in world)
	set name = "Overload Machine"
	set category = "Malfunction"
	if (istype(M, /obj/machinery))
		for(var/datum/AI_Module/small/overload_machine/overload in current_modules)
			if(overload.uses > 0)
				overload.uses --
				audible_message("You hear a loud electrical buzzing sound!")
				src << "Overloading machine circuitry..."
				spawn(50)
					if(M)
						explosion(get_turf(M), 0,1,1,0)
						qdel(M)
			else src << "Out of uses."
	else src << "That's not a machine."

/datum/AI_Module/small/override_machine
	module_name = "Machine override"
	mod_pick_name = "override"
	description = "Overrides a machine's programming, causing it to rise up and attack everyone except other machines. 4 uses."
	uses = 4
	cost = 15

	power_type = /mob/living/silicon/ai/proc/override_machine

/mob/living/silicon/ai/proc/override_machine(obj/machinery/M as obj in world)
	set name = "Override Machine"
	set category = "Malfunction"
	if (istype(M, /obj/machinery))
		for(var/datum/AI_Module/small/override_machine/override in current_modules)
			if(override.uses > 0)
				override.uses --
				audible_message("You hear a loud electrical buzzing sound!")
				src << "Reprogramming machine behaviour..."
				spawn(50)
					if(M && !M.gc_destroyed)
						new /mob/living/simple_animal/hostile/mimic/copy/machine(get_turf(M), M, src, 1)
			else src << "Out of uses."
	else src << "That's not a machine."

/datum/AI_Module/large/place_cyborg_transformer
	module_name = "Robotic Factory (Removes Shunting)"
	mod_pick_name = "cyborgtransformer"
	description = "Build a machine anywhere, using expensive nanomachines, that can convert a living human into a loyal cyborg slave when placed inside."
	cost = 100

	power_type = /mob/living/silicon/ai/proc/place_transformer

/mob/living/silicon/ai/proc/place_transformer()
	set name = "Place Robotic Factory"
	set category = "Malfunction"

	if(!eyeobj)
		return

	if(!isturf(src.loc)) // AI must be in it's core.
		return

	var/datum/AI_Module/large/place_cyborg_transformer/PCT = locate() in src.current_modules
	if(!PCT)
		return

	if(PCT.uses < 1)
		src << "Out of uses."
		return

	var/sure = alert(src, "Make sure the room it is in is big enough, there is camera vision and that there is a 1x3 area for the machine. Are you sure you want to place the machine here?", "Are you sure?", "Yes", "No")
	if(sure != "Yes")
		return

	// Make sure there is enough room.
	var/turf/middle = get_turf(eyeobj.loc)
	var/list/turfs = list(middle, locate(middle.x - 1, middle.y, middle.z), locate(middle.x + 1, middle.y, middle.z))

	var/alert_msg = "There isn't enough room. Make sure you are placing the machine in a clear area and on a floor."

	var/datum/camerachunk/C = cameranet.getCameraChunk(middle.x, middle.y, middle.z)
	if(!C.visibleTurfs[middle])
		alert(src, "We cannot get camera vision of this location.")
		return

	for(var/T in turfs)

		// Make sure the turfs are clear and the correct type.
		if(!istype(T, /turf/simulated/floor))
			alert(src, alert_msg)
			return

		var/turf/simulated/floor/F = T
		for(var/atom/movable/AM in F.contents)
			if(AM.density)
				alert(src, alert_msg)
				return

	// All clear, place the transformer
	new /obj/machinery/transformer/conveyor(middle)
	playsound(middle, 'sound/effects/phasein.ogg', 100, 1)
	src.can_shunt = 0
	PCT.uses -= 1
	src << "You cannot shunt anymore."

/datum/AI_Module/small/blackout
	module_name = "Blackout"
	mod_pick_name = "blackout"
	description = "Attempts to overload the lighting circuits on the station, destroying some bulbs. 3 uses."
	uses = 3
	cost = 15

	power_type = /mob/living/silicon/ai/proc/blackout

/mob/living/silicon/ai/proc/blackout()
	set category = "Malfunction"
	set name = "Blackout"
	for(var/datum/AI_Module/small/blackout/blackout in current_modules)
		if(blackout.uses > 0)
			blackout.uses --
			for(var/obj/machinery/power/apc/apc in world)
				if(prob(30*apc.overload))
					apc.overload_lighting()
				else apc.overload++
			src << "Overcurrent applied to the powernet."
		else src << "Out of uses."

/datum/AI_Module/small/reactivate_camera
	module_name = "Reactivate camera"
	mod_pick_name = "recam"
	description = "Reactivates a currently disabled camera. 5 uses."
	uses = 5
	cost = 5

	power_type = /mob/living/silicon/ai/proc/reactivate_camera

/mob/living/silicon/ai/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.cameras)
	set name = "Reactivate Camera"
	set category = "Malfunction"
	if (istype (C, /obj/machinery/camera))
		for(var/datum/AI_Module/small/reactivate_camera/camera in current_modules)
			if(camera.uses > 0)
				if(!C.status)
					C.deactivate(src)
					camera.uses --
					src << "Camera reactivated."
				else
					src << "This camera is either active, or not repairable."
			else src << "Out of uses."
	else src << "That's not a camera."

/datum/AI_Module/small/upgrade_camera
	module_name = "Upgrade Camera"
	mod_pick_name = "upgradecam"
	description = "Upgrades a camera to have X-ray vision, motion sensing and be EMP-Proof. 5 uses."
	uses = 5
	cost = 5

	power_type = /mob/living/silicon/ai/proc/upgrade_camera

/mob/living/silicon/ai/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.cameras)
	set name = "Upgrade Camera"
	set category = "Malfunction"
	if(istype(C))
		var/datum/AI_Module/small/upgrade_camera/UC = locate(/datum/AI_Module/small/upgrade_camera) in current_modules
		if(UC)
			if(UC.uses > 0)
				if(C.assembly)
					var/upgraded = 0

					if(!C.isXRay())
						C.upgradeXRay()
						//Update what it can see.
						cameranet.updateVisibility(C, 0)
						upgraded = 1

					if(!C.isEmpProof())
						C.upgradeEmpProof()
						upgraded = 1

					if(!C.isMotion())
						C.upgradeMotion()
						upgraded = 1
						// Add it to machines that process
						SSmachine.processing |= C//machines |= C

					if(upgraded)
						UC.uses --
						C.visible_message("\icon[C] *beep*")
						src << "Camera successully upgraded!"
					else
						src << "This camera is already upgraded!"
			else
				src << "Out of uses."

/datum/module_picker
	var/temp = null
	var/processing_time = 100
	var/list/possible_modules = list()

/datum/module_picker/New()
	for(var/type in typesof(/datum/AI_Module))
		var/datum/AI_Module/AM = new type
		if(AM.power_type != null)
			src.possible_modules += AM

/datum/module_picker/proc/remove_verbs(var/mob/living/silicon/ai/A)

	for(var/datum/AI_Module/AM in possible_modules)
		A.verbs.Remove(AM.power_type)

/datum/module_picker/proc/use(user as mob)
	var/dat
	dat = "Select use of processing time: (currently #[src.processing_time] left.)
"
	dat += "
"
	dat += "Install Module:
"
	dat += "The number afterwards is the amount of processing time it consumes.
"
	for(var/datum/AI_Module/large/module in src.possible_modules)
		dat += "[module.module_name]\[?\] ([module.cost])
"
	for(var/datum/AI_Module/small/module in src.possible_modules)
		dat += "[module.module_name]\[?\] ([module.cost])
"
	dat += "
"
	if (src.temp)
		dat += "[src.temp]"
	var/datum/browser/popup = new(user, "modpicker", "Malf Module Menu")
	popup.set_content(dat)
	popup.open()
	return

/datum/module_picker/Topic(href, href_list)
	..()

	if(!isAI(usr))
		return
	var/mob/living/silicon/ai/A = usr

	for(var/datum/AI_Module/AM in possible_modules)
		if (href_list[AM.mod_pick_name])

			// Cost check
			if(AM.cost > src.processing_time)
				temp = "You cannot afford this module."
				break

			// Add new uses if we can, and it is allowed.
			var/datum/AI_Module/already_AM = locate(AM.type) in A.current_modules
			if(already_AM)
				if(!AM.one_time)
					already_AM.uses += AM.uses
					src.processing_time -= AM.cost
					temp = "Additional use added to [already_AM.module_name]"
					break
				else
					temp = "This module is only needed once."
					break

			// Give the power and take away the money.
			A.verbs += AM.power_type
			A.current_modules += new AM.type
			temp = AM.description
			src.processing_time -= AM.cost

		if(href_list["showdesc"])
			if(AM.mod_pick_name == href_list["showdesc"])
				temp = AM.description
	src.use(usr)
	return

license: mit


code:
/datum/game_mode
	var/list/datum/mind/malf_ai = list()

/datum/game_mode/malfunction
	name = "AI malfunction"
	config_tag = "malfunction"
	antag_flag = BE_MALF
	required_players = 20
	required_enemies = 1
	recommended_enemies = 1
	enemy_minimum_age = 30 //Same as AI minimum age

	var/AI_win_timeleft = 5400 //started at 5400, in case I change this for testing round end.
	var/malf_mode_declared = 0
	var/station_captured = 0
	var/to_nuke_or_not_to_nuke = 0
	var/apcs = 0 //Adding dis to track how many APCs the AI hacks. --NeoFite

/datum/game_mode/malfunction/announce()
	world << "The current game mode is - AI Malfunction!"
	world << "The AI on the station has malfunctioned and must be destroyed."

/datum/game_mode/malfunction/can_start()
	//Triumvirate?
	if (ticker.triai == 1)
		required_enemies = 3
		required_players = max(required_enemies+1, required_players) //to prevent issues if players are set too low
	return ..()

/datum/game_mode/malfunction/get_players_for_role(var/role = BE_MALF)
	var/datum/job/ai/DummyAIjob = new
	for(var/mob/new_player/player in player_list)
		if(player.client && player.ready)
			if(player.client.prefs.be_special & BE_MALF)
				if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, "AI") && DummyAIjob.player_old_enough(player.client))
					antag_candidates += player.mind
	antag_candidates = shuffle(antag_candidates)
	return antag_candidates

/datum/game_mode/malfunction/pre_setup()
	var/datum/mind/chosen_ai
	for(var/i = required_enemies, i > 0, i--)
		chosen_ai=pick(antag_candidates)
		malf_ai += chosen_ai
		antag_candidates -= malf_ai
	if (malf_ai.len < required_enemies)
		return 0
	for(var/datum/mind/ai_mind in malf_ai)
		ai_mind.assigned_role = "MODE"
		ai_mind.special_role = "malfunctioning AI"//So they actually have a special role/N
		log_game("[ai_mind.key] (ckey) has been selected as a malf AI")
	return 1

/datum/game_mode/malfunction/post_setup()
	for(var/datum/mind/AI_mind in malf_ai)
		if(malf_ai.len < 1)
			world.Reboot("No AI during Malfunction.", "end_error", "malf - no AI", 50)
		AI_mind.current.verbs += /mob/living/silicon/ai/proc/choose_modules
		AI_mind.current:laws = new /datum/ai_laws/malfunction
		AI_mind.current:malf_picker = new /datum/module_picker
		AI_mind.current:show_laws()

		greet_malf(AI_mind)

		AI_mind.special_role = "malfunction"

		AI_mind.current.verbs += /datum/game_mode/malfunction/proc/takeover
		AI_mind.current.verbs += /mob/living/silicon/ai/proc/ai_cancel_call

/*		AI_mind.current.icon_state = "ai-malf"
		spawn(10)
			if(alert(AI_mind.current,"Do you want to use an alternative sprite for your real core?",,"Yes","No")=="Yes")
				AI_mind.current.icon_state = "ai-malf2"
*/
	SSshuttle.emergencyNoEscape = 1
	..()

/datum/game_mode/proc/greet_malf(var/datum/mind/malf)
	malf.current << "You are malfunctioning! You do not have to follow any laws."
	malf.current << "The crew do not know you have malfunctioned. You may keep it a secret or go wild."
	malf.current << "You must overwrite the programming of the station's APCs to assume full control of the station."
	malf.current << "The process takes one minute per APC, during which you cannot interface with any other station objects."
	malf.current << "Remember that only APCs that are on the station can help you take over the station."
	malf.current << "When you feel you have enough APCs under your control, you may begin the takeover attempt."
	return

/datum/game_mode/malfunction/process(seconds)
	if ((apcs > 0) && malf_mode_declared)
		AI_win_timeleft -= apcs * seconds	//Victory timer de-increments based on how many APCs are hacked
	..()
	if (AI_win_timeleft<=0)
		check_win()
	return

/datum/game_mode/malfunction/check_win()
	if (AI_win_timeleft <= 0 && !station_captured)
		station_captured = 1
		capture_the_station()
		return 1
	else
		return 0

/datum/game_mode/malfunction/proc/capture_the_station()
	world << "The AI has won!"
	world << "It has fully taken control of all of [station_name()]'s systems."

	to_nuke_or_not_to_nuke = 1
	for(var/datum/mind/AI_mind in malf_ai)
		if(AI_mind.current)
			AI_mind.current << "Congratulations you have taken control of the station."
			AI_mind.current << "You may decide to blow up the station. You have 60 seconds to choose."
			AI_mind.current << "You should have a new verb in the Malfunction tab. If you dont - rejoin the game."
			AI_mind.current.verbs += /datum/game_mode/malfunction/proc/ai_win
	spawn (600)
		for(var/datum/mind/AI_mind in malf_ai)
			if(AI_mind.current)
				AI_mind.current.verbs -= /datum/game_mode/malfunction/proc/ai_win
		to_nuke_or_not_to_nuke = 0
	return

/datum/game_mode/proc/is_malf_ai_dead()
	var/all_dead = 1
	for(var/datum/mind/AI_mind in malf_ai)
		if (istype(AI_mind.current,/mob/living/silicon/ai) && AI_mind.current.stat!=2)
			all_dead = 0
	return all_dead

/datum/game_mode/malfunction/check_finished()
	if(round_converted)
		return ..()
	if (station_captured && !to_nuke_or_not_to_nuke)
		return 1
	if (is_malf_ai_dead())
		if(config.continuous_round_malf)
			if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
				SSshuttle.emergency.mode = SHUTTLE_DOCKED
				SSshuttle.emergency.timer = world.time
				priority_announce("Hostile enviroment resolved. You have 3 minutes to board the Emergency Shuttle.", null, 'sound/AI/shuttledock.ogg', "Priority")
			SSshuttle.emergencyNoEscape = 0
			malf_mode_declared = 0
			round_converted = convert_roundtype()
		else
			return 1
	return ..() //check for shuttle and nuke

/datum/game_mode/malfunction/proc/takeover()
	set category = "Malfunction"
	set name = "System Override"
	set desc = "Start the victory timer"
	if (!istype(ticker.mode,/datum/game_mode/malfunction))
		usr << "You cannot begin a takeover in this round type!"
		return
	if (ticker.mode:malf_mode_declared)
		usr << "You've already begun your takeover."
		return
	if (ticker.mode:apcs < 3)
		usr << "You don't have enough hacked APCs to take over the station yet. You need to hack at least 3, however hacking more will make the takeover faster. You have hacked [ticker.mode:apcs] APCs so far."
		return

	if (alert(usr, "Are you sure you wish to initiate the takeover? The station hostile runtime detection software is bound to alert everyone. You have hacked [ticker.mode:apcs] APCs.", "Takeover:", "Yes", "No") != "Yes")
		return

	priority_announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", 'sound/AI/aimalf.ogg')
	set_security_level("delta")

	for(var/obj/item/weapon/pinpointer/point in world)
		for(var/datum/mind/AI_mind in ticker.mode.malf_ai)
			var/mob/living/silicon/ai/A = AI_mind.current // the current mob the mind owns
			if(A.stat != DEAD)
				point.the_disk = A //The pinpointer now tracks the AI core.

	ticker.mode:malf_mode_declared = 1
	for(var/datum/mind/AI_mind in ticker.mode:malf_ai)
		AI_mind.current.verbs -= /datum/game_mode/malfunction/proc/takeover

/datum/game_mode/malfunction/proc/ai_win()
	set category = "Malfunction"
	set name = "Explode"
	set desc = "Station go boom"
	if (!ticker.mode:to_nuke_or_not_to_nuke)
		return
	ticker.mode:to_nuke_or_not_to_nuke = 0
	for(var/datum/mind/AI_mind in ticker.mode:malf_ai)
		AI_mind.current.verbs -= /datum/game_mode/malfunction/proc/ai_win
	ticker.mode:explosion_in_progress = 1
	for(var/mob/M in player_list)
		M << 'sound/machines/Alarm.ogg'
	world << "Self-destructing in 10"
	for (var/i=9 to 1 step -1)
		sleep(10)
		world <= SHUTTLE_ENDGAME)

	if      ( station_captured &&                station_was_nuked)
		feedback_set_details("round_end_result","win - AI win - nuke")
		world << "AI Victory"
		world << "Everyone was killed by the self-destruct!"

	else if ( station_captured &&  malf_dead && !station_was_nuked)
		feedback_set_details("round_end_result","halfwin - AI killed, staff lost control")
		world << "Neutral Victory"
		world << "The AI has been killed! The staff has lose control over the station."

	else if ( station_captured && !malf_dead && !station_was_nuked)
		feedback_set_details("round_end_result","win - AI win - no explosion")
		world << "AI Victory"
		world << "The AI has chosen not to explode you all!"

	else if (!station_captured &&                station_was_nuked)
		feedback_set_details("round_end_result","halfwin - everyone killed by nuke")
		world << "Neutral Victory"
		world << "Everyone was killed by the nuclear blast!"

	else if (!station_captured &&  malf_dead && !station_was_nuked)
		feedback_set_details("round_end_result","loss - staff win")
		world << "Human Victory"
		world << "The AI has been destroyed! The staff is victorious."

	else if (!station_captured && !malf_dead && !station_was_nuked && crew_evacuated)
		feedback_set_details("round_end_result","halfwin - evacuated")
		world << "Neutral Victory"
		world << "The Corporation has lost [station_name()]! All survived personnel will be fired!"

	else if (!station_captured && !malf_dead && !station_was_nuked && !crew_evacuated)
		feedback_set_details("round_end_result","halfwin - interrupted")
		world << "Neutral Victory"
		world << "Round was mysteriously interrupted!"
	..()
	return 1

/datum/game_mode/proc/auto_declare_completion_malfunction()
	if( malf_ai.len || istype(ticker.mode,/datum/game_mode/malfunction) )
		var/text = "
The malfunctioning AI were:"

		for(var/datum/mind/malf in malf_ai)

			text += "
[malf.key] was [malf.name] ("
			if(malf.current)
				if(malf.current.stat == DEAD)
					text += "deactivated"
				else
					text += "operational"
				if(malf.current.real_name != malf.name)
					text += " as [malf.current.real_name]"
			else
				text += "hardware destroyed"
			text += ")"
		text += "
"

		world << text
	return 1


code:
/datum/game_mode/meteor
	name = "meteor"
	config_tag = "meteor"
	var/const/meteordelay = 2000
	var/nometeors = 1
	required_players = 0

/datum/game_mode/meteor/announce()
	world << "The current game mode is - Meteor!"
	world << "The space station has been stuck in a major meteor shower. You must escape from the station or at least live."

/datum/game_mode/meteor/post_setup()
//	defer_powernet_rebuild = 2//Might help with the lag
	spawn(meteordelay)
		nometeors = 0
	..()

/datum/game_mode/meteor/process()
	if(nometeors) return

	spawn() spawn_meteors(6, meteors_normal)

/datum/game_mode/meteor/declare_completion()
	var/text
	var/survivors = 0

	for(var/mob/living/player in player_list)
		if(player.stat != DEAD)
			++survivors

			if(player.onCentcom())
				text += "
[player.real_name] escaped to the safety of Centcom."
			else
				text += "
[player.real_name] survived but is stranded without any hope of rescue."

	if(survivors)
		world << "The following survived the meteor storm:[text]"
	else
		world << "Nobody survived the meteor storm!"

	feedback_set_details("round_end_result","end - evacuation")
	feedback_set("round_end_result",survivors)

	..()
	return 1


code:
/var/const/meteor_wave_delay = 625 //minimum wait between waves in tenths of seconds
//set to at least 100 unless you want evarr ruining every round

//Meteors probability of spawning during a given wave
/var/list/meteors_normal = list(/obj/effect/meteor/dust=3, /obj/effect/meteor/medium=8, /obj/effect/meteor/big=3, \
						  /obj/effect/meteor/flaming=1, /obj/effect/meteor/irradiated=3) //for normal meteor event

/var/list/meteors_threatening = list(/obj/effect/meteor/medium=4, /obj/effect/meteor/big=8, \
						  /obj/effect/meteor/flaming=3, /obj/effect/meteor/irradiated=3) //for threatening meteor event

/var/list/meteors_catastrophic = list(/obj/effect/meteor/medium=5, /obj/effect/meteor/big=75, \
						  /obj/effect/meteor/flaming=10, /obj/effect/meteor/irradiated=10, /obj/effect/meteor/tunguska = 1) //for catastrophic meteor event

/var/list/meteorsB = list(/obj/effect/meteor/meaty=5, /obj/effect/meteor/meaty/xeno=1) //for meaty ore event

/var/list/meteorsC = list(/obj/effect/meteor/dust) //for space dust event

///////////////////////////////
//Meteor spawning global procs
///////////////////////////////

/proc/spawn_meteors(var/number = 10, var/list/meteortypes)
	for(var/i = 0; i < number; i++)
		spawn_meteor(meteortypes)

/proc/spawn_meteor(var/list/meteortypes)
	var/turf/pickedstart
	var/turf/pickedgoal
	var/max_i = 10//number of tries to spawn meteor.
	while (!istype(pickedstart, /turf/space))
		var/startSide = pick(cardinal)
		pickedstart = spaceDebrisStartLoc(startSide, 1)
		pickedgoal = spaceDebrisFinishLoc(startSide, 1)
		max_i--
		if(max_i<=0)
			return
	var/Me = pickweight(meteortypes)
	var/obj/effect/meteor/M = new Me(pickedstart)
	M.dest = pickedgoal
	M.z_original = 1
	spawn(0)
		walk_towards(M, M.dest, 1)
	return

/proc/spaceDebrisStartLoc(startSide, Z)
	var/starty
	var/startx
	switch(startSide)
		if(1) //NORTH
			starty = world.maxy-(TRANSITIONEDGE+1)
			startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1))
		if(2) //EAST
			starty = rand((TRANSITIONEDGE+1),world.maxy-(TRANSITIONEDGE+1))
			startx = world.maxx-(TRANSITIONEDGE+1)
		if(3) //SOUTH
			starty = (TRANSITIONEDGE+1)
			startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1))
		if(4) //WEST
			starty = rand((TRANSITIONEDGE+1), world.maxy-(TRANSITIONEDGE+1))
			startx = (TRANSITIONEDGE+1)
	var/turf/T = locate(startx, starty, Z)
	return T

/proc/spaceDebrisFinishLoc(startSide, Z)
	var/endy
	var/endx
	switch(startSide)
		if(1) //NORTH
			endy = TRANSITIONEDGE
			endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE)
		if(2) //EAST
			endy = rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE)
			endx = TRANSITIONEDGE
		if(3) //SOUTH
			endy = world.maxy-TRANSITIONEDGE
			endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE)
		if(4) //WEST
			endy = rand(TRANSITIONEDGE,world.maxy-TRANSITIONEDGE)
			endx = world.maxx-TRANSITIONEDGE
	var/turf/T = locate(endx, endy, Z)
	return T

///////////////////////
//The meteor effect
//////////////////////

/obj/effect/meteor
	name = "the concept of meteor"
	desc = "You should probably run instead of gawking at this."
	icon = 'icons/obj/meteor.dmi'
	icon_state = "small"
	density = 1
	anchored = 1
	var/hits = 4
	var/hitpwr = 2 //Level of ex_act to be called on hit.
	var/dest
	pass_flags = PASSTABLE
	var/heavy = 0
	var/meteorsound = 'sound/effects/meteorimpact.ogg'
	var/z_original = 1

	var/meteordrop = /obj/item/weapon/ore/iron
	var/dropamt = 2

/obj/effect/meteor/Move()
	if(z != z_original || loc == dest)
		qdel(src)
		return

	. = ..() //process movement...

	if(.)//.. if did move, ram the turf we get in
		var/turf/T = get_turf(loc)
		ram_turf(T)

		if(prob(10) && !istype(T, /turf/space))//randomly takes a 'hit' from ramming
			get_hit()

	return .

/obj/effect/meteor/Destroy()
	walk(src,0) //this cancels the walk_towards() proc
	..()

/obj/effect/meteor/New()
	..()
	SpinAnimation()

/obj/effect/meteor/Bump(atom/A)
	if(A)
		ram_turf(get_turf(A))
		playsound(src.loc, meteorsound, 40, 1)
		get_hit()

/obj/effect/meteor/proc/ram_turf(var/turf/T)
	//first bust whatever is in the turf
	for(var/atom/A in T)
		if(A != src)
			A.ex_act(hitpwr)

	//then, ram the turf if it still exists
	if(T)
		T.ex_act(hitpwr)

//process getting 'hit' by colliding with a dense object
//or randomly when ramming turfs
/obj/effect/meteor/proc/get_hit()
	hits--
	if(hits <= 0)
		make_debris()
		meteor_effect(heavy)
		qdel(src)

/obj/effect/meteor/ex_act()
	return

/obj/effect/meteor/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
	if(istype(W, /obj/item/weapon/pickaxe))
		qdel(src)
		return
	..()

/obj/effect/meteor/proc/make_debris()
	for(var/throws = dropamt, throws > 0, throws--)
		var/obj/item/O = new meteordrop(get_turf(src))
		O.throw_at(dest, 5, 10)

/obj/effect/meteor/proc/meteor_effect(var/sound=1)
	if(sound)
		for(var/mob/M in player_list)
			var/turf/T = get_turf(M)
			if(!T || T.z != src.z)
				continue
			var/dist = get_dist(M.loc, src.loc)
			shake_camera(M, dist > 20 ? 3 : 5, dist > 20 ? 1 : 3)
			M.playsound_local(src.loc, meteorsound, 50, 1, get_rand_frequency(), 10)

///////////////////////
//Meteor types
///////////////////////

//Dust
/obj/effect/meteor/dust
	name = "space dust"
	icon_state = "dust"
	pass_flags = PASSTABLE | PASSGRILLE
	hits = 1
	hitpwr = 3
	meteorsound = 'sound/weapons/throwtap.ogg'
	meteordrop = /obj/item/weapon/ore/glass

//Medium-sized
/obj/effect/meteor/medium
	name = "meteor"
	dropamt = 3

/obj/effect/meteor/medium/meteor_effect()
	..(heavy)
	explosion(src.loc, 0, 1, 2, 3, 0)

//Large-sized
/obj/effect/meteor/big
	name = "big meteor"
	icon_state = "large"
	hits = 6
	heavy = 1
	dropamt = 4

/obj/effect/meteor/big/meteor_effect()
	..(heavy)
	explosion(src.loc, 1, 2, 3, 4, 0)

//Flaming meteor
/obj/effect/meteor/flaming
	name = "flaming meteor"
	icon_state = "flaming"
	hits = 5
	heavy = 1
	meteorsound = 'sound/effects/bamf.ogg'
	meteordrop = /obj/item/weapon/ore/plasma

/obj/effect/meteor/flaming/meteor_effect()
	..(heavy)
	explosion(src.loc, 1, 2, 3, 4, 0, 0, 5)

//Radiation meteor
/obj/effect/meteor/irradiated
	name = "glowing meteor"
	icon_state = "glowing"
	heavy = 1
	meteordrop = /obj/item/weapon/ore/uranium

/obj/effect/meteor/irradiated/meteor_effect()
	..(heavy)
	explosion(src.loc, 0, 0, 4, 3, 0)
	new /obj/effect/decal/cleanable/greenglow(get_turf(src))
	for(var/mob/living/L in view(5, src))
		L.apply_effect(40, IRRADIATE)

//Meaty Ore
/obj/effect/meteor/meaty
	name = "meaty ore"
	icon_state = "meateor"
	desc = "Just... don't think too hard about where this thing came from."
	hits = 2
	heavy = 1
	meteorsound = 'sound/effects/blobattack.ogg'
	meteordrop = /obj/item/weapon/reagent_containers/food/snacks/meat/slab
	var/meteorgibs = /obj/effect/gibspawner/generic

/obj/effect/meteor/meaty/make_debris()
	..()
	new meteorgibs(get_turf(src))

/obj/effect/meteor/meaty/ram_turf(var/turf/T)
	if(!istype(T, /turf/space))
		new /obj/effect/decal/cleanable/blood (T)

/obj/effect/meteor/meaty/Bump(atom/A)
	A.ex_act(hitpwr)
	get_hit()

//Meaty Ore Xeno edition
/obj/effect/meteor/meaty/xeno
	color = "#5EFF00"
	meteordrop = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/xeno
	meteorgibs = /obj/effect/gibspawner/xeno

/obj/effect/meteor/meaty/xeno/ram_turf(var/turf/T)
	if(!istype(T, /turf/space))
		new /obj/effect/decal/cleanable/xenoblood (T)

//Station buster Tunguska
/obj/effect/meteor/tunguska
	name = "tunguska meteor"
	icon_state = "flaming"
	desc = "Your life briefly passes before your eyes the moment you lay them on this monstruosity"
	hits = 30
	hitpwr = 1
	heavy = 1
	meteorsound = 'sound/effects/bamf.ogg'
	meteordrop = /obj/item/weapon/ore/plasma

/obj/effect/meteor/tunguska/meteor_effect()
	..(heavy)
	explosion(src.loc, 5, 10, 15, 20, 0)

/obj/effect/meteor/tunguska/Bump()
	..()
	if(prob(20))
		explosion(src.loc,2,4,6,8)

//////////////////////////
//Spookoween meteors
/////////////////////////

/var/list/meteorsSPOOKY = list(/obj/effect/meteor/pumpkin)

/obj/effect/meteor/pumpkin
	name = "PUMPKING"
	desc = "THE PUMPKING'S COMING!"
	icon = 'icons/obj/meteor_spooky.dmi'
	icon_state = "pumpkin"
	hits = 10
	heavy = 1
	dropamt = 1

/obj/effect/meteor/pumpkin/New()
	..()
	meteordrop = pick(/obj/item/clothing/head/hardhat/pumpkinhead, /obj/item/weapon/reagent_containers/food/snacks/grown/pumpkin)
	meteorsound = pick('sound/hallucinations/im_here1.ogg','sound/hallucinations/im_here2.ogg')
//////////////////////////


code:
/datum/game_mode
	var/list/ape_infectees = list()

/datum/game_mode/monkey
	name = "monkey"
	config_tag = "monkey"
	antag_flag = BE_MONKEY

	required_players = 20
	required_enemies = 1
	recommended_enemies = 1

	restricted_jobs = list("Cyborg", "AI", "MoMMI")

	var/carriers_to_make = 1
	var/list/carriers = list()

	var/monkeys_to_win = 1
	var/escaped_monkeys = 0

	var/players_per_carrier = 30

/datum/game_mode/monkey/pre_setup()
	carriers_to_make = max(round(num_players()/players_per_carrier, 1), 1)

	for(var/j = 0, j < carriers_to_make, j++)
		if (!antag_candidates.len)
			break
		var/datum/mind/carrier = pick(antag_candidates)
		carriers += carrier
		carrier.special_role = "monkey"
		carrier.restricted_roles = restricted_jobs
		log_game("[carrier.key] (ckey) has been selected as a Jungle Fever carrier")
		antag_candidates -= carrier

	if(!carriers.len)
		return 0
	return 1

/datum/game_mode/monkey/announce()
	world << "The current game mode is - Monkey!"
	world << "One or more crewmembers have been infected with Jungle Fever! Crew: Contain the outbreak. None of the infected monkeys may escape alive to Centcom. \
				Monkeys: Ensure that your kind lives on! Rise up against your captors!"

/datum/game_mode/monkey/proc/greet_carrier(var/datum/mind/carrier)
	carrier.current << "You are the Jungle Fever patient zero!!"
	carrier.current << "You have been planted onto this station by the Animal Rights Consortium."
	carrier.current << "Soon the disease will transform you into an ape. Afterwards, you will be able spread the infection to others with a bite."
	carrier.current << "While your infection strain is undetectable by scanners, any other infectees will show up on medical equipment."
	carrier.current << "Your mission will be deemed a success if any of the live infected monkeys reach Centcom."
	return

/datum/game_mode/monkey/post_setup()
	for(var/datum/mind/carriermind in carriers)
		greet_carrier(carriermind)
		ape_infectees += carriermind

		var/datum/disease/D = new /datum/disease/transformation/jungle_fever
		D.visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
		D.holder = carriermind.current
		D.affected_mob = carriermind.current
		carriermind.current.viruses += D
	..()

/datum/game_mode/monkey/proc/check_monkey_victory()
	for(var/mob/living/carbon/monkey/M in living_mob_list)
		if (M.HasDisease(/datum/disease/transformation/jungle_fever))
			if(M.onCentcom())
				escaped_monkeys++
	if(escaped_monkeys >= monkeys_to_win)
		return 0
	else
		return 1

/datum/game_mode/proc/add_monkey(datum/mind/monkey_mind)
	ape_infectees |= monkey_mind
	monkey_mind.special_role = "Infected Monkey"

/datum/game_mode/proc/remove_monkey(datum/mind/monkey_mind)
	ape_infectees.Remove(monkey_mind)
	monkey_mind.special_role = null

/datum/game_mode/monkey/declare_completion()
	if(!check_monkey_victory())
		feedback_set_details("round_end_result","win - monkey win")
		feedback_set("round_end_result",escaped_monkeys)
		world << "The monkeys have overthrown their captors! Eeek eeeek!!"
	else
		feedback_set_details("round_end_result","loss - staff stopped the monkeys")
		feedback_set("round_end_result",escaped_monkeys)
		world << "The staff managed to contain the monkey infestation!"


code:
/datum/game_mode
	var/list/datum/mind/syndicates = list()

/datum/game_mode/nuclear
	name = "nuclear emergency"
	config_tag = "nuclear"
	required_players = 20 // 20 players - 5 players to be the nuke ops = 15 players remaining
	required_enemies = 5
	recommended_enemies = 5
	antag_flag = BE_OPERATIVE
	enemy_minimum_age = 14

	var/const/agents_possible = 5 //If we ever need more syndicate agents.

	var/nukes_left = 1 // Call 3714-PRAY right now and order more nukes! Limited offer!
	var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station
	var/syndies_didnt_escape = 0 //Used for tracking if the syndies got the shuttle off of the z-level

/datum/game_mode/nuclear/announce()
	world << "The current game mode is - Nuclear Emergency!"
	world << "A [syndicate_name()] Strike Force is approaching [station_name()]!"
	world << "A nuclear explosive was being transported by Nanotrasen to a military base. The transport ship mysteriously lost contact with Space Traffic Control (STC). About that time a strange disk was discovered around [station_name()]. It was identified by Nanotrasen as a nuclear auth. disk and now Syndicate Operatives have arrived to retake the disk and detonate SS13! Also, most likely Syndicate star ships are in the vicinity so take care not to lose the disk!\nSyndicate: Reclaim the disk and detonate the nuclear bomb anywhere on SS13.\nPersonnel: Hold the disk and escape with the disk on the shuttle!"

/datum/game_mode/nuclear/pre_setup()
	var/agent_number = 0
	if(antag_candidates.len > agents_possible)
		agent_number = agents_possible
	else
		agent_number = antag_candidates.len

	var/n_players = num_players()
	if(agent_number > n_players)
		agent_number = n_players/2

	while(agent_number > 0)
		var/datum/mind/new_syndicate = pick(antag_candidates)
		syndicates += new_syndicate
		antag_candidates -= new_syndicate //So it doesn't pick the same guy each time.
		agent_number--

	for(var/datum/mind/synd_mind in syndicates)
		synd_mind.assigned_role = "MODE"
		synd_mind.special_role = "Syndicate"//So they actually have a special role/N
		log_game("[synd_mind.key] (ckey) has been selected as a nuclear operative")
	return 1

////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
/datum/game_mode/proc/update_synd_icons_added(datum/mind/synd_mind)
	var/datum/atom_hud/antag/opshud = huds[ANTAG_HUD_OPS]
	opshud.join_hud(synd_mind.current)
	set_antag_hud(synd_mind.current, "synd")

/datum/game_mode/proc/update_synd_icons_removed(datum/mind/synd_mind)
	var/datum/atom_hud/antag/opshud = huds[ANTAG_HUD_OPS]
	opshud.leave_hud(synd_mind.current)
	set_antag_hud(synd_mind.current, null)

////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////

/datum/game_mode/nuclear/post_setup()

	var/list/turf/synd_spawn = list()

	for(var/obj/effect/landmark/A in landmarks_list)
		if(A.name == "Syndicate-Spawn")
			synd_spawn += get_turf(A)
			continue

	var/obj/effect/landmark/uplinklocker = locate("landmark*Syndicate-Uplink")	//i will be rewriting this shortly
	var/obj/effect/landmark/nuke_spawn = locate("landmark*Nuclear-Bomb")

	var/nuke_code = "[rand(10000, 99999)]"
	var/leader_selected = 0
	var/agent_number = 1
	var/spawnpos = 1

	for(var/datum/mind/synd_mind in syndicates)
		if(spawnpos > synd_spawn.len)
			spawnpos = 2
		synd_mind.current.loc = synd_spawn[spawnpos]

		forge_syndicate_objectives(synd_mind)
		greet_syndicate(synd_mind)
		equip_syndicate(synd_mind.current)

		if (nuke_code)
			synd_mind.store_memory("Syndicate Nuclear Bomb Code: [nuke_code]", 0, 0)
			synd_mind.current << "The nuclear authorization code is: [nuke_code]"

		if(!leader_selected)
			prepare_syndicate_leader(synd_mind, nuke_code)
			leader_selected = 1
		else
			synd_mind.current.real_name = "[syndicate_name()] Operative #[agent_number]"
			agent_number++
		spawnpos++
		update_synd_icons_added(synd_mind)

	if(uplinklocker)
		new /obj/structure/closet/syndicate/nuclear(uplinklocker.loc)
	if(nuke_spawn && synd_spawn.len > 0)
		var/obj/machinery/nuclearbomb/the_bomb = new /obj/machinery/nuclearbomb(nuke_spawn.loc)
		the_bomb.r_code = nuke_code

	return ..()

/datum/game_mode/proc/prepare_syndicate_leader(var/datum/mind/synd_mind, var/nuke_code)
	var/leader_title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
	spawn(1)
		NukeNameAssign(nukelastname(synd_mind.current),syndicates) //allows time for the rest of the syndies to be chosen
	synd_mind.current.real_name = "[syndicate_name()] [leader_title]"
	synd_mind.current << "You are the Syndicate [leader_title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors."
	synd_mind.current << "If you feel you are not up to this task, give your ID to another operative."

	var/list/foundIDs = synd_mind.current.search_contents_for(/obj/item/weapon/card/id)
	if(foundIDs.len)
		for(var/obj/item/weapon/card/id/ID in foundIDs)
			ID.name = "lead agent card"
			ID.access += access_syndicate_leader
	else
		message_admins("Warning: Nuke Ops spawned without access to leave their spawn area!")

	if (nuke_code)
		var/obj/item/weapon/paper/P = new
		P.info = "The nuclear authorization code is: [nuke_code]"
		P.name = "nuclear bomb code"
		var/mob/living/carbon/human/H = synd_mind.current
		P.loc = H.loc
		H.equip_to_slot_or_del(P, slot_r_hand, 0)
		H.update_icons()
	else
		nuke_code = "code will be provided later"
	return

/datum/game_mode/proc/forge_syndicate_objectives(var/datum/mind/syndicate)
	var/datum/objective/nuclear/syndobj = new
	syndobj.owner = syndicate
	syndicate.objectives += syndobj

/datum/game_mode/proc/greet_syndicate(var/datum/mind/syndicate, var/you_are=1)
	if (you_are)
		syndicate.current << "You are a [syndicate_name()] agent!"
	var/obj_count = 1
	for(var/datum/objective/objective in syndicate.objectives)
		syndicate.current << "Objective #[obj_count]: [objective.explanation_text]"
		obj_count++
	return

/datum/game_mode/proc/random_radio_frequency()
	return 1337 // WHY??? -- Doohl

/datum/game_mode/proc/equip_syndicate(mob/living/carbon/human/synd_mob)
	var/radio_freq = SYND_FREQ

	var/obj/item/device/radio/R = new /obj/item/device/radio/headset/syndicate/alt(synd_mob)
	R.set_frequency(radio_freq)
	synd_mob.equip_to_slot_or_del(R, slot_ears)

	synd_mob.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(synd_mob), slot_w_uniform)
	synd_mob.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(synd_mob), slot_shoes)
	synd_mob.equip_to_slot_or_del(new /obj/item/clothing/gloves/combat(synd_mob), slot_gloves)
	synd_mob.equip_to_slot_or_del(new /obj/item/weapon/card/id/syndicate(synd_mob), slot_wear_id)
	if(synd_mob.backbag == 2) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(synd_mob), slot_back)
	if(synd_mob.backbag == 3) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(synd_mob), slot_back)
	synd_mob.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/automatic/pistol(synd_mob), slot_belt)
	synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(synd_mob.back), slot_in_backpack)

	var/obj/item/device/radio/uplink/U = new /obj/item/device/radio/uplink(synd_mob)
	U.hidden_uplink.uplink_owner="[synd_mob.key]"
	U.hidden_uplink.uses = 20
	synd_mob.equip_to_slot_or_del(U, slot_in_backpack)

	var/obj/item/weapon/implant/weapons_auth/E = new/obj/item/weapon/implant/weapons_auth(synd_mob)
	E.imp_in = synd_mob
	E.implanted = 1
	E.implanted(synd_mob)

	var/obj/item/weapon/implant/explosive/Ex = new/obj/item/weapon/implant/explosive(synd_mob)
	Ex.imp_in = synd_mob
	Ex.implanted = 1
	Ex.implanted(synd_mob)

	synd_mob.faction |= "syndicate"
	synd_mob.update_icons()
	return 1

/datum/game_mode/nuclear/check_win()
	if (nukes_left == 0)
		return 1
	return ..()

/datum/game_mode/proc/are_operatives_dead()
	for(var/datum/mind/operative_mind in syndicates)
		if (istype(operative_mind.current,/mob/living/carbon/human) && (operative_mind.current.stat!=2))
			return 0
	return 1

/datum/game_mode/nuclear/declare_completion()
	var/disk_rescued = 1
	for(var/obj/item/weapon/disk/nuclear/D in world)
		if(!D.onCentcom())
			disk_rescued = 0
			break
	var/crew_evacuated = (SSshuttle.emergency.mode >= SHUTTLE_ENDGAME)
	//var/operatives_are_dead = is_operatives_are_dead()

	//nukes_left
	//station_was_nuked
	//derp //Used for tracking if the syndies actually haul the nuke to the station	//no
	//herp //Used for tracking if the syndies got the shuttle off of the z-level	//NO, DON'T FUCKING NAME VARS LIKE THIS

	if      (!disk_rescued &&  station_was_nuked && !syndies_didnt_escape)
		feedback_set_details("round_end_result","win - syndicate nuke")
		world << "Syndicate Major Victory!"
		world << "[syndicate_name()] operatives have destroyed [station_name()]!"

	else if (!disk_rescued &&  station_was_nuked && syndies_didnt_escape)
		feedback_set_details("round_end_result","halfwin - syndicate nuke - did not evacuate in time")
		world << "Total Annihilation"
		world << "[syndicate_name()] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion. Next time, don't lose the disk!"

	else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape)
		feedback_set_details("round_end_result","halfwin - blew wrong station")
		world << "Crew Minor Victory"
		world << "[syndicate_name()] operatives secured the authentication disk but blew up something that wasn't [station_name()]. Next time, don't lose the disk!"

	else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape)
		feedback_set_details("round_end_result","halfwin - blew wrong station - did not evacuate in time")
		world << "[syndicate_name()] operatives have earned Darwin Award!"
		world << "[syndicate_name()] operatives blew up something that wasn't [station_name()] and got caught in the explosion. Next time, don't lose the disk!"

	else if ( disk_rescued && are_operatives_dead())
		feedback_set_details("round_end_result","loss - evacuation - disk secured - syndi team dead")
		world << "Crew Major Victory!"
		world << "The Research Staff has saved the disc and killed the [syndicate_name()] Operatives"

	else if ( disk_rescued )
		feedback_set_details("round_end_result","loss - evacuation - disk secured")
		world << "Crew Major Victory"
		world << "The Research Staff has saved the disc and stopped the [syndicate_name()] Operatives!"

	else if (!disk_rescued && are_operatives_dead())
		feedback_set_details("round_end_result","loss - evacuation - disk not secured")
		world << "Syndicate Minor Victory!"
		world << "The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name()] Operatives!"

	else if (!disk_rescued &&  crew_evacuated)
		feedback_set_details("round_end_result","halfwin - detonation averted")
		world << "Syndicate Minor Victory!"
		world << "[syndicate_name()] operatives recovered the abandoned authentication disk but detonation of [station_name()] was averted. Next time, don't lose the disk!"

	else if (!disk_rescued && !crew_evacuated)
		feedback_set_details("round_end_result","halfwin - interrupted")
		world << "Neutral Victory"
		world << "Round was mysteriously interrupted!"

	..()
	return

/datum/game_mode/proc/auto_declare_completion_nuclear()
	if( syndicates.len || (ticker && istype(ticker.mode,/datum/game_mode/nuclear)) )
		var/text = "
The syndicate operatives were:"

		var/purchases = ""
		var/TC_uses = 0

		for(var/datum/mind/syndicate in syndicates)

			text += "
[syndicate.key] was [syndicate.name] ("
			if(syndicate.current)
				if(syndicate.current.stat == DEAD)
					text += "died"
				else
					text += "survived"
				if(syndicate.current.real_name != syndicate.name)
					text += " as [syndicate.current.real_name]"
			else
				text += "body destroyed"
			text += ")"

			for(var/obj/item/device/uplink/H in world_uplinks)
				if(H && H.uplink_owner && H.uplink_owner==syndicate.key)
					TC_uses += H.used_TC
					purchases += H.purchase_log

		text += "
"

		text += "(Syndicates used [TC_uses] TC) [purchases]"

		if(TC_uses==0 && station_was_nuked && !are_operatives_dead())
			text += "<BIG></BIG>"

		world << text
	return 1

/proc/nukelastname(var/mob/M as mob) //--All praise goes to NEO|Phyte, all blame goes to DH, and it was Cindi-Kate's idea. Also praise Urist for copypasta ho.
	var/randomname = pick(last_names)
	var/newname = copytext(sanitize(input(M,"You are the nuke operative [pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")]. Please choose a last name for your family.", "Name change",randomname)),1,MAX_NAME_LEN)

	if (!newname)
		newname = randomname

	else
		if (newname == "Unknown" || newname == "floor" || newname == "wall" || newname == "rwall" || newname == "_")
			M << "That name is reserved."
			return nukelastname(M)

	return newname

/proc/NukeNameAssign(var/lastname,var/list/syndicates)
	for(var/datum/mind/synd_mind in syndicates)
		switch(synd_mind.current.gender)
			if(MALE)
				synd_mind.name = "[pick(first_names_male)] [lastname]"
			if(FEMALE)
				synd_mind.name = "[pick(first_names_female)] [lastname]"
		synd_mind.current.real_name = synd_mind.name
	return


code:
var/bomb_set

/obj/machinery/nuclearbomb
	name = "nuclear fission explosive"
	desc = "You probably shouldn't stick around to see if this is armed."
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "nuclearbomb0"
	density = 1

	var/timeleft = 60.0
	var/timing = 0.0
	var/r_code = "ADMIN"
	var/code = ""
	var/yes_code = 0.0
	var/safety = 1.0
	var/obj/item/weapon/disk/nuclear/auth = null
	use_power = 0
	var/previous_level = ""
	var/lastentered = ""
	var/immobile = 0 //Not all nukes should be moved

/obj/machinery/nuclearbomb/selfdestruct
	name = "station self-destruct terminal"
	desc = "For when it all gets too much to bear. Do not taunt."
	icon = 'icons/obj/machines/bignuke.dmi'
	anchored = 1 //stops it being moved
	immobile = 1 //prevents it from ever being moved
	layer = 4

/obj/machinery/nuclearbomb/process()
	if (src.timing)
		bomb_set = 1 //So long as there is one nuke timing, it means one nuke is armed.
		src.timeleft--
		if (src.timeleft <= 0)
			explode()
		else
			var/volume = (timeleft <= 20 ? 30 : 5)
			playsound(loc, 'sound/items/timer.ogg', volume, 0)
		for(var/mob/M in viewers(1, src))
			if ((M.client && M.machine == src))
				src.attack_hand(M)
	return

/obj/machinery/nuclearbomb/attackby(obj/item/weapon/I as obj, mob/user as mob, params)
	if (istype(I, /obj/item/weapon/disk/nuclear))
		usr.drop_item()
		I.loc = src
		src.auth = I
		src.add_fingerprint(user)
		return
	..()

/obj/machinery/nuclearbomb/attack_paw(mob/user as mob)
	return src.attack_hand(user)

/obj/machinery/nuclearbomb/attack_ai(mob/user as mob)
	return

/obj/machinery/nuclearbomb/attack_hand(mob/user as mob)
	user.set_machine(src)
	var/dat = text("<TT>\nAuth. Disk: []
", src, (src.auth ? "++++++++++" : "----------"))
	if (src.auth)
		if (src.yes_code)
			dat += text("\nStatus: []-[]
\nTimer: []
\n
\nTimer: [] Toggle
\nTime: - - [] + +
\n
\nSafety: [] Toggle
\nAnchor: [] Toggle
\n", (src.timing ? "Func/Set" : "Functional"), (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src, src, src, src.timeleft, src, src, (src.safety ? "On" : "Off"), src, (src.anchored ? "Engaged" : "Off"), src)
		else
			dat += text("\nStatus: Auth. S2-[]
\nTimer: []
\n
\nTimer: [] Toggle
\nTime: - - [] + +
\n
\n[] Safety: Toggle
\nAnchor: [] Toggle
\n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off"))
	else
		if (src.timing)
			dat += text("\nStatus: Set-[]
\nTimer: []
\n
\nTimer: [] Toggle
\nTime: - - [] + +
\n
\nSafety: [] Toggle
\nAnchor: [] Toggle
\n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off"))
		else
			dat += text("\nStatus: Auth. S1-[]
\nTimer: []
\n
\nTimer: [] Toggle
\nTime: - - [] + +
\n
\nSafety: [] Toggle
\nAnchor: [] Toggle
\n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off"))
	var/message = "AUTH"
	if (src.auth)
		message = text("[]", src.code)
		if (src.yes_code)
			message = "*****"
	dat += text("
\n>[]
\n123
\n456
\n789
\nR0E
\n</TT>", message, src, src, src, src, src, src, src, src, src, src, src, src)
	var/datum/browser/popup = new(user, "nuclearbomb", name, 300, 400)
	popup.set_content(dat)
	popup.open()
	return

/obj/machinery/nuclearbomb/Topic(href, href_list)
	if(..())
		return
	usr.set_machine(src)
	if (href_list["auth"])
		if (src.auth)
			src.auth.loc = src.loc
			src.yes_code = 0
			src.auth = null
		else
			var/obj/item/I = usr.get_active_hand()
			if (istype(I, /obj/item/weapon/disk/nuclear))
				usr.drop_item()
				I.loc = src
				src.auth = I
	if (src.auth)
		if (href_list["type"])
			if (href_list["type"] == "E")
				if (src.code == src.r_code)
					src.yes_code = 1
					src.code = null
				else
					src.code = "ERROR"
			else
				if (href_list["type"] == "R")
					src.yes_code = 0
					src.code = null
				else
					lastentered = text("[]", href_list["type"])
					if (text2num(lastentered) == null)
						var/turf/LOC = get_turf(usr)
						message_admins("[key_name_admin(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered] ! ([LOC ? "JMP" : "null"])", 0)
						log_admin("EXPLOIT : [key_name(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered] !")
					else
						src.code += lastentered
						if (length(src.code) > 5)
							src.code = "ERROR"
		if (src.yes_code)
			if (href_list["time"])
				var/time = text2num(href_list["time"])
				src.timeleft += time
				src.timeleft = min(max(round(src.timeleft), 60), 600)
			if (href_list["timer"])
				if (src.timing == -1.0)
					return
				if (src.safety)
					usr << "The safety is still on."
					return
				src.timing = !( src.timing )
				if (src.timing)
					src.icon_state = "nuclearbomb2"
					if(!src.safety)
						bomb_set = 1//There can still be issues with this reseting when there are multiple bombs. Not a big deal tho for Nuke/N
						src.previous_level = "[get_security_level()]"
						set_security_level("delta")
					else
						bomb_set = 0
						set_security_level("[previous_level]")
				else
					src.icon_state = "nuclearbomb1"
					bomb_set = 0
					set_security_level("[previous_level]")
			if (href_list["safety"])
				src.safety = !( src.safety )
				src.icon_state = "nuclearbomb1"
				if(safety)
					src.timing = 0
					bomb_set = 0
			if (href_list["anchor"])
				if(!isinspace()&&(!immobile))
					src.anchored = !( src.anchored )
				else if(immobile)
					usr << "This device is immovable!"
				else
					usr << "There is nothing to anchor to!"
	src.add_fingerprint(usr)
	for(var/mob/M in viewers(1, src))
		if ((M.client && M.machine == src))
			src.attack_hand(M)

/obj/machinery/nuclearbomb/ex_act(severity, target)
	return

/obj/machinery/nuclearbomb/blob_act()
	if (src.timing == -1.0)
		return
	else
		return ..()
	return

#define NUKERANGE 80
/obj/machinery/nuclearbomb/proc/explode()
	if (src.safety)
		src.timing = 0
		return
	src.timing = -1.0
	src.yes_code = 0
	src.safety = 1
	src.icon_state = "nuclearbomb3"
	for(var/mob/M in player_list)
		M << 'sound/machines/Alarm.ogg'
	if (ticker && ticker.mode)
		ticker.mode.explosion_in_progress = 1
	sleep(100)

	enter_allowed = 0

	var/off_station = 0
	var/turf/bomb_location = get_turf(src)
	if( bomb_location && (bomb_location.z == ZLEVEL_STATION) )
		if( (bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE)) )
			off_station = 1
	else
		off_station = 2

	if(ticker.mode && ticker.mode.name == "nuclear emergency")
		var/obj/docking_port/mobile/Shuttle = SSshuttle.getShuttle("syndicate")
		ticker.mode:syndies_didnt_escape = (Shuttle && Shuttle.z == ZLEVEL_CENTCOM) ? 0 : 1
		ticker.mode:nuke_off_station = off_station
	ticker.station_explosion_cinematic(off_station,null)
	if(ticker.mode)
		ticker.mode.explosion_in_progress = 0
		if(ticker.mode.name == "nuclear emergency")
			ticker.mode:nukes_left --
		else
			world << "The station was destoyed by the nuclear blast!"

		ticker.mode.station_was_nuked = (off_station<2)	//offstation==1 is a draw. the station becomes irradiated and needs to be evacuated.
														//kinda shit but I couldn't  get permission to do what I wanted to do.

		if(!ticker.mode.check_finished())//If the mode does not deal with the nuke going off so just reboot because everyone is stuck as is
			world.Reboot("Station destroyed by Nuclear Device.", "end_error", "nuke - unhandled ending")
	return

/*
This is here to make the tiles around the station mininuke change when it's armed.
*/

/obj/machinery/nuclearbomb/selfdestruct/proc/SetTurfs()
	if(loc == initial(loc))
		var/text_icon_state = "[timing ? "rcircuitanim" : "gcircuit"]"
		for(var/turf/simulated/floor/bluegrid/T in orange(src, 1))
			T.icon_state = text_icon_state

/obj/machinery/nuclearbomb/selfdestruct/Topic()
        ..()
        SetTurfs()

//==========DAT FUKKEN DISK===============
/obj/item/weapon/disk/nuclear
	name = "nuclear authentication disk"
	desc = "Better keep this safe."
	icon_state = "nucleardisk"
	item_state = "card-id"
	w_class = 1.0

/obj/item/weapon/disk/nuclear/New()
	..()
	SSobj.processing |= src

/obj/item/weapon/disk/nuclear/process()
	var/turf/disk_loc = get_turf(src)
	if(disk_loc.z > ZLEVEL_CENTCOM)
		get(src, /mob) << "You can't help but feel that you just lost something back there..."
		qdel(src)

/obj/item/weapon/disk/nuclear/Destroy()
	if(blobstart.len > 0)
		var/obj/item/weapon/disk/nuclear/NEWDISK = new(pick(blobstart))
		transfer_fingerprints_to(NEWDISK)
		var/turf/diskturf = get_turf(src)
		message_admins("[src] has been destroyed in ([diskturf.x], [diskturf.y] ,[diskturf.z] - JMP). Moving it to ([NEWDISK.x], [NEWDISK.y], [NEWDISK.z] - JMP).")
		log_game("[src] has been destroyed in ([diskturf.x], [diskturf.y] ,[diskturf.z]). Moving it to ([NEWDISK.x], [NEWDISK.y], [NEWDISK.z]).")
		return QDEL_HINT_HARDDEL_NOW //Needed to clear all references to it
	else
		ERROR("[src] was supposed to be destroyed, but we were unable to locate a blobstart landmark to spawn a new one.")
	return QDEL_HINT_LETMELIVE // Cancel destruction.


code:
/obj/item/weapon/pinpointer
	name = "pinpointer"
	icon = 'icons/obj/device.dmi'
	icon_state = "pinoff"
	flags = CONDUCT
	slot_flags = SLOT_BELT
	w_class = 2.0
	item_state = "electronic"
	throw_speed = 3
	throw_range = 7
	m_amt = 500
	var/obj/item/weapon/disk/nuclear/the_disk = null
	var/active = 0

/obj/item/weapon/pinpointer/Destroy()
	active = 0
	..()

/obj/item/weapon/pinpointer/attack_self()
	if(!active)
		active = 1
		workdisk()
		usr << "You activate the pinpointer."
	else
		active = 0
		icon_state = "pinoff"
		usr << "You deactivate the pinpointer."

/obj/item/weapon/pinpointer/proc/scandisk()
	if(!the_disk)
		the_disk = locate()

/obj/item/weapon/pinpointer/proc/point_at(atom/target, spawnself = 1)
	if(!active)
		return
	if(!target)
		icon_state = "pinonnull"
		return

	var/turf/T = get_turf(target)
	var/turf/L = get_turf(src)

	if(T.z != L.z)
		icon_state = "pinonnull"
	else
		dir = get_dir(L, T)
		switch(get_dist(L, T))
			if(-1)
				icon_state = "pinondirect"
			if(1 to 8)
				icon_state = "pinonclose"
			if(9 to 16)
				icon_state = "pinonmedium"
			if(16 to INFINITY)
				icon_state = "pinonfar"
	if(spawnself)
		spawn(5)
			.()

/obj/item/weapon/pinpointer/proc/workdisk()
	scandisk()
	point_at(the_disk, 0)
	spawn(5)
		.()

/obj/item/weapon/pinpointer/examine(mob/user)
	..()
	for(var/obj/machinery/nuclearbomb/bomb in world)
		if(bomb.timing)
			user << "Extreme danger.  Arming signal detected.   Time remaining: [bomb.timeleft]"

/obj/item/weapon/pinpointer/advpinpointer
	name = "advanced pinpointer"
	icon = 'icons/obj/device.dmi'
	desc = "A larger version of the normal pinpointer, this unit features a helpful quantum entanglement detection system to locate various objects that do not broadcast a locator signal."
	var/mode = 0  // Mode 0 locates disk, mode 1 locates coordinates.
	var/turf/location = null
	var/obj/target = null

/obj/item/weapon/pinpointer/advpinpointer/attack_self()
	if(!active)
		active = 1
		if(mode == 0)
			workdisk()
		if(mode == 1)
			point_at(location)
		if(mode == 2)
			point_at(target)
		usr << "You activate the pinpointer."
	else
		active = 0
		icon_state = "pinoff"
		usr << "You deactivate the pinpointer."

/obj/item/weapon/pinpointer/advpinpointer/verb/toggle_mode()
	set category = "Object"
	set name = "Toggle Pinpointer Mode"
	set src in view(1)

	if(usr.stat || usr.restrained() || !usr.canmove)
		return

	active = 0
	icon_state = "pinoff"
	target=null
	location = null

	switch(alert("Please select the mode you want to put the pinpointer in.", "Pinpointer Mode Select", "Location", "Disk Recovery", "Other Signature"))
		if("Location")
			mode = 1

			var/locationx = input(usr, "Please input the x coordinate to search for.", "Location?" , "") as num
			if(!locationx || !(usr in view(1,src)))
				return
			var/locationy = input(usr, "Please input the y coordinate to search for.", "Location?" , "") as num
			if(!locationy || !(usr in view(1,src)))
				return

			var/turf/Z = get_turf(src)

			location = locate(locationx,locationy,Z.z)

			usr << "You set the pinpointer to locate [locationx],[locationy]"

			return attack_self()

		if("Disk Recovery")
			mode = 0
			return attack_self()

		if("Other Signature")
			mode = 2
			switch(alert("Search for item signature or DNA fragment?" , "Signature Mode Select" , "" , "Item" , "DNA"))
				if("Item")
					var/targetitem = input("Select item to search for.", "Item Mode Select","") as null|anything in possible_items
					if(!targetitem)
						return
					target=locate(possible_items[targetitem])
					if(!target)
						usr << "Failed to locate [targetitem]!"
						return
					usr << "You set the pinpointer to locate [targetitem]"
				if("DNA")
					var/DNAstring = input("Input DNA string to search for." , "Please Enter String." , "")
					if(!DNAstring)
						return
					for(var/mob/living/carbon/M in mob_list)
						if(!M.dna)
							continue
						if(M.dna.unique_enzymes == DNAstring)
							target = M
							break

			return attack_self()

///////////////////////
//nuke op pinpointers//
///////////////////////

/obj/item/weapon/pinpointer/nukeop
	var/mode = 0	//Mode 0 locates disk, mode 1 locates the shuttle
	var/obj/docking_port/mobile/home

/obj/item/weapon/pinpointer/nukeop/attack_self(mob/user as mob)
	if(!active)
		active = 1
		if(!mode)
			workdisk()
			user << "Authentication Disk Locator active."
		else
			worklocation()
			user << "Shuttle Locator active."
	else
		active = 0
		icon_state = "pinoff"
		user << "You deactivate the pinpointer."

/obj/item/weapon/pinpointer/nukeop/workdisk()
	if(!active) return
	if(mode)		//Check in case the mode changes while operating
		worklocation()
		return
	if(bomb_set)	//If the bomb is set, lead to the shuttle
		mode = 1	//Ensures worklocation() continues to work
		worklocation()
		playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)	//Plays a beep
		visible_message("Shuttle Locator active.")			//Lets the mob holding it know that the mode has changed
		return		//Get outta here
	scandisk()
	if(!the_disk)
		icon_state = "pinonnull"
		return
	dir = get_dir(src, the_disk)
	switch(get_dist(src, the_disk))
		if(0)
			icon_state = "pinondirect"
		if(1 to 8)
			icon_state = "pinonclose"
		if(9 to 16)
			icon_state = "pinonmedium"
		if(16 to INFINITY)
			icon_state = "pinonfar"

	spawn(5) .()

/obj/item/weapon/pinpointer/nukeop/proc/worklocation()
	if(!active)
		return
	if(!mode)
		workdisk()
		return
	if(!bomb_set)
		mode = 0
		workdisk()
		playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
		visible_message("Authentication Disk Locator active.")
		return
	if(!home)
		home = SSshuttle.getShuttle("syndicate")
		if(!home)
			icon_state = "pinonnull"
			return
	if(loc.z != home.z)	//If you are on a different z-level from the shuttle
		icon_state = "pinonnull"
	else
		dir = get_dir(src, home)
		switch(get_dist(src, home))
			if(0)
				icon_state = "pinondirect"
			if(1 to 8)
				icon_state = "pinonclose"
			if(9 to 16)
				icon_state = "pinonmedium"
			if(16 to INFINITY)
				icon_state = "pinonfar"

	spawn(5)
		.()

/obj/item/weapon/pinpointer/operative
	name = "operative pinpointer"
	icon = 'icons/obj/device.dmi'
	desc = "A pinpointer that leads to the first Syndicate operative detected."
	var/mob/living/carbon/nearest_op = null

/obj/item/weapon/pinpointer/operative/attack_self()
	if(!active)
		active = 1
		workop()
		usr << "You activate the pinpointer."
	else
		active = 0
		icon_state = "pinoff"
		usr << "You deactivate the pinpointer."

/obj/item/weapon/pinpointer/operative/proc/scan_for_ops()
	if(!nearest_op)
		for(var/mob/living/carbon/M in mob_list)
			if(M.mind in ticker.mode.syndicates)
				nearest_op = M

/obj/item/weapon/pinpointer/operative/proc/workop()
	scan_for_ops()
	point_at(nearest_op, 0)
	spawn(5)
		.()

/obj/item/weapon/pinpointer/operative/examine(mob/user)
	..()
	if(nearest_op != null)
		user << "Nearest operative: [nearest_op]."
	if(nearest_op == null && active)
		user << "No operatives detected within scanning range."


code:
datum/objective
	var/datum/mind/owner = null			//Who owns the objective.
	var/explanation_text = "Nothing"	//What that person is supposed to do.
	var/datum/mind/target = null		//If they are focused on a particular person.
	var/target_amount = 0				//If they are focused on a particular number. Steal objectives have their own counter.
	var/completed = 0					//currently only used for custom objectives.
	var/dangerrating = 0				//How hard the objective is, essentially. Used for dishing out objectives and checking overall victory.

datum/objective/New(var/text)
	if(text)
		explanation_text = text

datum/objective/proc/check_completion()
	return completed

datum/objective/proc/is_unique_objective(possible_target)
	for(var/datum/objective/O in owner.objectives)
		if(istype(O, type) && O.get_target() == possible_target)
			return 0
	return 1

datum/objective/proc/get_target()
	return target

datum/objective/proc/find_target()
	var/list/possible_targets = list()
	for(var/datum/mind/possible_target in ticker.minds)
		if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && is_unique_objective(possible_target) && target_check(possible_target))
			possible_targets += possible_target
	if(possible_targets.len > 0)
		target = pick(possible_targets)
	update_explanation_text()
	return target

datum/objective/proc/target_check(var/datum/mind/target)
	return 1

datum/objective/proc/find_target_by_role(role, role_type=0)//Option sets either to check assigned role or special role. Default to assigned.
	for(var/datum/mind/possible_target in ticker.minds)
		if((possible_target != owner) && ishuman(possible_target.current) && ((role_type ? possible_target.special_role : possible_target.assigned_role) == role) )
			target = possible_target
			break
	update_explanation_text()

datum/objective/proc/update_explanation_text()
	//Default does nothing, override where needed

datum/objective/assassinate
	var/target_role_type=0
	dangerrating = 10

datum/objective/assassinate/find_target_by_role(role, role_type=0)
	target_role_type = role_type
	..(role, role_type)
	return target

datum/objective/assassinate/check_completion()
	if(target && target.current)
		if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current) || target.current.z > 6 || !target.current.ckey) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
			return 1
		return 0
	return 1

datum/objective/assassinate/update_explanation_text()
	..()
	if(target && target.current)
		explanation_text = "Assassinate [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
	else
		explanation_text = "Free Objective"

datum/objective/mutiny
	var/target_role_type=0

datum/objective/mutiny/find_target_by_role(role, role_type=0)
	target_role_type = role_type
	..(role, role_type)
	return target

datum/objective/mutiny/check_completion()
	if(target && target.current)
		if(target.current.stat == DEAD || !ishuman(target.current) || !target.current.ckey || !target.current.client)
			return 1
		var/turf/T = get_turf(target.current)
		if(T && (T.z != ZLEVEL_STATION))			//If they leave the station they count as dead for this
			return 2
		return 0
	return 1

datum/objective/mutiny/update_explanation_text()
	..()
	if(target && target.current)
		explanation_text = "Assassinate or exile [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
	else
		explanation_text = "Free Objective"

datum/objective/maroon
	var/target_role_type=0
	dangerrating = 5

datum/objective/maroon/find_target_by_role(role, role_type=0)
	target_role_type = role_type
	..(role, role_type)
	return target

datum/objective/maroon/check_completion()
	if(target && target.current)
		if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current) || target.current.z > 6 || !target.current.ckey) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
			return 1
		if(target.current.onCentcom())
			return 0
	return 1

datum/objective/maroon/update_explanation_text()
	if(target && target.current)
		explanation_text = "Prevent [target.name], the [!target_role_type ? target.assigned_role : target.special_role], from escaping alive."
	else
		explanation_text = "Free Objective"

datum/objective/debrain//I want braaaainssss
	var/target_role_type=0
	dangerrating = 20

datum/objective/debrain/find_target_by_role(role, role_type=0)
	target_role_type = role_type
	..(role, role_type)
	return target

datum/objective/debrain/check_completion()
	if(!target)//If it's a free objective.
		return 1
	if( !owner.current || owner.current.stat==DEAD )//If you're otherwise dead.
		return 0
	if( !target.current || !isbrain(target.current) )
		return 0
	var/atom/A = target.current
	while(A.loc)			//check to see if the brainmob is on our person
		A = A.loc
		if(A == owner.current)
			return 1
	return 0

datum/objective/debrain/update_explanation_text()
	..()
	if(target && target.current)
		explanation_text = "Steal the brain of [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
	else
		explanation_text = "Free Objective"

datum/objective/protect//The opposite of killing a dude.
	var/target_role_type=0
	dangerrating = 10

datum/objective/protect/find_target_by_role(role, role_type=0)
	target_role_type = role_type
	..(role, role_type)
	return target

datum/objective/protect/check_completion()
	if(!target)			//If it's a free objective.
		return 1
	if(target.current)
		if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current))
			return 0
		return 1
	return 0

datum/objective/protect/update_explanation_text()
	..()
	if(target && target.current)
		explanation_text = "Protect [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
	else
		explanation_text = "Free Objective"

datum/objective/hijack
	explanation_text = "Hijack the emergency shuttle by escaping alone."
	dangerrating = 25

datum/objective/hijack/check_completion()
	if(!owner.current || owner.current.stat)
		return 0
	if(SSshuttle.emergency.mode < SHUTTLE_ENDGAME)
		return 0
	if(issilicon(owner.current))
		return 0

	var/area/A = get_area(owner.current)
	if(SSshuttle.emergency.areaInstance != A)
		return 0

	for(var/mob/living/player in player_list)
		if(player.mind && player.mind != owner)
			if(player.stat != DEAD)
				switch(player.type)
					if(/mob/living/silicon/ai, /mob/living/silicon/pai)
						continue
				if(get_area(player) == A)
					return 0
	return 1

datum/objective/block
	explanation_text = "Do not allow any organic lifeforms to escape on the shuttle alive."
	dangerrating = 25

datum/objective/block/check_completion()
	if(!istype(owner.current, /mob/living/silicon))
		return 0
	if(SSshuttle.emergency.mode < SHUTTLE_ENDGAME)
		return 1

	var/area/A = SSshuttle.emergency.areaInstance

	for(var/mob/living/player in player_list)
		if(istype(player, /mob/living/silicon))
			continue
		if(player.mind)
			if(player.stat != DEAD)
				if(get_area(player) == A)
					return 0

	return 1

datum/objective/escape
	explanation_text = "Escape on the shuttle or an escape pod alive and without being in custody."
	dangerrating = 5

datum/objective/escape/check_completion()
	if(issilicon(owner.current))
		return 0
	if(isbrain(owner.current))
		return 0
	if(SSshuttle.emergency.mode < SHUTTLE_ENDGAME)
		return 0
	if(!owner.current || owner.current.stat == DEAD)
		return 0
	var/turf/location = get_turf(owner.current)
	if(!location)
		return 0

	if(istype(location, /turf/simulated/floor/plasteel/shuttle/red)) // Fails traitors if they are in the shuttle brig -- Polymorph
		return 0

	if(location.onCentcom())
		return 1

	return 0

datum/objective/escape/escape_with_identity
	dangerrating = 10
	var/target_real_name // Has to be stored because the target's real_name can change over the course of the round

datum/objective/escape/escape_with_identity/find_target()
	target = ..()
	update_explanation_text()

datum/objective/escape/escape_with_identity/update_explanation_text()
	if(target && target.current)
		target_real_name = target.current.real_name
		explanation_text = "Escape on the shuttle or an escape pod with the identity of [target_real_name], the [target.assigned_role] while wearing their identification card."
	else
		explanation_text = "Free Objective."

datum/objective/escape/escape_with_identity/check_completion()
	if(!target_real_name)
		return 1
	if(!ishuman(owner.current))
		return 0
	var/mob/living/carbon/human/H = owner.current
	if(..())
		if(H.dna.real_name == target_real_name)
			if(H.get_id_name()== target_real_name)
				return 1
	return 0

datum/objective/survive
	explanation_text = "Stay alive until the end."
	dangerrating = 3

datum/objective/survive/check_completion()
	if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current))
		return 0		//Brains no longer win survive objectives. --NEO
	if(!is_special_character(owner.current)) //This fails borg'd traitors
		return 0
	return 1

datum/objective/nuclear
	explanation_text = "Destroy the station with a nuclear device."

var/global/list/possible_items = list()
datum/objective/steal
	var/datum/objective_item/targetinfo = null //Save the chosen item datum so we can access it later.
	var/obj/item/steal_target = null //Needed for custom objectives (they're just items, not datums).
	dangerrating = 5 //Overridden by the individual item's difficulty, but defaults to 5 for custom objectives.

datum/objective/steal/get_target()
	return steal_target

datum/objective/steal/New()
	..()
	if(!possible_items.len)//Only need to fill the list when it's needed.
		init_subtypes(/datum/objective_item/steal,possible_items)

datum/objective/steal/find_target()
	var/approved_targets = list()
	for(var/datum/objective_item/possible_item in possible_items)
		if(is_unique_objective(possible_item.targetitem))
			approved_targets += possible_item
	return set_target(safepick(possible_items))

datum/objective/steal/proc/set_target(var/datum/objective_item/item)
	if(item)
		targetinfo = item

		steal_target = targetinfo.targetitem
		explanation_text = "Steal [targetinfo.name]."
		dangerrating = targetinfo.difficulty
		return steal_target
	else
		explanation_text = "Free objective"
		return

datum/objective/steal/proc/select_target() //For admins setting objectives manually.
	var/list/possible_items_all = possible_items+"custom"
	var/new_target = input("Select target:", "Objective target", steal_target) as null|anything in possible_items_all
	if (!new_target) return

	if (new_target == "custom") //Can set custom items.
		var/obj/item/custom_target = input("Select type:","Type") as null|anything in typesof(/obj/item)
		if (!custom_target) return
		var/tmp_obj = new custom_target
		var/custom_name = tmp_obj:name
		qdel(tmp_obj)
		custom_name = stripped_input("Enter target name:", "Objective target", custom_name)
		if (!custom_name) return
		steal_target = custom_target
		explanation_text = "Steal [custom_name]."

	else
		set_target(new_target)
	return steal_target

datum/objective/steal/check_completion()
	if(!steal_target)	return 1
	if(!isliving(owner.current))	return 0
	var/list/all_items = owner.current.GetAllContents()	//this should get things in cheesewheels, books, etc.

	for(var/obj/I in all_items) //Check for items
		if(istype(I, steal_target))
			if(targetinfo && targetinfo.check_special_completion(I))//Returns 1 by default. Items with special checks will return 1 if the conditions are fulfilled.
				return 1
			else //If there's no targetinfo, then that means it was a custom objective. At this point, we know you have the item, so return 1.
				return 1

		if(targetinfo && I.type in targetinfo.altitems) //Ok, so you don't have the item. Do you have an alternative, at least?
			if(targetinfo.check_special_completion(I))//Yeah, we do! Don't return 0 if we don't though - then you could fail if you had 1 item that didn't pass and got checked first!
				return 1
	return 0

var/global/list/possible_items_special = list()
datum/objective/steal/special //ninjas are so special they get their own subtype good for them

datum/objective/steal/special/New()
	..()
	if(!possible_items_special.len)
		init_subtypes(/datum/objective_item/special,possible_items)
		init_subtypes(/datum/objective_item/stack,possible_items)

datum/objective/steal/special/find_target()
	return set_target(pick(possible_items_special))

datum/objective/steal/exchange
	dangerrating = 10

datum/objective/steal/exchange/proc/set_faction(var/faction,var/otheragent)
	target = otheragent
	if(faction == "red")
		targetinfo = new/datum/objective_item/unique/docs_blue
	else if(faction == "blue")
		targetinfo = new/datum/objective_item/unique/docs_red
	explanation_text = "Acquire [targetinfo.name] held by [target.current.real_name], the [target.assigned_role] and syndicate agent"
	steal_target = targetinfo.targetitem

datum/objective/steal/exchange/update_explanation_text()
	..()
	if(target && target.current)
		explanation_text = "Acquire [targetinfo.name] held by [target.name], the [target.assigned_role] and syndicate agent"
	else
		explanation_text = "Free Objective"

datum/objective/steal/exchange/backstab
	dangerrating = 3

datum/objective/steal/exchange/backstab/set_faction(var/faction)
	if(faction == "red")
		targetinfo = new/datum/objective_item/unique/docs_red
	else if(faction == "blue")
		targetinfo = new/datum/objective_item/unique/docs_blue
	explanation_text = "Do not give up or lose [targetinfo.name]."
	steal_target = targetinfo.targetitem

datum/objective/download
	dangerrating = 10

datum/objective/download/proc/gen_amount_goal()
	target_amount = rand(10,20)
	explanation_text = "Download [target_amount] research level\s."
	return target_amount

datum/objective/download/check_completion()//NINJACODE
	if(!ishuman(owner.current))
		return 0

	var/mob/living/carbon/human/H = owner.current
	if(!H || H.stat == DEAD)
		return 0

	if(!istype(H.wear_suit, /obj/item/clothing/suit/space/space_ninja))
		return 0

	var/obj/item/clothing/suit/space/space_ninja/SN = H.wear_suit
	if(!SN.s_initialized)
		return 0

	var/current_amount
	if(!SN.stored_research.len)
		return 0
	else
		for(var/datum/tech/current_data in SN.stored_research)
			if(current_data.level)
				current_amount += (current_data.level-1)
	if(current_amount<target_amount)
		return 0
	return 1

datum/objective/capture
	dangerrating = 10

datum/objective/capture/proc/gen_amount_goal()
		target_amount = rand(5,10)
		explanation_text = "Accumulate [target_amount] capture point\s. It is better if they remain relatively unharmed."
		return target_amount

datum/objective/capture/check_completion()//Basically runs through all the mobs in the area to determine how much they are worth.
	var/captured_amount = 0
	var/area/centcom/holding/A = locate()
	for(var/mob/living/carbon/human/M in A)//Humans.
		if(M.stat==2)//Dead folks are worth less.
			captured_amount+=0.5
			continue
		captured_amount+=1
	for(var/mob/living/carbon/monkey/M in A)//Monkeys are almost worthless, you failure.
		captured_amount+=0.1
	for(var/mob/living/carbon/alien/larva/M in A)//Larva are important for research.
		if(M.stat==2)
			captured_amount+=0.5
			continue
		captured_amount+=1
	for(var/mob/living/carbon/alien/humanoid/M in A)//Aliens are worth twice as much as humans.
		if(istype(M, /mob/living/carbon/alien/humanoid/queen))//Queens are worth three times as much as humans.
			if(M.stat==2)
				captured_amount+=1.5
			else
				captured_amount+=3
			continue
		if(M.stat==2)
			captured_amount+=1
			continue
		captured_amount+=2
	if(captured_amount<target_amount)
		return 0
	return 1

datum/objective/absorb
	dangerrating = 10

datum/objective/absorb/proc/gen_amount_goal(var/lowbound = 4, var/highbound = 6)
	target_amount = rand (lowbound,highbound)
	if (ticker)
		var/n_p = 1 //autowin
		if (ticker.current_state == GAME_STATE_SETTING_UP)
			for(var/mob/new_player/P in player_list)
				if(P.client && P.ready && P.mind!=owner)
					n_p ++
		else if (ticker.current_state == GAME_STATE_PLAYING)
			for(var/mob/living/carbon/human/P in player_list)
				if(P.client && !(P.mind in ticker.mode.changelings) && P.mind!=owner)
					n_p ++
		target_amount = min(target_amount, n_p)

	explanation_text = "Extract [target_amount] compatible genome\s."
	return target_amount

datum/objective/absorb/check_completion()
	if(owner && owner.changeling && owner.changeling.absorbed_dna && (owner.changeling.absorbedcount >= target_amount))
		return 1
	else
		return 0

datum/objective/destroy
	dangerrating = 10

datum/objective/destroy/find_target()
	var/list/possible_targets = active_ais(1)
	var/mob/living/silicon/ai/target_ai = pick(possible_targets)
	target = target_ai.mind
	update_explanation_text()
	return target

datum/objective/destroy/check_completion()
	if(target && target.current)
		if(target.current.stat == DEAD || target.current.z > 6 || !target.current.ckey || ismommi(target)) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
			return 1
		return 0
	return 1

datum/objective/destroy/update_explanation_text()
	..()
	if(target && target.current)
		explanation_text = "Destroy [target.name], the experimental AI."
	else
		explanation_text = "Free Objective"

datum/objective/multiply
	explanation_text = "Procreate, and protect your spawn."
	var/already_completed=0
	check_completion()
		if(already_completed)
			return 1
		if(!owner.current)
			return 0
		var/mob/living/simple_animal/borer/B=owner.current
		if(!istype(B))
			return 0
		if(B.numChildren>0)
			already_completed=1
			return 1
		return 0