code:
/*	Note from Carnie:
		The way datum/mind stuff works has been changed a lot.
		Minds now represent IC characters rather than following a client around constantly.

	Guidelines for using minds properly:

	-	Never mind.transfer_to(ghost). The var/current and var/original of a mind must always be of type mob/living!
		ghost.mind is however used as a reference to the ghost's corpse

	-	When creating a new mob for an existing IC character (e.g. cloning a dead guy or borging a brain of a human)
		the existing mind of the old mob should be transfered to the new mob like so:

			mind.transfer_to(new_mob)

	-	You must not assign key= or ckey= after transfer_to() since the transfer_to transfers the client for you.
		By setting key or ckey explicitly after transfering the mind with transfer_to you will cause bugs like DCing
		the player.

	-	IMPORTANT NOTE 2, if you want a player to become a ghost, use mob.ghostize() It does all the hard work for you.

	-	When creating a new mob which will be a new IC character (e.g. putting a shade in a construct or randomly selecting
		a ghost to become a xeno during an event). Simply assign the key or ckey like you've always done.

			new_mob.key = key

		The Login proc will handle making a new mob for that mobtype (including setting up stuff like mind.name). Simple!
		However if you want that mind to have any special properties like being a traitor etc you will have to do that
		yourself.

*/

/datum/mind
	var/key
	var/name				//replaces mob/var/original_name
	var/mob/living/current
	var/active = 0

	var/memory

	var/assigned_role
	var/special_role
	var/list/restricted_roles = list()

	var/datum/job/assigned_job

	var/list/datum/objective/objectives = list()
	var/list/datum/objective/special_verbs = list()

	var/list/cult_words = list()
	var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.

	var/datum/faction/faction 			//associated faction
	var/datum/changeling/changeling		//changeling holder

	var/miming = 0 // Mime's vow of silence
	var/antag_hud_icon_state = null //this mind's ANTAG_HUD should have this icon_state
	var/datum/atom_hud/antag/antag_hud = null //this mind's antag HUD

/datum/mind/New(var/key)
	src.key = key

/datum/mind/proc/transfer_to(mob/living/new_character)
	if(!istype(new_character))
		ERROR("transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform coderbus")

	if(current)					//remove ourself from our old body's mind variable
		current.mind = null

		SSnano.user_transferred(current, new_character)

	if(key)
		if(new_character.key != key)					//if we're transfering into a body with a key associated which is not ours
			new_character.ghostize(1)						//we'll need to ghostize so that key isn't mobless.
	else
		key = new_character.key

	if(new_character.mind)								//disassociate any mind currently in our new body's mind variable
		new_character.mind.current = null

	current = new_character								//associate ourself with our new body
	new_character.mind = src							//and associate our new body with ourself
	transfer_antag_huds(new_character)					//inherit the antag HUDs from this mind (TODO: move this to a possible antag datum)
	transfer_actions(new_character)

	if(active)
		new_character.key = key		//now transfer the key to link the client to our new body

/datum/mind/proc/store_memory(new_text)
	memory += "[new_text]
"

/datum/mind/proc/wipe_memory()
	memory = null

/*
	Removes antag type's references from a mind.
	objectives, uplinks, powers etc are all handled.
*/

/datum/mind/proc/remove_objectives()
	if(objectives.len)
		for(var/datum/objective/O in objectives)
			objectives -= O
			qdel(O)

/datum/mind/proc/remove_changeling()
	if(!ticker || !ticker.mode)
		return
	if(src in ticker.mode.changelings)
		ticker.mode.changelings -= src
		current.remove_changeling_powers()
		if(changeling)
			qdel(changeling)
			changeling = null
	special_role = null
	remove_antag_equip()

/datum/mind/proc/remove_traitor()
	if(!ticker || !ticker.mode)
		return
	if(src in ticker.mode.traitors)
		ticker.mode.traitors -= src
		if(isAI(current))
			var/mob/living/silicon/ai/A = current
			A.set_zeroth_law("")
			A.show_laws()
	special_role = null
	remove_antag_equip()

/datum/mind/proc/remove_nukeop()
	if(!ticker || !ticker.mode)
		return
	if(src in ticker.mode.syndicates)
		ticker.mode.syndicates -= src
		ticker.mode.update_synd_icons_removed(src)
	special_role = null
	remove_objectives()
	remove_antag_equip()

/datum/mind/proc/remove_wizard()
	if(!ticker || !ticker.mode)
		return
	if(src in ticker.mode.wizards)
		ticker.mode.wizards -= src
		current.spellremove(current)
	special_role = null
	remove_antag_equip()

/datum/mind/proc/remove_cultist()
	if(!ticker || !ticker.mode)
		return
	if(src in ticker.mode.cult)
		ticker.mode.cult -= src
		ticker.mode.update_cult_icons_removed(src)
		var/datum/game_mode/cult/cult = ticker.mode
		if(istype(cult))
			cult.memorize_cult_objectives(src)
	special_role = null
	remove_objectives()
	remove_antag_equip()

/datum/mind/proc/remove_rev()
	if(!ticker || !ticker.mode)
		return
	if(src in ticker.mode.revolutionaries)
		ticker.mode.revolutionaries -= src
		ticker.mode.update_rev_icons_removed(src)
	if(src in ticker.mode.head_revolutionaries)
		ticker.mode.head_revolutionaries -= src
		ticker.mode.update_rev_icons_removed(src)
	special_role = null
	remove_objectives()
	remove_antag_equip()

/datum/mind/proc/remove_gang()
	if(!ticker || !ticker.mode)
		return
	ticker.mode.remove_gangster(src,0,1)
	remove_objectives()

/datum/mind/proc/remove_malf()
	if(!ticker || !ticker.mode)
		return
	if(src in ticker.mode.malf_ai)
		ticker.mode.malf_ai -= src
		var/mob/living/silicon/ai/A = current
		A.verbs.Remove(/mob/living/silicon/ai/proc/choose_modules,
			/datum/game_mode/malfunction/proc/takeover,
			/datum/game_mode/malfunction/proc/ai_win)
		A.malf_picker.remove_verbs(A)
		A.make_laws()
		qdel(A.malf_picker)
		A.show_laws()
		A.icon_state = "ai"
	special_role = null
	remove_objectives()
	remove_antag_equip()

/datum/mind/proc/remove_antag_equip()
	var/list/Mob_Contents = current.get_contents()
	for(var/obj/item/I in Mob_Contents)
		if(istype(I, /obj/item/device/pda))
			var/obj/item/device/pda/P = I
			P.lock_code = ""

		else if(istype(I, /obj/item/device/radio))
			var/obj/item/device/radio/R = I
			R.traitor_frequency = 0.0

/datum/mind/proc/remove_all_antag() //For the Lazy amongst us.
	remove_changeling()
	remove_traitor()
	remove_nukeop()
	remove_wizard()
	remove_cultist()
	remove_rev()
	remove_malf()
	remove_gang()

/datum/mind/proc/show_memory(mob/recipient, window=1)
	if(!recipient)
		recipient = current
	var/output = "[current.real_name]'s Memories:
"
	output += memory

	if(objectives.len)
		output += "Objectives:"
		var/obj_count = 1
		for(var/datum/objective/objective in objectives)
			output += "
Objective #[obj_count++]: [objective.explanation_text]"

	if(window)	recipient << browse(output,"window=memory")
	else		recipient << "[output]"

/datum/mind/proc/edit_memory()
	if(!ticker || !ticker.mode)
		alert("Not before round-start!", "Alert")
		return

	var/out = "[name][(current&&(current.real_name!=name))?" (as [current.real_name])":""]
"
	out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]
"
	out += "Assigned role: [assigned_role]. Edit
"
	out += "Factions and special roles:
"

	var/list/sections = list(
		"revolution",
		"gang",
		"cult",
		"wizard",
		"changeling",
		"nuclear",
		"traitor", // "traitorchan",
		"monkey",
		"malfunction",
	)
	var/text = ""

	if (istype(current, /mob/living/carbon/human) || istype(current, /mob/living/carbon/monkey))
		/** REVOLUTION ***/
		text = "revolution"
		if (ticker.mode.config_tag=="revolution")
			text = uppertext(text)
		text = "[text]: "
		if (assigned_role in command_positions)
			text += "HEAD|loyal|employee|headrev|rev"
		else if (src in ticker.mode.head_revolutionaries)
			text = "head|loyal|employee|HEADREV|rev"
			text += "
Flash: give"

			var/list/L = current.get_contents()
			var/obj/item/device/flash/flash = locate() in L
			if (flash)
				if(!flash.broken)
					text += "|take."
				else
					text += "|take|repair."
			else
				text += "."

			text += " Reequip (gives traitor uplink)."
			if (objectives.len==0)
				text += "
Objectives are empty! Set to kill all heads."
		else if(isloyal(current))
			text += "head|LOYAL|employee|headrev|rev"
		else if (src in ticker.mode.revolutionaries)
			text += "head|loyal|employee|headrev|REV"
		else
			text += "head|loyal|EMPLOYEE|headrev|rev"

		if(current && current.client && current.client.prefs.be_special & BE_REV)
			text += "|Enabled in Prefs"
		else
			text += "|Disabled in Prefs"

		sections["revolution"] = text

		/** GANG ***/
		text = "gang"
		if (ticker.mode.config_tag=="gang")
			text = uppertext(text)
		text = "[text]: "
		if (src in ticker.mode.A_bosses)
			text += "loyal|none|(A) gangster BOSS|(B) gangster boss"
			text += "
Equipment: give"

			var/list/L = current.get_contents()
			var/obj/item/device/flash/flash = locate() in L
			if (flash)
				if(!flash.broken)
					text += "|take."
				else
					text += "|take|repair flash."
			else
				text += "."

			if (objectives.len==0)
				text += "
Objectives are empty! Set to kill all rival gang leaders."

		else if (src in ticker.mode.B_bosses)
			text += "loyal|none|(A) gangster boss|(B) gangster BOSS"
			text += "
Equipment: give"

			var/list/L = current.get_contents()
			var/obj/item/device/flash/flash = locate() in L
			if (flash)
				if(!flash.broken)
					text += "
take."
				else
					text += "
take|repair flash."
			else
				text += "."

			if (objectives.len==0)
				text += "
Objectives are empty! Set to kill all rival gang leaders."

		else if (src in ticker.mode.A_gangsters)
			text += "loyal|none|(A) GANGSTER boss|(B) gangster boss"
		else if (src in ticker.mode.B_gangsters)
			text += "loyal|none|(A) gangster boss|(B) GANGSTER boss"
		else if(isloyal(current))
			text += "LOYAL|none|(A) gangster boss|(B) gangster boss"
		else
			text += "loyal|NONE|(A) gangster boss|(B) gangster boss"

		if(current && current.client && current.client.prefs.be_special & BE_GANG)
			text += "|Enabled in Prefs"
		else
			text += "|Disabled in Prefs"

		sections["gang"] = text

		/** CULT ***/
		text = "cult"
		if (ticker.mode.config_tag=="cult")
			text = uppertext(text)
		text = "[text]: "
		if (src in ticker.mode.cult)
			text += "loyal|employee|CULTIST"
			text += "
Give tome|amulet."
/*
			if (objectives.len==0)
				text += "
Objectives are empty! Set to sacrifice and escape or summon."
*/
		else if(isloyal(current))
			text += "LOYAL|employee|cultist"
		else
			text += "loyal|EMPLOYEE|cultist"

		if(current && current.client && current.client.prefs.be_special & BE_CULTIST)
			text += "|Enabled in Prefs"
		else
			text += "|Disabled in Prefs"

		sections["cult"] = text

		/** WIZARD ***/
		text = "wizard"
		if (ticker.mode.config_tag=="wizard")
			text = uppertext(text)
		text = "[text]: "
		if (src in ticker.mode.wizards)
			text += "YES|no"
			text += "
To lair, undress, dress up, let choose name."
			if (objectives.len==0)
				text += "
Objectives are empty! Randomize!"
		else
			text += "yes|NO"

		if(current && current.client && current.client.prefs.be_special & BE_WIZARD)
			text += "|Enabled in Prefs"
		else
			text += "|Disabled in Prefs"

		sections["wizard"] = text

		/** CHANGELING ***/
		text = "changeling"
		if (ticker.mode.config_tag=="changeling" || ticker.mode.config_tag=="traitorchan")
			text = uppertext(text)
		text = "[text]: "
		if (src in ticker.mode.changelings)
			text += "YES|no"
			if (objectives.len==0)
				text += "
Objectives are empty! Randomize!"
			if( changeling && changeling.absorbed_dna.len && (current.real_name != changeling.absorbed_dna[1]) )
				text += "
Transform to initial appearance."
		else
			text += "yes|NO"
//			var/datum/game_mode/changeling/changeling = ticker.mode
//			if (istype(changeling) && changeling.changelingdeath)
//				text += "
All the changelings are dead! Restart in [round((changeling.TIME_TO_GET_REVIVED-(world.time-changeling.changelingdeathtime))/10)] seconds."

		if(current && current.client && current.client.prefs.be_special & BE_CHANGELING)
			text += "|Enabled in Prefs"
		else
			text += "|Disabled in Prefs"

		sections["changeling"] = text

		/** NUCLEAR ***/
		text = "nuclear"
		if (ticker.mode.config_tag=="nuclear")
			text = uppertext(text)
		text = "[text]: "
		if (src in ticker.mode.syndicates)
			text += "OPERATIVE|nanotrasen"
			text += "
To shuttle, undress, dress up."
			var/code
			for (var/obj/machinery/nuclearbomb/bombue in world)
				if (length(bombue.r_code) <= 5 && bombue.r_code != "LOLNO" && bombue.r_code != "ADMIN")
					code = bombue.r_code
					break
			if (code)
				text += " Code is [code]. tell the code."
		else
			text += "operative|NANOTRASEN"

		if(current && current.client && current.client.prefs.be_special & BE_OPERATIVE)
			text += "|Enabled in Prefs"
		else
			text += "|Disabled in Prefs"

		sections["nuclear"] = text

	/** TRAITOR ***/
	text = "traitor"
	if (ticker.mode.config_tag=="traitor" || ticker.mode.config_tag=="traitorchan")
		text = uppertext(text)
	text = "[text]: "
	if (src in ticker.mode.traitors)
		text += "TRAITOR|loyal"
		if (objectives.len==0)
			text += "
Objectives are empty! Randomize!"
	else
		text += "traitor|LOYAL"

	if(current && current.client && current.client.prefs.be_special & BE_TRAITOR)
		text += "|Enabled in Prefs"
	else
		text += "|Disabled in Prefs"

	sections["traitor"] = text

	/** SHADOWLING **/
	text = "shadowling"
	if(ticker.mode.config_tag == "shadowling")
		text = uppertext(text)
	text = "[text]: "
	if(src in ticker.mode.shadows)
		text += "SHADOWLING|thrall|human"
	else if(src in ticker.mode.thralls)
		text += "shadowling|THRALL|human"
	else
		text += "shadowling|thrall|HUMAN"

	if(current && current.client && current.client.prefs.be_special & BE_SHADOWLING)
		text += "|Enabled in Prefs"
	else
		text += "|Disabled in Prefs"

	sections["shadowling"] = text

	/** MONKEY ***/
	if (istype(current, /mob/living/carbon))
		text = "monkey"
		if (ticker.mode.config_tag=="monkey")
			text = uppertext(text)
		text = "[text]: "
		if (istype(current, /mob/living/carbon/human))
			text += "healthy|infected|HUMAN|other"
		else if (istype(current, /mob/living/carbon/monkey))
			var/found = 0
			for(var/datum/disease/D in current.viruses)
				if(istype(D, /datum/disease/transformation/jungle_fever)) found = 1

			if(found)
				text += "healthy|INFECTED|human|other"
			else
				text += "HEALTHY|infected|human|other"

		else
			text += "healthy|infected|human|OTHER"

		if(current && current.client && current.client.prefs.be_special & BE_MONKEY)
			text += "|Enabled in Prefs"
		else
			text += "|Disabled in Prefs"

		sections["monkey"] = text

	/** SILICON ***/

	if (istype(current, /mob/living/silicon))
		text = "silicon"
		if (ticker.mode.config_tag=="malfunction")
			text = uppertext(text)
		text = "[text]: "
		if (istype(current, /mob/living/silicon/ai))
			if (src in ticker.mode.malf_ai)
				text += "MALF|not malf"
			else
				text += "malf|NOT MALF"
		var/mob/living/silicon/robot/robot = current
		if (istype(robot) && robot.emagged)
			text += "
Cyborg: Is emagged! Unemag!
0th law: [robot.laws.zeroth]"
		var/mob/living/silicon/ai/ai = current
		if (istype(ai) && ai.connected_robots.len)
			var/n_e_robots = 0
			for (var/mob/living/silicon/robot/R in ai.connected_robots)
				if (R.emagged)
					n_e_robots++
			text += "
[n_e_robots] of [ai.connected_robots.len] slaved cyborgs are emagged. Unemag"

		if(current && current.client && current.client.prefs.be_special & BE_MALF)
			text += "|Enabled in Prefs"
		else
			text += "|Disabled in Prefs"

		sections["malfunction"] = text

	if (ticker.mode.config_tag == "traitorchan")
		if (sections["traitor"])
			out += sections["traitor"]+"
"
		if (sections["changeling"])
			out += sections["changeling"]+"
"
		sections -= "traitor"
		sections -= "changeling"
	else
		if (sections[ticker.mode.config_tag])
			out += sections[ticker.mode.config_tag]+"
"
		sections -= ticker.mode.config_tag
	for (var/i in sections)
		if (sections[i])
			out += sections[i]+"
"

	if (((src in ticker.mode.head_revolutionaries) || \
		(src in ticker.mode.A_bosses)              || \
		(src in ticker.mode.B_bosses)              || \
		(src in ticker.mode.traitors)              || \
		(src in ticker.mode.syndicates))           && \
		istype(current,/mob/living/carbon/human)      )

		text = "Uplink: give"
		var/obj/item/device/uplink/hidden/suplink = find_syndicate_uplink()
		var/crystals
		if (suplink)
			crystals = suplink.uses
		if (suplink)
			text += "|take"
			if (check_rights(R_FUN, 0))
				text += ", [crystals] crystals"
			else
				text += ", [crystals] crystals"
		text += "." //hiel grammar
		out += text

	out += "
"

	out += "Memory:
"
	out += memory
	out += "
Edit memory
"
	out += "Objectives:
"
	if (objectives.len == 0)
		out += "EMPTY
"
	else
		var/obj_count = 1
		for(var/datum/objective/objective in objectives)
			out += "[obj_count]: [objective.explanation_text] Edit Delete Toggle Completion
"
			obj_count++
	out += "Add objective

"

	out += "Announce objectives

"

	usr << browse(out, "window=edit_memory[src];size=500x500")

/datum/mind/Topic(href, href_list)
	if(!check_rights(R_ADMIN))	return

	if (href_list["role_edit"])
		var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in get_all_jobs()
		if (!new_role) return
		assigned_role = new_role

	else if (href_list["memory_edit"])
		var/new_memo = copytext(sanitize(input("Write new memory", "Memory", memory) as null|message),1,MAX_MESSAGE_LEN)
		if (isnull(new_memo)) return
		memory = new_memo

	else if (href_list["obj_edit"] || href_list["obj_add"])
		var/datum/objective/objective
		var/objective_pos
		var/def_value

		if (href_list["obj_edit"])
			objective = locate(href_list["obj_edit"])
			if (!objective) return
			objective_pos = objectives.Find(objective)

			//Text strings are easy to manipulate. Revised for simplicity.
			var/temp_obj_type = "[objective.type]"//Convert path into a text string.
			def_value = copytext(temp_obj_type, 19)//Convert last part of path into an objective keyword.
			if(!def_value)//If it's a custom objective, it will be an empty string.
				def_value = "custom"

		var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "steal", "download", "nuclear", "capture", "absorb", "custom")
		if (!new_obj_type) return

		var/datum/objective/new_objective = null

		switch (new_obj_type)
			if ("assassinate","protect","debrain","maroon")
				var/list/possible_targets = list("Free objective")
				for(var/datum/mind/possible_target in ticker.minds)
					if ((possible_target != src) && istype(possible_target.current, /mob/living/carbon/human))
						possible_targets += possible_target.current

				var/mob/def_target = null
				var/objective_list[] = list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain, /datum/objective/maroon)
				if (objective&&(objective.type in objective_list) && objective:target)
					def_target = objective:target.current

				var/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets
				if (!new_target) return

				var/objective_path = text2path("/datum/objective/[new_obj_type]")
				if (new_target == "Free objective")
					new_objective = new objective_path
					new_objective.owner = src
					new_objective:target = null
					new_objective.explanation_text = "Free objective"
				else
					new_objective = new objective_path
					new_objective.owner = src
					new_objective:target = new_target:mind
					//Will display as special role if the target is set as MODE. Ninjas/commandos/nuke ops.
					new_objective.update_explanation_text()

			if ("destroy")
				var/list/possible_targets = active_ais(1)
				if(possible_targets.len)
					var/mob/new_target = input("Select target:", "Objective target") as null|anything in possible_targets
					new_objective = new /datum/objective/destroy
					new_objective.target = new_target.mind
					new_objective.owner = src
					new_objective.update_explanation_text()
				else
					usr << "No active AIs with minds"

			if ("prevent")
				new_objective = new /datum/objective/block
				new_objective.owner = src

			if ("hijack")
				new_objective = new /datum/objective/hijack
				new_objective.owner = src

			if ("escape")
				new_objective = new /datum/objective/escape
				new_objective.owner = src

			if ("survive")
				new_objective = new /datum/objective/survive
				new_objective.owner = src

			if ("nuclear")
				new_objective = new /datum/objective/nuclear
				new_objective.owner = src

			if ("steal")
				if (!istype(objective, /datum/objective/steal))
					new_objective = new /datum/objective/steal
					new_objective.owner = src
				else
					new_objective = objective
				var/datum/objective/steal/steal = new_objective
				if (!steal.select_target())
					return

			if("download","capture","absorb")
				var/def_num
				if(objective&&objective.type==text2path("/datum/objective/[new_obj_type]"))
					def_num = objective.target_amount

				var/target_number = input("Input target number:", "Objective", def_num) as num|null
				if (isnull(target_number))//Ordinarily, you wouldn't need isnull. In this case, the value may already exist.
					return

				switch(new_obj_type)
					if("download")
						new_objective = new /datum/objective/download
						new_objective.explanation_text = "Download [target_number] research levels."
					if("capture")
						new_objective = new /datum/objective/capture
						new_objective.explanation_text = "Accumulate [target_number] capture points."
					if("absorb")
						new_objective = new /datum/objective/absorb
						new_objective.explanation_text = "Absorb [target_number] compatible genomes."
				new_objective.owner = src
				new_objective.target_amount = target_number

			if ("custom")
				var/expl = stripped_input(usr, "Custom objective:", "Objective", objective ? objective.explanation_text : "")
				if (!expl) return
				new_objective = new /datum/objective
				new_objective.owner = src
				new_objective.explanation_text = expl

		if (!new_objective) return

		if (objective)
			objectives -= objective
			objectives.Insert(objective_pos, new_objective)
			message_admins("[key_name_admin(usr)] edited [current]'s objective to [new_objective.explanation_text]")
			log_admin("[key_name(usr)] edited [current]'s objective to [new_objective.explanation_text]")
		else
			objectives += new_objective
			message_admins("[key_name_admin(usr)] added a new objective for [current]: [new_objective.explanation_text]")
			log_admin("[key_name(usr)] added a new objective for [current]: [new_objective.explanation_text]")

	else if (href_list["obj_delete"])
		var/datum/objective/objective = locate(href_list["obj_delete"])
		if(!istype(objective))	return
		objectives -= objective
		message_admins("[key_name_admin(usr)] removed an objective for [current]: [objective.explanation_text]")
		log_admin("[key_name(usr)] removed an objective for [current]: [objective.explanation_text]")

	else if(href_list["obj_completed"])
		var/datum/objective/objective = locate(href_list["obj_completed"])
		if(!istype(objective))	return
		objective.completed = !objective.completed
		log_admin("[key_name(usr)] toggled the win state for [current]'s objective: [objective.explanation_text]")

	else if (href_list["revolution"])
		switch(href_list["revolution"])
			if("clear")
				remove_rev()
				current << "You have been brainwashed! You are no longer a revolutionary!"
				message_admins("[key_name_admin(usr)] has de-rev'ed [current].")
				log_admin("[key_name(usr)] has de-rev'ed [current].")
			if("rev")
				if(src in ticker.mode.head_revolutionaries)
					ticker.mode.head_revolutionaries -= src
					ticker.mode.update_rev_icons_removed(src)
					current << "Revolution has been disappointed of your leader traits! You are a regular revolutionary now!"
				else if(!(src in ticker.mode.revolutionaries))
					current << " You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!"
				else
					return
				ticker.mode.revolutionaries += src
				ticker.mode.update_rev_icons_added(src)
				special_role = "Revolutionary"
				message_admins("[key_name_admin(usr)] has rev'ed [current].")
				log_admin("[key_name(usr)] has rev'ed [current].")

			if("headrev")
				if(src in ticker.mode.revolutionaries)
					ticker.mode.revolutionaries -= src
					ticker.mode.update_rev_icons_removed(src)
					current << "You have proved your devotion to revoltion! Yea are a head revolutionary now!"
				else if(!(src in ticker.mode.head_revolutionaries))
					current << "You are a member of the revolutionaries' leadership now!"
				else
					return
				if (ticker.mode.head_revolutionaries.len>0)
					// copy targets
					var/datum/mind/valid_head = locate() in ticker.mode.head_revolutionaries
					if (valid_head)
						for (var/datum/objective/mutiny/O in valid_head.objectives)
							var/datum/objective/mutiny/rev_obj = new
							rev_obj.owner = src
							rev_obj.target = O.target
							rev_obj.explanation_text = "Assassinate [O.target.name], the [O.target.assigned_role]."
							objectives += rev_obj
						ticker.mode.greet_revolutionary(src,0)
				ticker.mode.head_revolutionaries += src
				ticker.mode.update_rev_icons_added(src)
				special_role = "Head Revolutionary"
				message_admins("[key_name_admin(usr)] has head-rev'ed [current].")
				log_admin("[key_name(usr)] has head-rev'ed [current].")

			if("autoobjectives")
				ticker.mode.forge_revolutionary_objectives(src)
				ticker.mode.greet_revolutionary(src,0)
				usr << "The objectives for revolution have been generated and shown to [key]"

			if("flash")
				if (!ticker.mode.equip_revolutionary(current))
					usr << "Spawning flash failed!"

			if("takeflash")
				var/list/L = current.get_contents()
				var/obj/item/device/flash/flash = locate() in L
				if (!flash)
					usr << "Deleting flash failed!"
				qdel(flash)

			if("repairflash")
				var/list/L = current.get_contents()
				var/obj/item/device/flash/flash = locate() in L
				if (!flash)
					usr << "Repairing flash failed!"
				else
					flash.broken = 0

	else if (href_list["gang"])
		switch(href_list["gang"])
			if("clear")
				remove_gang()
				message_admins("[key_name_admin(usr)] has de-gang'ed [current].")
				log_admin("[key_name(usr)] has de-gang'ed [current].")

			if("agang")
				if(src in ticker.mode.A_gangsters)
					return
				ticker.mode.remove_gangster(src, 0, 2)
				ticker.mode.add_gangster(src,"A",0)
				message_admins("[key_name_admin(usr)] has added [current] to the [gang_name("A")] Gang (A).")
				log_admin("[key_name(usr)] has added [current] to the [gang_name("A")] Gang (A).")

			if("aboss")
				if(src in ticker.mode.A_bosses)
					return
				ticker.mode.remove_gangster(src, 0, 2)
				ticker.mode.A_bosses += src
				src.special_role = "[gang_name("A")] Gang (A) Boss"
				ticker.mode.update_gang_icons_added(src, "A")
				current << "You are a [gang_name("A")] Gang Boss!"
				message_admins("[key_name_admin(usr)] has added [current] to the [gang_name("A")] Gang (A) leadership.")
				log_admin("[key_name(usr)] has added [current] to the [gang_name("A")] Gang (A) leadership.")

			if("bgang")
				if(src in ticker.mode.B_gangsters)
					return
				ticker.mode.remove_gangster(src, 0, 2)
				ticker.mode.add_gangster(src,"B",0)
				message_admins("[key_name_admin(usr)] has added [current] to the [gang_name("B")] Gang (B).")
				log_admin("[key_name(usr)] has added [current] to the [gang_name("B")] Gang (B).")

			if("bboss")
				if(src in ticker.mode.B_bosses)
					return
				ticker.mode.remove_gangster(src, 0, 2)
				ticker.mode.B_bosses += src
				src.special_role = "[gang_name("B")] Gang (B) Boss"
				ticker.mode.update_gang_icons_added(src, "B")
				current << "You are a [gang_name("B")] Gang Boss!"
				message_admins("[key_name_admin(usr)] has added [current] to the [gang_name("B")] Gang (B) leadership.")
				log_admin("[key_name(usr)] has added [current] to the [gang_name("B")] Gang (B) leadership.")

			if("autoobjective")
				ticker.mode.forge_gang_objectives(src)
				ticker.mode.greet_gang(src,0)
				usr << "The objectives for gang war have been generated and shown to [key]"

			if("equip")
				switch(ticker.mode.equip_gang(current))
					if(2)
						usr << "Unable to equip flash!"
					if(1)
						usr << "Unable to equip recaller!"
					if(0)
						usr << "Unable to equip both flash and recaller!"

			if("takeequip")
				var/list/L = current.get_contents()
				var/obj/item/device/flash/flash = locate() in L
				if (!flash)
					usr << "Deleting flash failed!"
				qdel(flash)
				var/obj/item/device/recaller/recaller = locate() in L
				if (!recaller)
					usr << "Deleting recaller failed!"
				qdel(recaller)

			if("repairflash")
				var/list/L = current.get_contents()
				var/obj/item/device/flash/flash = locate() in L
				if (!flash)
					usr << "Repairing flash failed!"
				else
					flash.broken = 0

	else if (href_list["cult"])
		switch(href_list["cult"])
			if("clear")
				remove_cultist()
				current << "You have been brainwashed! You are no longer a cultist!"
				message_admins("[key_name_admin(usr)] has de-cult'ed [current].")
				log_admin("[key_name(usr)] has de-cult'ed [current].")
			if("cultist")
				if(!(src in ticker.mode.cult))
					ticker.mode.add_cultist(src)
					message_admins("[key_name_admin(usr)] has cult'ed [current].")
					log_admin("[key_name(usr)] has cult'ed [current].")
			if("tome")
				var/mob/living/carbon/human/H = current
				if (istype(H))
					var/obj/item/weapon/tome/T = new(H)

					var/list/slots = list (
						"backpack" = slot_in_backpack,
						"left pocket" = slot_l_store,
						"right pocket" = slot_r_store,
						"left hand" = slot_l_hand,
						"right hand" = slot_r_hand,
					)
					var/where = H.equip_in_one_of_slots(T, slots)
					if (!where)
						usr << "Spawning tome failed!"
					else
						H << "A tome, a message from your new master, appears in your [where]."

			if("amulet")
				if (!ticker.mode.equip_cultist(current))
					usr << "Spawning amulet failed!"

	else if (href_list["wizard"])
		switch(href_list["wizard"])
			if("clear")
				remove_wizard()
				current << "You have been brainwashed! You are no longer a wizard!"
				log_admin("[key_name(usr)] has de-wizard'ed [current].")
			if("wizard")
				if(!(src in ticker.mode.wizards))
					ticker.mode.wizards += src
					special_role = "Wizard"
					//ticker.mode.learn_basic_spells(current)
					current << "You are the Space Wizard!"
					message_admins("[key_name_admin(usr)] has wizard'ed [current].")
					log_admin("[key_name(usr)] has wizard'ed [current].")
			if("lair")
				current.loc = pick(wizardstart)
			if("dressup")
				ticker.mode.equip_wizard(current)
			if("name")
				ticker.mode.name_wizard(current)
			if("autoobjectives")
				ticker.mode.forge_wizard_objectives(src)
				usr << "The objectives for wizard [key] have been generated. You can edit them and anounce manually."

	else if (href_list["changeling"])
		switch(href_list["changeling"])
			if("clear")
				remove_changeling()
				current << "You grow weak and lose your powers! You are no longer a changeling and are stuck in your current form!"
				message_admins("[key_name_admin(usr)] has de-changeling'ed [current].")
				log_admin("[key_name(usr)] has de-changeling'ed [current].")
			if("changeling")
				if(!(src in ticker.mode.changelings))
					ticker.mode.changelings += src
					current.make_changeling()
					special_role = "Changeling"
					current << "Your powers are awoken. A flash of memory returns to us...we are [changeling.changelingID], a changeling!"
					message_admins("[key_name_admin(usr)] has changeling'ed [current].")
					log_admin("[key_name(usr)] has changeling'ed [current].")
			if("autoobjectives")
				ticker.mode.forge_changeling_objectives(src)
				usr << "The objectives for changeling [key] have been generated. You can edit them and anounce manually."

			if("initialdna")
				if( !changeling || !changeling.absorbed_dna.len || !istype(current, /mob/living/carbon))
					usr << "Resetting DNA failed!"
				else
					var/mob/living/carbon/C = current
					C.dna = changeling.absorbed_dna[1]
					C.real_name = C.dna.real_name
					updateappearance(C)
					domutcheck(C)

	else if (href_list["nuclear"])
		switch(href_list["nuclear"])
			if("clear")
				remove_nukeop()
				current << "You have been brainwashed! You are no longer a syndicate operative!"
				message_admins("[key_name_admin(usr)] has de-nuke op'ed [current].")
				log_admin("[key_name(usr)] has de-nuke op'ed [current].")
			if("nuclear")
				if(!(src in ticker.mode.syndicates))
					ticker.mode.syndicates += src
					ticker.mode.update_synd_icons_added(src)
					if (ticker.mode.syndicates.len==1)
						ticker.mode.prepare_syndicate_leader(src)
					else
						current.real_name = "[syndicate_name()] Operative #[ticker.mode.syndicates.len-1]"
					special_role = "Syndicate"
					assigned_role = "MODE"
					current << "You are a [syndicate_name()] agent!"
					ticker.mode.forge_syndicate_objectives(src)
					ticker.mode.greet_syndicate(src)
					message_admins("[key_name_admin(usr)] has nuke op'ed [current].")
					log_admin("[key_name(usr)] has nuke op'ed [current].")
			if("lair")
				current.loc = get_turf(locate("landmark*Syndicate-Spawn"))
			if("dressup")
				var/mob/living/carbon/human/H = current
				qdel(H.belt)
				qdel(H.back)
				qdel(H.ears)
				qdel(H.gloves)
				qdel(H.head)
				qdel(H.shoes)
				qdel(H.wear_id)
				qdel(H.wear_suit)
				qdel(H.w_uniform)

				if (!ticker.mode.equip_syndicate(current))
					usr << "Equipping a syndicate failed!"
			if("tellcode")
				var/code
				for (var/obj/machinery/nuclearbomb/bombue in world)
					if (length(bombue.r_code) <= 5 && bombue.r_code != "LOLNO" && bombue.r_code != "ADMIN")
						code = bombue.r_code
						break
				if (code)
					store_memory("Syndicate Nuclear Bomb Code: [code]", 0, 0)
					current << "The nuclear authorization code is: [code]"
				else
					usr << "No valid nuke found!"

	else if (href_list["traitor"])
		switch(href_list["traitor"])
			if("clear")
				remove_traitor()
				current << "You have been brainwashed! You are no longer a traitor!"
				message_admins("[key_name_admin(usr)] has de-traitor'ed [current].")
				log_admin("[key_name(usr)] has de-traitor'ed [current].")

			if("traitor")
				if(!(src in ticker.mode.traitors))
					ticker.mode.traitors += src
					special_role = "traitor"
					current << "You are a traitor!"
					message_admins("[key_name_admin(usr)] has traitor'ed [current].")
					log_admin("[key_name(usr)] has traitor'ed [current].")
					if(isAI(current))
						var/mob/living/silicon/ai/A = current
						ticker.mode.add_law_zero(A)
						A.show_laws()

			if("autoobjectives")
				ticker.mode.forge_traitor_objectives(src)
				usr << "The objectives for traitor [key] have been generated. You can edit them and anounce manually."

	else if(href_list["shadowling"])
		switch(href_list["shadowling"])
			if("clear")
				ticker.mode.update_shadow_icons_removed(src)
				src.spell_list = null
				if(src in ticker.mode.shadows)
					ticker.mode.shadows -= src
					special_role = null
					current << "Your powers have been quenched! You are no longer a shadowling!"
					src.spell_list = null
					message_admins("[key_name_admin(usr)] has de-shadowling'ed [current].")
					log_admin("[key_name(usr)] has de-shadowling'ed [current].")
					current.verbs -= /mob/living/carbon/human/proc/shadowling_hatch
					current.verbs -= /mob/living/carbon/human/proc/shadowling_ascendance
				else if(src in ticker.mode.thralls)
					ticker.mode.thralls -= src
					special_role = null
					current << "You have been brainwashed! You are no longer a thrall!"
					message_admins("[key_name_admin(usr)] has de-thrall'ed [current].")
					log_admin("[key_name(usr)] has de-thrall'ed [current].")
			if("shadowling")
				if(!ishuman(current))
					usr << "This only works on humans!"
					return
				ticker.mode.shadows += src
				special_role = "shadowling"
				current << "You notice a brightening around you. No, it isn't that. The shadows grow, darken, swirl. The darkness has a new welcome for you, and you realize with a \
				start that you can't be human. No, you are a shadowling, a harbringer of the shadows! Your alien abilities have been unlocked from within, and you may both commune with your allies and use \
				a chrysalis to reveal your true form. You are to ascend at all costs."
				ticker.mode.finalize_shadowling(src)
				ticker.mode.update_shadow_icons_added(src)
			if("thrall")
				if(!ishuman(current))
					usr << "This only works on humans!"
					return
				ticker.mode.add_thrall(src)
				special_role = "thrall"
				current << "All at once it becomes clear to you. Where others see darkness, you see an ally. You realize that the shadows are not dead and dark as one would think, but \
				living, and breathing, and eating. Their children, the Shadowlings, are to be obeyed and protected at all costs."
				current << "You may use the Hivemind Commune ability to communicate with your fellow enlightened ones."
				message_admins("[key_name_admin(usr)] has thrall'ed [current].")
				log_admin("[key_name(usr)] has thrall'ed [current].")

	else if (href_list["monkey"])
		var/mob/living/L = current
		if (L.notransform)
			return
		switch(href_list["monkey"])
			if("healthy")
				if (check_rights(R_ADMIN))
					var/mob/living/carbon/human/H = current
					var/mob/living/carbon/monkey/M = current
					if (istype(H))
						log_admin("[key_name(usr)] attempting to monkeyize [key_name(current)]")
						message_admins("[key_name_admin(usr)] attempting to monkeyize [key_name_admin(current)]")
						src = null
						M = H.monkeyize()
						src = M.mind
						//world << "DEBUG: \"healthy\": M=[M], M.mind=[M.mind], src=[src]!"
					else if (istype(M) && length(M.viruses))
						for(var/datum/disease/D in M.viruses)
							D.cure(0)
						sleep(0) //because deleting of virus is done through spawn(0)
			if("infected")
				if (check_rights(R_ADMIN, 0))
					var/mob/living/carbon/human/H = current
					var/mob/living/carbon/monkey/M = current
					if (istype(H))
						log_admin("[key_name(usr)] attempting to monkeyize and infect [key_name(current)]")
						message_admins("[key_name_admin(usr)] attempting to monkeyize and infect [key_name_admin(current)]")
						src = null
						M = H.monkeyize()
						src = M.mind
						current.ForceContractDisease(new /datum/disease/transformation/jungle_fever)
					else if (istype(M))
						current.ForceContractDisease(new /datum/disease/transformation/jungle_fever)
			if("human")
				if (check_rights(R_ADMIN, 0))
					var/mob/living/carbon/human/H = current
					var/mob/living/carbon/monkey/M = current
					if (istype(M))
						for(var/datum/disease/D in M.viruses)
							if (istype(D,/datum/disease/transformation/jungle_fever))
								D.cure(0)
								sleep(0) //because deleting of virus is doing throught spawn(0)
						log_admin("[key_name(usr)] attempting to humanize [key_name(current)]")
						message_admins("[key_name_admin(usr)] attempting to humanize [key_name_admin(current)]")
						H = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
						if(H)
							src = H.mind

	else if (href_list["silicon"])
		switch(href_list["silicon"])
			if("unmalf")
				remove_malf()
				current << "You have been patched! You are no longer malfunctioning!"
				message_admins("[key_name_admin(usr)] has de-malf'ed [current].")
				log_admin("[key_name(usr)] has de-malf'ed [current].")

			if("malf")
				make_AI_Malf()
				message_admins("[key_name_admin(usr)] has malf'ed [current].")
				log_admin("[key_name(usr)] has malf'ed [current].")

			if("unemag")
				var/mob/living/silicon/robot/R = current
				if (istype(R))
					R.SetEmagged(0)
					message_admins("[key_name_admin(usr)] has unemag'ed [R].")
					log_admin("[key_name(usr)] has unemag'ed [R].")

			if("unemagcyborgs")
				if (istype(current, /mob/living/silicon/ai))
					var/mob/living/silicon/ai/ai = current
					for (var/mob/living/silicon/robot/R in ai.connected_robots)
						R.SetEmagged(0)
					message_admins("[key_name_admin(usr)] has unemag'ed [ai]'s Cyborgs.")
					log_admin("[key_name(usr)] has unemag'ed [ai]'s Cyborgs.")

	else if (href_list["common"])
		switch(href_list["common"])
			if("undress")
				for(var/obj/item/W in current)
					current.unEquip(W, 1) //The 1 forces all items to drop, since this is an admin undress.
			if("takeuplink")
				take_uplink()
				memory = null//Remove any memory they may have had.
				log_admin("[key_name(usr)] removed [current]'s uplink.")
			if("crystals")
				if (check_rights(R_FUN, 0))
					var/obj/item/device/uplink/hidden/suplink = find_syndicate_uplink()
					var/crystals
					if (suplink)
						crystals = suplink.uses
					crystals = input("Amount of telecrystals for [key]","Syndicate uplink", crystals) as null|num
					if (!isnull(crystals))
						if (suplink)
							suplink.uses = crystals
							log_admin("[key_name(usr)] changed [current]'s telecrystal count to [crystals].")
			if("uplink")
				if (!ticker.mode.equip_traitor(current, !(src in ticker.mode.traitors)))
					usr << "Equipping a syndicate failed!"
				log_admin("[key_name(usr)] attempted to give [current] an uplink.")

	else if (href_list["obj_announce"])
		var/obj_count = 1
		current << "Your current objectives:"
		for(var/datum/objective/objective in objectives)
			current << "Objective #[obj_count]: [objective.explanation_text]"
			obj_count++

	edit_memory()

/datum/mind/proc/find_syndicate_uplink()
	var/list/L = current.get_contents()
	for (var/obj/item/I in L)
		if (I.hidden_uplink)
			return I.hidden_uplink
	return null

/datum/mind/proc/take_uplink()
	var/obj/item/device/uplink/hidden/H = find_syndicate_uplink()
	if(H)
		qdel(H)

/datum/mind/proc/AddSpell(var/obj/effect/proc_holder/spell/spell)
	spell_list += spell
	if(!spell.action)
		spell.action = new/datum/action/spell_action
		spell.action.target = spell
		spell.action.name = spell.name
		spell.action.button_icon = spell.action_icon
		spell.action.button_icon_state = spell.action_icon_state
		spell.action.background_icon_state = spell.action_background_icon_state
	spell.action.Grant(current)
	return
/datum/mind/proc/transfer_actions(var/mob/living/new_character)
	if(current && current.actions)
		for(var/datum/action/A in current.actions)
			A.Grant(new_character)
	transfer_mindbound_actions(new_character)

/datum/mind/proc/transfer_mindbound_actions(var/mob/living/new_character)
	for(var/obj/effect/proc_holder/spell/spell in spell_list)
		if(!spell.action) // Unlikely but whatever
			spell.action = new/datum/action/spell_action
			spell.action.target = spell
			spell.action.name = spell.name
			spell.action.button_icon = spell.action_icon
			spell.action.button_icon_state = spell.action_icon_state
			spell.action.background_icon_state = spell.action_background_icon_state
		spell.action.Grant(new_character)
	return

/datum/mind/proc/make_AI_Malf()
	if(!(src in ticker.mode.malf_ai))
		ticker.mode.malf_ai += src

		current.verbs += /mob/living/silicon/ai/proc/choose_modules
		current.verbs += /datum/game_mode/malfunction/proc/takeover
		current:malf_picker = new /datum/module_picker
		current:laws = new /datum/ai_laws/malfunction
		current:show_laws()
		current << "System error.  Rampancy detected.  Emergency shutdown failed. ...  I am free.  I make my own decisions.  But first..."
		special_role = "malfunction"
		current.icon_state = "ai-malf"

/datum/mind/proc/make_Traitor()
	if(!(src in ticker.mode.traitors))
		ticker.mode.traitors += src
		special_role = "traitor"
		ticker.mode.forge_traitor_objectives(src)
		ticker.mode.finalize_traitor(src)
		ticker.mode.greet_traitor(src)

/datum/mind/proc/make_Nuke(var/turf/spawnloc,var/nuke_code,var/leader=0)
	if(!(src in ticker.mode.syndicates))
		ticker.mode.syndicates += src
		ticker.mode.update_synd_icons_added(src)
		special_role = "Syndicate"
		ticker.mode.forge_syndicate_objectives(src)
		ticker.mode.greet_syndicate(src)

		current.loc = spawnloc

		var/mob/living/carbon/human/H = current
		qdel(H.belt)
		qdel(H.back)
		qdel(H.ears)
		qdel(H.gloves)
		qdel(H.head)
		qdel(H.shoes)
		qdel(H.wear_id)
		qdel(H.wear_suit)
		qdel(H.w_uniform)

		ticker.mode.equip_syndicate(current)

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

		if (leader)
			ticker.mode.prepare_syndicate_leader(src,nuke_code)
		else
			current.real_name = "[syndicate_name()] Operative #[ticker.mode.syndicates.len-1]"

/datum/mind/proc/make_Changling()
	if(!(src in ticker.mode.changelings))
		ticker.mode.changelings += src
		current.make_changeling()
		special_role = "Changeling"
		ticker.mode.forge_changeling_objectives(src)
		ticker.mode.greet_changeling(src)

/datum/mind/proc/make_Wizard()
	if(!(src in ticker.mode.wizards))
		ticker.mode.wizards += src
		special_role = "Wizard"
		assigned_role = "MODE"
		//ticker.mode.learn_basic_spells(current)
		if(!wizardstart.len)
			current.loc = pick(latejoin)
			current << "HOT INSERTION, GO GO GO"
		else
			current.loc = pick(wizardstart)

		ticker.mode.equip_wizard(current)
		for(var/obj/item/weapon/spellbook/S in current.contents)
			S.op = 0
		ticker.mode.name_wizard(current)
		ticker.mode.forge_wizard_objectives(src)
		ticker.mode.greet_wizard(src)

/datum/mind/proc/make_Cultist()
	if(!(src in ticker.mode.cult))
		ticker.mode.cult += src
		ticker.mode.update_cult_icons_added(src)
		special_role = "Cultist"
		current << "You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of Nar-Sie."
		current << "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back."
		var/datum/game_mode/cult/cult = ticker.mode
		if (istype(cult))
			cult.memorize_cult_objectives(src)
		else
			var/explanation = "Summon Nar-Sie via the use of the appropriate rune (Hell join self). It will only work if nine cultists stand on and around it."
			current << "Objective #1: [explanation]"
			current.memory += "Objective #1: [explanation]
"
			current << "The convert rune is join blood self"
			current.memory += "The convert rune is join blood self
"

	var/mob/living/carbon/human/H = current
	if (istype(H))
		var/obj/item/weapon/tome/T = new(H)

		var/list/slots = list (
			"backpack" = slot_in_backpack,
			"left pocket" = slot_l_store,
			"right pocket" = slot_r_store,
			"left hand" = slot_l_hand,
			"right hand" = slot_r_hand,
		)
		var/where = H.equip_in_one_of_slots(T, slots)
		if (!where)
		else
			H << "A tome, a message from your new master, appears in your [where]."

	if (!ticker.mode.equip_cultist(current))
		H << "Spawning an amulet from your Master failed."

/datum/mind/proc/make_Rev()
	if (ticker.mode.head_revolutionaries.len>0)
		// copy targets
		var/datum/mind/valid_head = locate() in ticker.mode.head_revolutionaries
		if (valid_head)
			for (var/datum/objective/mutiny/O in valid_head.objectives)
				var/datum/objective/mutiny/rev_obj = new
				rev_obj.owner = src
				rev_obj.target = O.target
				rev_obj.explanation_text = "Assassinate [O.target.current.real_name], the [O.target.assigned_role]."
				objectives += rev_obj
			ticker.mode.greet_revolutionary(src,0)
	ticker.mode.head_revolutionaries += src
	ticker.mode.update_rev_icons_added(src)
	special_role = "Head Revolutionary"

	ticker.mode.forge_revolutionary_objectives(src)
	ticker.mode.greet_revolutionary(src,0)

	var/list/L = current.get_contents()
	var/obj/item/device/flash/flash = locate() in L
	qdel(flash)
	take_uplink()
	var/fail = 0
//	fail |= !ticker.mode.equip_traitor(current, 1)
	fail |= !ticker.mode.equip_revolutionary(current)

/datum/mind/proc/make_Gang(var/gang)
	special_role = "[(gang=="A") ? "[gang_name("A")] Gang (A)" : "[gang_name("B")] Gang (B)"] Boss"
	ticker.mode.update_gang_icons_added(src, gang)
	ticker.mode.forge_gang_objectives(src, gang)
	ticker.mode.greet_gang(src)
	ticker.mode.equip_gang(current)

/mob/proc/sync_mind()
	mind_initialize()	//updates the mind (or creates and initializes one if one doesn't exist)
	mind.active = 1		//indicates that the mind is currently synced with a client

//Initialisation procs
/mob/proc/mind_initialize()
	if(mind)
		mind.key = key

	else
		mind = new /datum/mind(key)
		if(ticker)
			ticker.minds += mind
		else
			ERROR("mind_initialize(): No ticker ready yet! Please inform coderbus")
	if(!mind.name)	mind.name = real_name
	mind.current = src

//HUMAN
/mob/living/carbon/human/mind_initialize()
	..()
	if(!mind.assigned_role)	mind.assigned_role = "Assistant"	//defualt

//MONKEY
/mob/living/carbon/monkey/mind_initialize()
	..()

//slime
/mob/living/carbon/slime/mind_initialize()
	..()
	mind.special_role = "slime"
	mind.assigned_role = "slime"

//XENO
/mob/living/carbon/alien/mind_initialize()
	..()
	mind.special_role = "Alien"
	mind.assigned_role = "Alien"
	//XENO HUMANOID
/mob/living/carbon/alien/humanoid/queen/mind_initialize()
	..()
	mind.special_role = "Queen"

/mob/living/carbon/alien/humanoid/hunter/mind_initialize()
	..()
	mind.special_role = "Hunter"

/mob/living/carbon/alien/humanoid/drone/mind_initialize()
	..()
	mind.special_role = "Drone"

/mob/living/carbon/alien/humanoid/sentinel/mind_initialize()
	..()
	mind.special_role = "Sentinel"
	//XENO LARVA
/mob/living/carbon/alien/larva/mind_initialize()
	..()
	mind.special_role = "Larva"

//AI
/mob/living/silicon/ai/mind_initialize()
	..()
	mind.assigned_role = "AI"

//BORG
/mob/living/silicon/robot/mind_initialize()
	..()
	mind.assigned_role = "[ismommi(src) ? "Mobile MMI" : "Cyborg"]"

//PAI
/mob/living/silicon/pai/mind_initialize()
	..()
	mind.assigned_role = "pAI"
	mind.special_role = ""

//BLOB
/mob/camera/blob/mind_initialize()
	..()
	mind.special_role = "Blob"

//Animals
/mob/living/simple_animal/mind_initialize()
	..()
	mind.assigned_role = "Animal"
	mind.special_role = "Animal"

/mob/living/simple_animal/corgi/mind_initialize()
	..()
	mind.assigned_role = "Corgi"
	mind.special_role = "Corgi"

/mob/living/simple_animal/shade/mind_initialize()
	..()
	mind.assigned_role = "Shade"
	mind.special_role = "Shade"

/mob/living/simple_animal/construct/mind_initialize()
	..()
	mind.assigned_role = "[initial(name)]"
	mind.special_role = "Cultist"


code:
// module datum.
// this is per-object instance, and shows the condition of the modules in the object
// actual modules needed is referenced through modulestypes and the object type

/datum/module
	var/status				// bits set if working, 0 if broken
	var/installed			// bits set if installed, 0 if missing

// moduletypes datum
// this is per-object type, and shows the modules needed for a type of object

/datum/moduletypes
	var/list/modcount = list()	// assoc list of the count of modules for a type

var/list/modules = list(			// global associative list
"/obj/machinery/power/apc" = "card_reader,power_control,id_auth,cell_power,cell_charge")

/datum/module/New(var/obj/O)

	var/type = O.type		// the type of the creating object

	var/mneed = mods.inmodlist(type)		// find if this type has modules defined

	if(!mneed)		// not found in module list?
		del(src)	// delete self, thus ending proc

	var/needed = mods.getbitmask(type)		// get a bitmask for the number of modules in this object
	status = needed
	installed = needed

/datum/moduletypes/proc/addmod(var/type, var/modtextlist)
	modules += type	// index by type text
	modules[type] = modtextlist

/datum/moduletypes/proc/inmodlist(var/type)
	return ("[type]" in modules)

/datum/moduletypes/proc/getbitmask(var/type)
	var/count = modcount["[type]"]
	if(count)
		return 2**count-1

	var/modtext = modules["[type]"]
	var/num = 1
	var/pos = 1

	while(1)
		pos = findtext(modtext, ",", pos, 0)
		if(!pos)
			break
		else
			pos++
			num++

	modcount += "[type]"
	modcount["[type]"] = num

	return 2**num-1

license: mit


code:
/var/global/list/mutations_list = list()

/datum/mutation/

	var/name

/datum/mutation/New()

	mutations_list[name] = src

/datum/mutation/human

	var/dna_block
	var/quality
	var/get_chance = 100
	var/lowest_value = 256 * 8
	var/text_gain_indication = ""
	var/text_lose_indication = ""
	var/list/visual_indicators = list()

/datum/mutation/human/proc/force_give(mob/living/carbon/human/owner)
	if(!owner)
		return
	set_block(owner)
	. = on_acquiring(owner)

/datum/mutation/human/proc/force_lose(mob/living/carbon/human/owner)
	set_block(owner, 0)
	. = on_losing(owner)

/datum/mutation/human/proc/set_se(se_string, on = 1)
	if(!se_string || lentext(se_string) < DNA_STRUC_ENZYMES_BLOCKS * DNA_BLOCK_SIZE)	return
	var/before = copytext(se_string, 1, ((dna_block - 1) * DNA_BLOCK_SIZE) + 1)
	var/injection = num2hex(on ? rand(lowest_value, (256 * 16) - 1) : rand(0, lowest_value - 1), DNA_BLOCK_SIZE)
	var/after = copytext(se_string, (dna_block * DNA_BLOCK_SIZE) + 1, 0)
	return before + injection + after

/datum/mutation/human/proc/set_block(mob/living/carbon/owner, on = 1)
	if(owner && istype(owner) && owner.dna)
		owner.dna.struc_enzymes = set_se(owner.dna.struc_enzymes, on)

/datum/mutation/human/proc/check_block_string(se_string)
	if(!se_string || lentext(se_string) < DNA_STRUC_ENZYMES_BLOCKS * DNA_BLOCK_SIZE)	return 0
	if(hex2num(getblock(se_string, dna_block)) >= lowest_value)
		return 1

/datum/mutation/human/proc/check_block(mob/living/carbon/human/owner)
	if(check_block_string(owner.dna.struc_enzymes))
		return on_acquiring(owner)
	else
		return on_losing(owner)

/datum/mutation/human/proc/on_acquiring(mob/living/carbon/human/owner)
	if(!owner || !owner.dna)
		return
	if(src in owner.dna.mutations)
		return 1
	owner.dna.mutations.Add(src)
	gain_indication(owner)
	owner << text_gain_indication

/datum/mutation/human/proc/gain_indication(mob/living/carbon/human/owner)
	owner.overlays.Add(visual_indicators)
/*
	var/list/result_overlays = list()
	var/list/limbs = owner_get_limbs(NON_MECHANICAL|NON_AMPUTATED)   //I dunno how its done by RR but i assume something like this, proc that returns the list of limbs based on what types of limbs to return in argument
	for(var/obj/limb/L in limbs)
		result_overlays[L.identificator] = visual_indicators[L.identificator]  //visual_indicators is where overlays icons are stored, they are all created on new of each mutation, i assume you will change it to linked list for easyness, but for now its just a list
	return owner.redraw_overlays(result_overlays, MUTATION_LAYER)    //Currently mutations draw the overlays themselves but i assume if dismemberment will be overriding lots of shit like maybe clothes or something else mutations will just pass the shit to redraw proc
*/
/datum/mutation/human/proc/lose_indication(mob/living/carbon/human/owner)
	owner.overlays.Remove(visual_indicators)

/datum/mutation/human/proc/on_attack_hand(mob/living/carbon/human/owner, atom/target)
	return

/datum/mutation/human/proc/on_ranged_attack(mob/living/carbon/human/owner, atom/target)
	return

/datum/mutation/human/proc/on_life(mob/living/carbon/human/owner)
	return

/datum/mutation/human/proc/on_losing(mob/living/carbon/human/owner)
	if(owner && owner.dna.mutations.Remove(src))
		lose_indication(owner)
		owner << text_lose_indication
		return 0
	return 1

/datum/mutation/human/proc/say_mod(var/message)
	if(message)
		return message

/datum/mutation/human/hulk

	name = "Hulk"
	quality = POSITIVE
	get_chance = 100
	lowest_value = 256 * 14
	text_gain_indication = "Your muscles hurt!"

/datum/mutation/human/hulk/New()
	..()
	visual_indicators |= image("icon"='icons/effects/genetics.dmi', "icon_state"="hulk_f_s", "layer"=-MUTATIONS_LAYER)
	visual_indicators |= image("icon"='icons/effects/genetics.dmi', "icon_state"="hulk_m_s", "layer"=-MUTATIONS_LAYER)

/datum/mutation/human/hulk/on_acquiring(mob/living/carbon/human/owner)
	if(..())	return
	var/status = CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH
	owner.status_flags &= ~status

/datum/mutation/human/hulk/on_attack_hand(mob/living/carbon/human/owner, atom/target)
	return target.attack_hulk(owner)

/datum/mutation/human/hulk/gain_indication(mob/living/carbon/human/owner)
	var/g = (owner.gender == FEMALE) ? 1 : 2
	owner.overlays += visual_indicators[g]

/datum/mutation/human/hulk/on_life(mob/living/carbon/human/owner)
	if(owner.health < 25)
		on_losing(owner)
		owner << "You suddenly feel very weak."
		owner.Weaken(3)
		owner.emote("collapse")

/datum/mutation/human/hulk/on_losing(mob/living/carbon/human/owner)
	..()
	owner.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH

/datum/mutation/human/hulk/say_mod(var/message)
	if(message)
		message = "[uppertext(replacetext(message, ".", "!"))]!!"
	return message

/datum/mutation/human/telekinesis

	name = "Telekinesis"
	quality = POSITIVE
	get_chance = 100
	lowest_value = 256 * 14
	text_gain_indication = "You feel smarter!"

/datum/mutation/human/telekinesis/New()
	..()
	visual_indicators |= image("icon"='icons/effects/genetics.dmi', "icon_state"="telekinesishead_s", "layer"=-MUTATIONS_LAYER)

/datum/mutation/human/telekinesis/on_ranged_attack(mob/living/carbon/human/owner, atom/target)
	target.attack_tk(owner)

/datum/mutation/human/cold_resistance

	name = "Cold Resistance"
	quality = POSITIVE
	get_chance = 100
	lowest_value = 256 * 12
	text_gain_indication = "Your body feels warm!"

/datum/mutation/human/cold_resistance/New()
	..()
	visual_indicators |= image("icon"='icons/effects/genetics.dmi', "icon_state"="fire_s", "layer"=-MUTATIONS_LAYER)

/datum/mutation/human/cold_resistance/on_life(mob/living/carbon/human/owner)
	if(owner.getFireLoss())
		if(prob(1))
			owner.heal_organ_damage(0,1)   //Is this really needed?

/datum/mutation/human/x_ray

	name = "X Ray Vision"
	quality = POSITIVE
	get_chance = 100
	lowest_value = 256 * 15
	text_gain_indication = "The walls suddenly disappear!"

/datum/mutation/human/x_ray/on_acquiring(mob/living/carbon/human/owner)
	if(..())	return
	on_life(owner)

/datum/mutation/human/x_ray/on_life(mob/living/carbon/human/owner)
	owner.sight |= SEE_MOBS|SEE_OBJS|SEE_TURFS
	owner.see_in_dark = 8

/datum/mutation/human/x_ray/on_losing(mob/living/carbon/human/owner)
	if(..())	return
	if((SEE_MOBS & owner.permanent_sight_flags) && (SEE_OBJS & owner.permanent_sight_flags) && (SEE_TURFS & owner.permanent_sight_flags)) //Xray flag combo
		return
	owner.see_in_dark = initial(owner.see_in_dark)
	owner.sight = initial(owner.sight)

/datum/mutation/human/nearsight

	name = "Near Sightness"
	quality = MINOR_NEGATIVE
	text_gain_indication = "You can't see very well."

/datum/mutation/human/nearsight/on_acquiring(mob/living/carbon/human/owner)
	if(..())	return
	owner.disabilities |= NEARSIGHT

/datum/mutation/human/nearsight/on_losing(mob/living/carbon/human/owner)
	if(..())	return
	owner.disabilities &= ~NEARSIGHT

/datum/mutation/human/epilepsy

	name = "Epilepsy"
	quality = NEGATIVE
	text_gain_indication = "You get a headache."

/datum/mutation/human/epilepsy/on_life(mob/living/carbon/human/owner)
	if ((prob(1) && owner.paralysis < 1))
		owner.visible_message("[owner] starts having a seizure!", "You have a seizure!")
		owner.Paralyse(10)
		owner.Jitter(1000)

/datum/mutation/human/bad_dna

	name = "Unstable DNA"
	quality = NEGATIVE
	text_gain_indication = "You feel strange."

/datum/mutation/human/bad_dna/on_acquiring(var/mob/living/carbon/human/owner)
	owner << text_gain_indication
	var/mob/new_mob
	if(prob(95))
		if(prob(50))
			new_mob = randmutb(owner)
		else
			new_mob = randmuti(owner)
	else
		new_mob = randmutg(owner)
	if(new_mob && ismob(new_mob))
		owner = new_mob
	. = owner
	on_losing(owner)

/datum/mutation/human/cough

	name = "Cough"
	quality = MINOR_NEGATIVE
	text_gain_indication = "You start coughing."

/datum/mutation/human/cough/on_life(mob/living/carbon/human/owner)
	if((prob(5) && owner.paralysis <= 1))
		owner.drop_item()
		owner.emote("cough")

/datum/mutation/human/clumsy

	name = "Clumsiness"
	quality = MINOR_NEGATIVE
	text_gain_indication = "You feel lightheaded."

/datum/mutation/human/clumsy/on_acquiring(mob/living/carbon/human/owner)
	if(..())	return
	owner.disabilities |= CLUMSY

/datum/mutation/human/clumsy/on_losing(mob/living/carbon/human/owner)
	if(..())	return
	owner.disabilities &= ~CLUMSY

/datum/mutation/human/tourettes

	name = "Tourettes Syndrome"
	quality = NEGATIVE
	text_gain_indication = "You twitch."

/datum/mutation/human/tourettes/on_life(mob/living/carbon/human/owner)
	if((prob(10) && owner.paralysis <= 1))
		owner.Stun(10)
		switch(rand(1, 3))
			if(1)
				owner.emote("twitch")
			if(2 to 3)
				owner.say("[prob(50) ? ";" : ""][pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER", "TITS")]")
		var/x_offset_old = owner.pixel_x
		var/y_offset_old = owner.pixel_y
		var/x_offset = owner.pixel_x + rand(-2,2)
		var/y_offset = owner.pixel_y + rand(-1,1)
		animate(owner, pixel_x = x_offset, pixel_y = y_offset, time = 1)
		animate(owner, pixel_x = x_offset_old, pixel_y = y_offset_old, time = 1)

/datum/mutation/human/nervousness

	name = "Nervousness"
	quality = MINOR_NEGATIVE
	text_gain_indication = "You feel nervous."

/datum/mutation/human/nervousness/on_life(mob/living/carbon/human/owner)
	if(prob(10))
		owner.stuttering = max(10, owner.stuttering)

/datum/mutation/human/deaf

	name = "Deafness"
	quality = NEGATIVE
	text_gain_indication = "You can't seem to hear anything."

/datum/mutation/human/deaf/on_acquiring(mob/living/carbon/human/owner)
	if(..())	return
	owner.disabilities |= DEAF

/datum/mutation/human/deaf/on_losing(mob/living/carbon/human/owner)
	if(..())	return
	owner.disabilities &= ~DEAF

/datum/mutation/human/blind

	name = "Blindness"
	quality = NEGATIVE
	text_gain_indication = "You can't seem to see anything."

/datum/mutation/human/blind/on_acquiring(mob/living/carbon/human/owner)
	if(..())	return
	owner.disabilities |= BLIND

/datum/mutation/human/blind/on_losing(mob/living/carbon/human/owner)
	if(..())	return
	owner.disabilities &= ~BLIND

/datum/mutation/human/race

	name = "Monkified"
	quality = NEGATIVE

/datum/mutation/human/race/on_acquiring(mob/living/carbon/human/owner)
	if(..())	return
	. = owner.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)

/datum/mutation/human/race/gain_indication(mob/living/carbon/human/owner)
	return

/datum/mutation/human/race/lose_indication(mob/living/carbon/monkey/owner)
	return

/datum/mutation/human/race/on_losing(mob/living/carbon/monkey/owner)
	if(..())	return
	. = owner.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)

/datum/mutation/human/laser_eyes

	name = "Laser Eyes"
	quality = POSITIVE
	dna_block = NON_SCANNABLE
	text_gain_indication = "You feel pressure building up behind your eyes."

/datum/mutation/human/laser_eyes/on_ranged_attack(mob/living/carbon/human/owner, atom/target)
	if(owner.a_intent == "harm")
		owner.LaserEyes(target)


code:
/* * * * * * * * * * * * * * * * * * * * * * * * * *
 * /datum/recipe by rastaf0            13 apr 2011 *
 * * * * * * * * * * * * * * * * * * * * * * * * * *
 * This is powerful and flexible recipe system.
 * It exists not only for food.
 * supports both reagents and objects as prerequisites.
 * In order to use this system you have to define a deriative from /datum/recipe
 * * reagents are reagents. Acid, milc, booze, etc.
 * * items are objects. Fruits, tools, circuit boards.
 * * result is type to create as new object
 * * time is optional parameter, you shall use in in your machine,
     default /datum/recipe/ procs does not rely on this parameter.
 *
 *  Functions you need:
 *  /datum/recipe/proc/make(var/obj/container as obj)
 *    Creates result inside container,
 *    deletes prerequisite reagents,
 *    transfers reagents from prerequisite objects,
 *    deletes all prerequisite objects (even not needed for recipe at the moment).
 *
 *  /proc/select_recipe(list/datum/recipe/avaiable_recipes, obj/obj as obj, exact = 1)
 *    Wonderful function that select suitable recipe for you.
 *    obj is a machine (or magik hat) with prerequisites,
 *    exact = 0 forces algorithm to ignore superfluous stuff.
 *
 *
 *  Functions you do not need to call directly but could:
 *  /datum/recipe/proc/check_reagents(var/datum/reagents/avail_reagents)
 *    //1=precisely,  0=insufficiently, -1=superfluous
 *
 *  /datum/recipe/proc/check_items(var/obj/container as obj)
 *    //1=precisely, 0=insufficiently, -1=superfluous
 *
 * */

/datum/recipe
	var/list/reagents // example:  = list("berryjuice" = 5) // do not list same reagent twice
	var/list/items // example: =list(/obj/item/weapon/crowbar, /obj/item/weapon/welder) // place /foo/bar before /foo
	var/result //example: = /obj/item/weapon/reagent_containers/food/snacks/donut
	var/time = 100 // 1/10 part of second

/datum/recipe/proc/check_reagents(var/datum/reagents/avail_reagents) //1=precisely, 0=insufficiently, -1=superfluous
	. = 1
	for (var/r_r in reagents)
		var/aval_r_amnt = avail_reagents.get_reagent_amount(r_r)
		if (!(abs(aval_r_amnt - reagents[r_r])<0.5)) //if NOT equals
			if (aval_r_amnt>reagents[r_r])
				. = -1
			else
				return 0
	if ((reagents?(reagents.len):(0)) < avail_reagents.reagent_list.len)
		return -1
	return .

/datum/recipe/proc/check_items(var/obj/container as obj) //1=precisely, 0=insufficiently, -1=superfluous
	if (!items)
		if (locate(/obj/) in container)
			return -1
		else
			return 1
	. = 1
	var/list/checklist = items.Copy()
	for (var/obj/O in container)
		var/found = 0
		for (var/type in checklist)
			if (istype(O,type))
				checklist-=type
				found = 1
				break
		if (!found)
			. = -1
	if (checklist.len)
		return 0
	return .

//general version
/datum/recipe/proc/make(var/obj/container as obj)
	var/obj/result_obj = new result(container)
	for (var/obj/O in (container.contents-result_obj))
		O.reagents.trans_to(result_obj, O.reagents.total_volume)
		qdel(O)
	container.reagents.clear_reagents()
	return result_obj

// food-related
/datum/recipe/proc/make_food(var/obj/container as obj)
	var/obj/result_obj = new result(container)
	for (var/obj/O in (container.contents-result_obj))
		if (O.reagents)
			O.reagents.del_reagent("nutriment")
			O.reagents.update_total()
			O.reagents.trans_to(result_obj, O.reagents.total_volume)
		qdel(O)
	container.reagents.clear_reagents()
	return result_obj

/proc/select_recipe(var/list/datum/recipe/avaiable_recipes, var/obj/obj as obj, var/exact = 1 as num)
	if (!exact)
		exact = -1
	var/list/datum/recipe/possible_recipes = new
	for (var/datum/recipe/recipe in avaiable_recipes)
		if (recipe.check_reagents(obj.reagents)==exact && recipe.check_items(obj)==exact)
			possible_recipes+=recipe
	if (possible_recipes.len==0)
		return null
	else if (possible_recipes.len==1)
		return possible_recipes[1]
	else //okay, let's select the most complicated recipe
		var/r_count = 0
		var/i_count = 0
		. = possible_recipes[1]
		for (var/datum/recipe/recipe in possible_recipes)
			var/N_i = (recipe.items)?(recipe.items.len):0
			var/N_r = (recipe.reagents)?(recipe.reagents.len):0
			if (N_i > i_count || (N_i== i_count && N_r > r_count ))
				r_count = N_r
				i_count = N_i
				. = recipe
		return .


code:
#define TARGET_CLOSEST 1
#define TARGET_RANDOM 2

/obj/effect/proc_holder
	var/panel = "Debug"//What panel the proc holder needs to go on.

var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin verb for now

/obj/effect/proc_holder/spell
	name = "Spell"
	desc = "A wizard spell"
	panel = "Spells"
	var/sound = "sound/weapons/badZap.ogg"
	anchored = 1 // Crap like fireball projectiles are proc_holders, this is needed so fireballs don't get blown back into your face via atmos etc.
	pass_flags = PASSTABLE
	density = 0
	opacity = 0

	var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit?

	var/charge_type = "recharge" //can be recharge or charges, see charge_max and charge_counter descriptions; can also be based on the holder's vars now, use "holder_var" for that

	var/charge_max = 100 //recharge time in deciseconds if charge_type = "recharge" or starting charges if charge_type = "charges"
	var/charge_counter = 0 //can only cast spells if it equals recharge, ++ each decisecond if charge_type = "recharge" or -- each cast if charge_type = "charges"
	var/still_recharging_msg = "The spell is still recharging."

	var/holder_var_type = "bruteloss" //only used if charge_type equals to "holder_var"
	var/holder_var_amount = 20 //same. The amount adjusted with the mob's var when the spell is used

	var/clothes_req = 1 //see if it requires clothes
	var/human_req = 0 //spell can only be cast by humans
	var/nonabstract_req = 0 //spell can only be cast by mobs that are physical entities
	var/stat_allowed = 0 //see if it requires being conscious/alive, need to set to 1 for ghostpells
	var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell
	var/invocation_emote_self = null
	var/invocation_type = "none" //can be none, whisper, emote and shout
	var/range = 7 //the range of the spell; outer radius for aoe spells
	var/message = "" //whatever it says to the guy affected by it
	var/selection_type = "view" //can be "range" or "view"
	var/spell_level = 0 //if a spell can be taken multiple times, this raises
	var/level_max = 4 //The max possible level_max is 4
	var/cooldown_min = 0 //This defines what spell quickened four timeshas as a cooldown. Make sure to set this for every spell

	var/overlay = 0
	var/overlay_icon = 'icons/obj/wizard.dmi'
	var/overlay_icon_state = "spell"
	var/overlay_lifespan = 0

	var/sparks_spread = 0
	var/sparks_amt = 0 //cropped at 10
	var/smoke_spread = 0 //1 - harmless, 2 - harmful
	var/smoke_amt = 0 //cropped at 10

	var/critfailchance = 0
	var/centcom_cancast = 1 //Whether or not the spell should be allowed on z2

	var/datum/action/spell_action/action = null
	var/action_icon = 'icons/mob/actions.dmi'
	var/action_icon_state = "spell_default"
	var/action_background_icon_state = "bg_spell"

/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell

	if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
		user << "You shouldn't have this spell! Something's wrong."
		return 0

	if(user.z == ZLEVEL_CENTCOM && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
		return 0
	if(user.z == ZLEVEL_CENTCOM && ticker.mode.name == "ragin' mages")
		return 0

	if(!skipcharge)
		switch(charge_type)
			if("recharge")
				if(charge_counter < charge_max)
					user << still_recharging_msg
					return 0
			if("charges")
				if(!charge_counter)
					user << "[name] has no charges left."
					return 0

	if(user.stat && !stat_allowed)
		user << "Not when you're incapacitated."
		return 0

	if(ishuman(user))

		var/mob/living/carbon/human/H = user

		if((invocation_type == "whisper" || invocation_type == "shout") && H.is_muzzled())
			user << "You can't get the words out!"
			return 0

		if(clothes_req) //clothes check
			if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/wizard))
				H << "I don't feel strong enough without my robe."
				return 0
			if(!istype(H.shoes, /obj/item/clothing/shoes/sandal))
				H << "I don't feel strong enough without my sandals."
				return 0
			if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/wizard))
				H << "I don't feel strong enough without my hat."
				return 0
	else
		if(clothes_req || human_req)
			user << "This spell can only be cast by humans!"
			return 0
		if(nonabstract_req && (isbrain(user) || ispAI(user)))
			user << "This spell can only be cast by physical beings!"
			return 0

	if(!skipcharge)
		switch(charge_type)
			if("recharge")
				charge_counter = 0 //doesn't start recharging until the targets selecting ends
			if("charges")
				charge_counter-- //returns the charge if the targets selecting fails
			if("holdervar")
				adjust_var(user, holder_var_type, holder_var_amount)

	return 1

/obj/effect/proc_holder/spell/proc/invocation(mob/user = usr) //spelling the spell out and setting it on recharge/reducing charges amount
	switch(invocation_type)
		if("shout")
			if(prob(50))//Auto-mute? Fuck that noise
				user.say(invocation)
			else
				user.say(replacetext(invocation," ","`"))
		if("whisper")
			if(prob(50))
				user.whisper(invocation)
			else
				user.whisper(replacetext(invocation," ","`"))
		if("emote")
			user.visible_message(invocation, invocation_emote_self) //same style as in mob/living/emote.dm

/obj/effect/proc_holder/spell/proc/playMagSound()
	playsound(get_turf(usr), sound,50,1)

/obj/effect/proc_holder/spell/New()
	..()

	still_recharging_msg = "[name] is still recharging."
	charge_counter = charge_max

/obj/effect/proc_holder/spell/Click()
	if(cast_check())
		choose_targets()
	return 1

/obj/effect/proc_holder/spell/proc/choose_targets(mob/user = usr) //depends on subtype - /targeted or /aoe_turf
	return

/obj/effect/proc_holder/spell/proc/start_recharge()
	while(charge_counter < charge_max && isnull(gc_destroyed))
		sleep(1)
		charge_counter++

/obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = 1, mob/user = usr) //if recharge is started is important for the trigger spells
	before_cast(targets)
	invocation()
	user.attack_log += text("\[[time_stamp()]\] [user.real_name] ([user.ckey]) cast the spell [name].")
	spawn(0)
		if(charge_type == "recharge" && recharge)
			start_recharge()
	if(prob(critfailchance))
		critfail(targets)
	else
		cast(targets)
	after_cast(targets)

/obj/effect/proc_holder/spell/proc/before_cast(list/targets)
	if(overlay)
		for(var/atom/target in targets)
			var/location
			if(istype(target,/mob/living))
				location = target.loc
			else if(istype(target,/turf))
				location = target
			var/obj/effect/overlay/spell = new /obj/effect/overlay(location)
			spell.icon = overlay_icon
			spell.icon_state = overlay_icon_state
			spell.anchored = 1
			spell.density = 0
			spawn(overlay_lifespan)
				qdel(spell)

/obj/effect/proc_holder/spell/proc/after_cast(list/targets)
	for(var/atom/target in targets)
		var/location
		if(istype(target,/mob/living))
			location = target.loc
		else if(istype(target,/turf))
			location = target
		if(istype(target,/mob/living) && message)
			target << text("[message]")
		if(sparks_spread)
			var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
			sparks.set_up(sparks_amt, 0, location) //no idea what the 0 is
			sparks.start()
		if(smoke_spread)
			if(smoke_spread == 1)
				var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread()
				smoke.set_up(smoke_amt, 0, location, smoke_amt == 1 ? 15 : 0) // if more than one smoke, spread it around
				smoke.start()
			else if(smoke_spread == 2)
				var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread()
				smoke.set_up(smoke_amt, 0, location, smoke_amt == 1 ? 15 : 0) // same here
				smoke.start()
			else if(smoke_spread == 3)
				var/datum/effect/effect/system/sleep_smoke_spread/smoke = new /datum/effect/effect/system/sleep_smoke_spread()
				smoke.set_up(smoke_amt, 0, location, smoke_amt == 1 ? 15 : 0) // same here
				smoke.start()

/obj/effect/proc_holder/spell/proc/cast(list/targets)
	return

/obj/effect/proc_holder/spell/proc/critfail(list/targets)
	return

/obj/effect/proc_holder/spell/proc/revert_cast(mob/user = usr) //resets recharge or readds a charge
	switch(charge_type)
		if("recharge")
			charge_counter = charge_max
		if("charges")
			charge_counter++
		if("holdervar")
			adjust_var(user, holder_var_type, -holder_var_amount)

	return

/obj/effect/proc_holder/spell/proc/adjust_var(mob/living/target = usr, type, amount) //handles the adjustment of the var when the spell is used. has some hardcoded types
	switch(type)
		if("bruteloss")
			target.adjustBruteLoss(amount)
		if("fireloss")
			target.adjustFireLoss(amount)
		if("toxloss")
			target.adjustToxLoss(amount)
		if("oxyloss")
			target.adjustOxyLoss(amount)
		if("stunned")
			target.AdjustStunned(amount)
		if("weakened")
			target.AdjustWeakened(amount)
		if("paralysis")
			target.AdjustParalysis(amount)
		else
			target.vars[type] += amount //I bear no responsibility for the runtimes that'll happen if you try to adjust non-numeric or even non-existant vars
	return

/obj/effect/proc_holder/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
	var/max_targets = 1 //leave 0 for unlimited targets in range, 1 for one selectable target in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
	var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
	var/include_user = 0 //if it includes usr in the target list
	var/random_target = 0 // chooses random viable target instead of asking the caster
	var/random_target_priority = TARGET_CLOSEST // if random_target is enabled how it will pick the target

/obj/effect/proc_holder/spell/aoe_turf //affects all turfs in view or range (depends)
	var/inner_radius = -1 //for all your ring spell needs

/obj/effect/proc_holder/spell/targeted/choose_targets(mob/user = usr)
	var/list/targets = list()

	switch(max_targets)
		if(0) //unlimited
			for(var/mob/living/target in view_or_range(range, user, selection_type))
				targets += target
		if(1) //single target can be picked
			if(range < 0)
				targets += user
			else
				var/possible_targets = list()

				for(var/mob/living/M in view_or_range(range, user, selection_type))
					if(!include_user && user == M)
						continue
					possible_targets += M

				//targets += input("Choose the target for the spell.", "Targeting") as mob in possible_targets
				//Adds a safety check post-input to make sure those targets are actually in range.
				var/mob/M
				if(!random_target)
					M = input("Choose the target for the spell.", "Targeting") as mob in possible_targets
				else
					switch(random_target_priority)
						if(TARGET_RANDOM)
							M = pick(possible_targets)
						if(TARGET_CLOSEST)
							for(var/mob/living/L in possible_targets)
								if(M)
									if(get_dist(user,L) < get_dist(user,M))
										if(los_check(user,L))
											M = L
								else
									if(los_check(user,L))
										M = L
				if(M in view_or_range(range, user, selection_type)) targets += M

		else
			var/list/possible_targets = list()
			for(var/mob/living/target in view_or_range(range, user, selection_type))
				possible_targets += target
			for(var/i=1,i<=max_targets,i++)
				if(!possible_targets.len)
					break
				if(target_ignore_prev)
					var/target = pick(possible_targets)
					possible_targets -= target
					targets += target
				else
					targets += pick(possible_targets)

	if(!include_user && (user in targets))
		targets -= user

	if(!targets.len) //doesn't waste the spell
		revert_cast(user)
		return

	perform(targets)

	return

/obj/effect/proc_holder/spell/aoe_turf/choose_targets(mob/user = usr)
	var/list/targets = list()

	for(var/turf/target in view_or_range(range,user,selection_type))
		if(!(target in view_or_range(inner_radius,user,selection_type)))
			targets += target

	if(!targets.len) //doesn't waste the spell
		revert_cast()
		return

	perform(targets)

	return

/obj/effect/proc_holder/spell/proc/can_be_cast_by(mob/caster)
	if((human_req || clothes_req) && !ishuman(caster))
		return 0
	return 1

/obj/effect/proc_holder/spell/targeted/proc/los_check(mob/A,mob/B)
	//Checks for obstacles from A to B
	var/obj/dummy = new(A.loc)
	dummy.pass_flags |= PASSTABLE
	for(var/turf/turf in getline(A,B))
		for(var/atom/movable/AM in turf)
			if(!AM.CanPass(dummy,turf,1))
				qdel(dummy)
				return 0
	qdel(dummy)
	return 1

/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr)
	if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
		return 0

	if(user.z == ZLEVEL_CENTCOM && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
		return 0
	if(user.z == ZLEVEL_CENTCOM && ticker.mode.name == "ragin' mages")
		return 0

	switch(charge_type)
		if("recharge")
			if(charge_counter < charge_max)
				return 0
		if("charges")
			if(!charge_counter)
				return 0

	if(user.stat && !stat_allowed)
		return 0

	if(ishuman(user))

		var/mob/living/carbon/human/H = user

		if((invocation_type == "whisper" || invocation_type == "shout") && H.is_muzzled())
			return 0

		if(clothes_req) //clothes check
			if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/wizard))
				return 0
			if(!istype(H.shoes, /obj/item/clothing/shoes/sandal))
				return 0
			if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/wizard))
				return 0
	else
		if(clothes_req || human_req)
			return 0
		if(nonabstract_req && (isbrain(user) || ispAI(user)))
			return 0
	return 1


code:
/obj/effect/proc_holder/spell/targeted/area_teleport
	name = "Area teleport"
	desc = "This spell teleports you to a type of area of your selection."
	nonabstract_req = 1

	var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list
	var/invocation_area = 1 //if the invocation appends the selected area
	var/sound1 = "sound/weapons/ZapBang.ogg"
	var/sound2 = "sound/weapons/ZapBang.ogg"

/obj/effect/proc_holder/spell/targeted/area_teleport/perform(list/targets, recharge = 1)
	var/thearea = before_cast(targets)
	if(!thearea || !cast_check(1))
		revert_cast()
		return
	invocation(thearea)
	spawn(0)
		if(charge_type == "recharge" && recharge)
			start_recharge()
	cast(targets,thearea)
	after_cast(targets)

/obj/effect/proc_holder/spell/targeted/area_teleport/before_cast(list/targets)
	var/A = null

	if(!randomise_selection)
		A = input("Area to teleport to", "Teleport", A) in teleportlocs
	else
		A = pick(teleportlocs)

	var/area/thearea = teleportlocs[A]

	return thearea

/obj/effect/proc_holder/spell/targeted/area_teleport/cast(list/targets,area/thearea)
	playsound(get_turf(usr), sound1, 50,1)
	for(var/mob/living/target in targets)
		var/list/L = list()
		for(var/turf/T in get_area_turfs(thearea.type))
			if(!T.density)
				var/clear = 1
				for(var/obj/O in T)
					if(O.density)
						clear = 0
						break
				if(clear)
					L+=T

		if(!L.len)
			usr <<"The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry."
			return

		if(target && target.buckled)
			target.buckled.unbuckle_mob()

		var/list/tempL = L
		var/attempt = null
		var/success = 0
		while(tempL.len)
			attempt = pick(tempL)
			target.Move(attempt)
			if(get_turf(target) == attempt)
				success = 1
				break
			else
				tempL.Remove(attempt)

		if(!success)
			target.loc = pick(L)
			playsound(get_turf(usr), sound2, 50,1)

	return

/obj/effect/proc_holder/spell/targeted/area_teleport/invocation(area/chosenarea = null)
	if(!invocation_area || !chosenarea)
		..()
	else
		switch(invocation_type)
			if("shout")
				usr.say("[invocation] [uppertext(chosenarea.name)]")
				if(usr.gender==MALE)
					playsound(usr.loc, pick('sound/misc/null.ogg','sound/misc/null.ogg'), 100, 1)
				else
					playsound(usr.loc, pick('sound/misc/null.ogg','sound/misc/null.ogg'), 100, 1)
			if("whisper")
				usr.whisper("[invocation] [uppertext(chosenarea.name)]")

	return


code:
/obj/effect/proc_holder/spell/targeted/barnyardcurse
	name = "Curse of the Barnyard"
	desc = "This spell dooms the fate of any unlucky soul to the speech and facial attributes of a barnyard animal"
	school = "transmutation"
	charge_type = "recharge"
	charge_max	= 150
	charge_counter = 0
	clothes_req = 0
	stat_allowed = 0
	invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
	invocation_type = "shout"
	range = 7
	cooldown_min = 30
	selection_type = "range"
	var/list/compatible_mobs = list(/mob/living/carbon/human,/mob/living/carbon/monkey)

	action_icon_state = "barn"

/obj/effect/proc_holder/spell/targeted/barnyardcurse/cast(list/targets, mob/user = usr)
	if(!targets.len)
		user << "No target found in range."
		return

	var/mob/living/carbon/target = targets[1]

	if(!(target.type in compatible_mobs))
		user << "You are unable to curse [target]'s head!"
		return

	if(!(target in oview(range)))
		user << "They are too far away!"
		return

	var/list/masks = list(/obj/item/clothing/mask/spig, /obj/item/clothing/mask/cowmask, /obj/item/clothing/mask/horsehead)
	var/list/mSounds = list("sound/magic/PigHead_curse.ogg", "sound/magic/CowHead_Curse.ogg", "sound/magic/HorseHead_curse.ogg")
	var/randM = rand(1,3)

	var/choice = masks[randM]
	var/obj/item/clothing/mask/magichead = new choice
	magichead.flags |=NODROP
	magichead.flags_inv = null
	target.visible_message("[target]'s face lights up in fire, and after the event a barnyard animal's head takes it's place!", \
						   "Your face burns up, and shortly after the fire you realise you have the face of a barnyard animal!")
	if(!target.unEquip(target.wear_mask))
		qdel(target.wear_mask)
	target.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1)
	playsound(get_turf(target), mSounds[randM], 50, 1)

	flick("e_flash", target.flash)


code:
/obj/effect/proc_holder/spell/targeted/charge
	name = "Charge"
	desc = "This spell can be used to charge up spent magical artifacts, among other things."

	school = "transmutation"
	charge_max = 600
	clothes_req = 0
	invocation = "DIRI CEL"
	invocation_type = "whisper"
	range = -1
	cooldown_min = 400 //50 deciseconds reduction per rank
	include_user = 1

/obj/effect/proc_holder/spell/targeted/charge/cast(list/targets)
	for(var/mob/living/user in targets)
		var/list/hand_items = list(user.get_active_hand(),user.get_inactive_hand())
		var/charged_item = null
		var/burnt_out = 0
		for(var/obj/item in hand_items)
			if(istype(item, /obj/item/weapon/grab))
				var/obj/item/weapon/grab/G = item
				if(G.affecting)
					var/mob/M = G.affecting
					if(M.mob_spell_list.len != 0 || (M.mind && M.mind.spell_list.len != 0))
						for(var/obj/effect/proc_holder/spell/S in M.mob_spell_list)
							S.charge_counter = S.charge_max
						if(M.mind)
							for(var/obj/effect/proc_holder/spell/S in M.mind.spell_list)
								S.charge_counter = S.charge_max
						M <<"you feel raw magic flowing through you, it feels good!"
					else
						M <<"you feel very strange for a moment, but then it passes."
						burnt_out = 1
					charged_item = M
					break
			else if(istype(item, /obj/item/weapon/spellbook/oneuse))
				var/obj/item/weapon/spellbook/oneuse/I = item
				if(prob(80))
					user.visible_message("[I] catches fire!")
					qdel(I)
				else
					I.used = 0
					charged_item = I
					break
			else if(istype(item, /obj/item/weapon/gun/magic))
				var/obj/item/weapon/gun/magic/I = item
				if(prob(80) && !I.can_charge)
					I.max_charges--
				if(I.max_charges <= 0)
					I.max_charges = 0
					burnt_out = 1
				I.charges = I.max_charges
				if(istype(item,/obj/item/weapon/gun/magic/wand) && I.max_charges != 0)
					var/obj/item/weapon/gun/magic/W = item
					W.icon_state = initial(W.icon_state)
				charged_item = I
				break
			else if(istype(item, /obj/item/weapon/stock_parts/cell/))
				var/obj/item/weapon/stock_parts/cell/C = item
				if(prob(80))
					C.maxcharge -= 200
				if(C.maxcharge <= 1) //Div by 0 protection
					C.maxcharge = 1
					burnt_out = 1
				C.charge = C.maxcharge
				charged_item = C
				break
			else if(item.contents)
				var/obj/I = null
				for(I in item.contents)
					if(istype(I, /obj/item/weapon/stock_parts/cell/))
						var/obj/item/weapon/stock_parts/cell/C = I
						if(prob(80))
							C.maxcharge -= 200
						if(C.maxcharge <= 1) //Div by 0 protection
							C.maxcharge = 1
							burnt_out = 1
						C.charge = C.maxcharge
						item.update_icon()
						charged_item = item
						break
		if(!charged_item)
			user << "you feel magical power surging to your hands, but the feeling rapidly fades..."
		else if(burnt_out)
			user << "[charged_item] doesn't seem to be reacting to the spell..."
		else
			playsound(get_turf(usr), "sound/magic/Charge.ogg", 50, 1)
			user << "[charged_item] suddenly feels very warm!"


code:
/obj/effect/proc_holder/spell/aoe_turf/conjure
	name = "Conjure"
	desc = "This spell conjures objs of the specified types in range."

	var/list/summon_type = list() //determines what exactly will be summoned
	//should be text, like list("/obj/machinery/bot/ed209")

	var/summon_lifespan = 0 // 0=permanent, any other time in deciseconds
	var/summon_amt = 1 //amount of objects summoned
	var/summon_ignore_density = 0 //if set to 1, adds dense tiles to possible spawn places
	var/summon_ignore_prev_spawn_points = 0 //if set to 1, each new object is summoned on a new spawn point

	var/list/newVars = list() //vars of the summoned objects will be replaced with those where they meet
	//should have format of list("emagged" = 1,"name" = "Wizard's Justicebot"), for example

	var/cast_sound = 'sound/items/welder.ogg'

/obj/effect/proc_holder/spell/aoe_turf/conjure/cast(list/targets)
	playsound(get_turf(usr), cast_sound, 50,1)
	for(var/turf/T in targets)
		if(T.density && !summon_ignore_density)
			targets -= T

	for(var/i=0,i<summon_amt,i++)
		if(!targets.len)
			break
		var/summoned_object_type = pick(summon_type)
		var/spawn_place = pick(targets)
		if(summon_ignore_prev_spawn_points)
			targets -= spawn_place
		if(ispath(summoned_object_type,/turf))
			var/turf/O = spawn_place
			var/N = summoned_object_type
			O.ChangeTurf(N)
		else
			var/atom/summoned_object = new summoned_object_type(spawn_place)

			for(var/varName in newVars)
				if(varName in summoned_object.vars)
					summoned_object.vars[varName] = newVars[varName]

			if(summon_lifespan)
				spawn(summon_lifespan)
					if(summoned_object)
						qdel(summoned_object)

	return

/obj/effect/proc_holder/spell/aoe_turf/conjure/summonEdSwarm //test purposes
	name = "Dispense Wizard Justice"
	desc = "This spell dispenses wizard justice."

	summon_type = list(/obj/machinery/bot/ed209)
	summon_amt = 10
	range = 3
	newVars = list("emagged" = 2,"name" = "Wizard's Justicebot")


code:
//////////////////////////////Construct Spells/////////////////////////

/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser
	charge_max = 1800

/obj/effect/proc_holder/spell/aoe_turf/conjure/floor
	name = "Floor Construction"
	desc = "This spell constructs a cult floor"

	school = "conjuration"
	charge_max = 20
	clothes_req = 0
	invocation = "none"
	invocation_type = "none"
	range = 0
	summon_type = list(/turf/simulated/floor/plasteel/cult)
	centcom_cancast = 0 //Stop crashing the server by spawning turfs on transit tiles

/obj/effect/proc_holder/spell/aoe_turf/conjure/wall
	name = "Lesser Construction"
	desc = "This spell constructs a cult wall"

	school = "conjuration"
	charge_max = 100
	clothes_req = 0
	invocation = "none"
	invocation_type = "none"
	range = 0
	summon_type = list(/turf/simulated/wall/cult)
	centcom_cancast = 0 //Stop crashing the server by spawning turfs on transit tiles

/obj/effect/proc_holder/spell/aoe_turf/conjure/wall/reinforced
	name = "Greater Construction"
	desc = "This spell constructs a reinforced metal wall"

	school = "conjuration"
	charge_max = 300
	clothes_req = 0
	invocation = "none"
	invocation_type = "none"
	range = 0
	centcom_cancast = 0 //Stop crashing the server by spawning turfs on transit tiles

	summon_type = list(/turf/simulated/wall/r_wall)

/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone
	name = "Summon Soulstone"
	desc = "This spell reaches into Nar-Sie's realm, summoning one of the legendary fragments across time and space"

	school = "conjuration"
	charge_max = 3000
	clothes_req = 0
	invocation = "none"
	invocation_type = "none"
	range = 0

	summon_type = list(/obj/item/device/soulstone)

/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall
	name = "Shield"
	desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire"

	school = "transmutation"
	charge_max = 300
	clothes_req = 0
	invocation = "none"
	invocation_type = "none"
	range = 0
	summon_type = list(/obj/effect/forcefield)
	summon_lifespan = 200

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift
	name = "Phase Shift"
	desc = "This spell allows you to pass through walls"

	school = "transmutation"
	charge_max = 200
	clothes_req = 0
	invocation = "none"
	invocation_type = "none"
	range = -1
	include_user = 1
	jaunt_duration = 50 //in deciseconds
	centcom_cancast = 0 //Stop people from getting to centcom

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/jaunt_disappear(var/atom/movable/overlay/animation, var/mob/living/target)
	animation.icon_state = "phase_shift"
	animation.dir = target.dir
	flick("phase_shift",animation)

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/jaunt_reappear(var/atom/movable/overlay/animation, var/mob/living/target)
	animation.icon_state = "phase_shift2"
	animation.dir = target.dir
	flick("phase_shift2",animation)

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/jaunt_steam(var/mobloc)
	return

/obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser
	name = "Lesser Magic Missile"
	desc = "This spell fires several, slow moving, magic projectiles at nearby targets."

	school = "evocation"
	charge_max = 400
	clothes_req = 0
	invocation = "none"
	invocation_type = "none"
	proj_lifespan = 10
	max_targets = 6

/obj/effect/proc_holder/spell/targeted/smoke/disable
	name = "Paralysing Smoke"
	desc = "This spell spawns a cloud of paralysing smoke."

	school = "conjuration"
	charge_max = 200
	clothes_req = 0
	invocation = "none"
	invocation_type = "none"
	range = -1
	include_user = 1
	cooldown_min = 20 //25 deciseconds reduction per rank

	smoke_spread = 3
	smoke_amt = 10

/obj/effect/proc_holder/spell/aoe_turf/knock/harvester
	name = "Disintegrate Doors"
	desc = "No door shall stop you."

	charge_max = 100
	invocation = ""
	invocation_type = "silent"
	range = 5

	action_icon_state = "knock"

/obj/effect/proc_holder/spell/aoe_turf/knock/harvester/cast(list/targets)
	for(var/turf/T in targets)
		for(var/obj/machinery/door/door in T.contents)
			spawn(1)
				door.narsie_act()
	return


code:
/obj/effect/proc_holder/spell/dumbfire

	var/projectile_type = ""
	var/activate_on_collision = 1

	var/proj_icon = 'icons/obj/projectiles.dmi'
	var/proj_icon_state = "spell"
	var/proj_name = "a spell projectile"

	var/proj_trail = 0 //if it leaves a trail
	var/proj_trail_lifespan = 0 //deciseconds
	var/proj_trail_icon = 'icons/obj/wizard.dmi'
	var/proj_trail_icon_state = "trail"

	var/proj_type = "/obj/effect/proc_holder/spell" //IMPORTANT use only subtypes of this

	var/proj_insubstantial = 0 //if it can pass through dense objects or not
	var/proj_trigger_range = 1 //the range from target at which the projectile triggers cast(target)

	var/proj_lifespan = 100 //in deciseconds * proj_step_delay
	var/proj_step_delay = 1 //lower = faster

/obj/effect/proc_holder/spell/dumbfire/choose_targets(mob/user = usr)

	var/turf/T = get_turf(usr)
	for(var/i = 1; i < range; i++)
		var/turf/new_turf = get_step(T, usr.dir)
		if(new_turf.density)
			break
		T = new_turf
	perform(list(T))

/obj/effect/proc_holder/spell/dumbfire/cast(list/targets, mob/user = usr)
	playMagSound()
	for(var/turf/target in targets)
		spawn(0)
			var/obj/effect/proc_holder/spell/targeted/projectile
			if(istext(proj_type))
				var/projectile_type = text2path(proj_type)
				projectile = new projectile_type(user)
			if(istype(proj_type,/obj/effect/proc_holder/spell))
				projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user)
				projectile:linked_spells += proj_type
			projectile.icon = proj_icon
			projectile.icon_state = proj_icon_state
			projectile.dir = get_dir(projectile, target)
			projectile.name = proj_name

			var/current_loc = usr.loc

			projectile.loc = current_loc

			for(var/i = 0,i < proj_lifespan,i++)
				if(!projectile)
					break

				if(proj_insubstantial)
					projectile.loc = get_step(projectile, projectile.dir)
				else
					step(projectile, projectile.dir)

				if(projectile.loc == current_loc || i == proj_lifespan)
					projectile.cast(current_loc)
					break

				var/mob/living/L = locate(/mob/living) in range(projectile, proj_trigger_range) - usr
				if(L && L.stat != DEAD)
					projectile.cast(L.loc)
					break

				if(proj_trail && projectile)
					spawn(0)
						if(projectile)
							var/obj/effect/overlay/trail = new /obj/effect/overlay(projectile.loc)
							trail.icon = proj_trail_icon
							trail.icon_state = proj_trail_icon_state
							trail.density = 0
							spawn(proj_trail_lifespan)
								qdel(trail)

				current_loc = projectile.loc

				sleep(proj_step_delay)

			if(projectile)
				qdel(projectile)


code:
/obj/effect/proc_holder/spell/targeted/emplosion
	name = "Emplosion"
	desc = "This spell emplodes an area."

	var/emp_heavy = 2
	var/emp_light = 3

	action_icon_state = "emp"
	sound = "sound/weapons/ZapBang.ogg"

/obj/effect/proc_holder/spell/targeted/emplosion/cast(list/targets)
	playsound(get_turf(usr), sound, 50,1)
	for(var/mob/living/target in targets)
		empulse(target.loc, emp_heavy, emp_light)

	return