code:
#define VEST_STEALTH 1
#define VEST_COMBAT 2
#define GIZMO_SCAN 1
#define GIZMO_MARK 2

//AGENT VEST
/obj/item/clothing/suit/armor/abductor/vest
	name = "agent vest"
	desc = "A vest outfitted with advanced stealth technology. It has two modes - combat and stealth."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "vest_stealth"
	item_state = "armor"
	blood_overlay_type = "armor"
	origin_tech = "materials=5;biotech=4;powerstorage=5;abductor=3"
	armor = list(melee = 15, bullet = 15, laser = 15, energy = 15, bomb = 15, bio = 15, rad = 15)
	actions_types = list(/datum/action/item_action/hands_free/activate)
	var/mode = VEST_STEALTH
	var/stealth_active = 0
	var/combat_cooldown = 10
	var/datum/icon_snapshot/disguise
	var/stealth_armor = list(melee = 15, bullet = 15, laser = 15, energy = 15, bomb = 15, bio = 15, rad = 15)
	var/combat_armor = list(melee = 50, bullet = 50, laser = 50, energy = 50, bomb = 50, bio = 50, rad = 50)

/obj/item/clothing/suit/armor/abductor/vest/proc/flip_mode()
	switch(mode)
		if(VEST_STEALTH)
			mode = VEST_COMBAT
			DeactivateStealth()
			armor = combat_armor
			icon_state = "vest_combat"
		if(VEST_COMBAT)// TO STEALTH
			mode = VEST_STEALTH
			armor = stealth_armor
			icon_state = "vest_stealth"
	if(istype(loc, /mob/living/carbon/human))
		var/mob/living/carbon/human/H = loc
		H.update_inv_wear_suit()
	for(var/X in actions)
		var/datum/action/A = X
		A.UpdateButtonIcon()

/obj/item/clothing/suit/armor/abductor/vest/item_action_slot_check(slot, mob/user)
	if(slot == slot_wear_suit) //we only give the mob the ability to activate the vest if he's actually wearing it.
		return 1

/obj/item/clothing/suit/armor/abductor/vest/proc/SetDisguise(datum/icon_snapshot/entry)
	disguise = entry

/obj/item/clothing/suit/armor/abductor/vest/proc/ActivateStealth()
	if(disguise == null)
		return
	stealth_active = 1
	if(istype(src.loc, /mob/living/carbon/human))
		var/mob/living/carbon/human/M = src.loc
		spawn(0)
			anim(M.loc,M,'icons/mob/mob.dmi',,"cloak",,M.dir)

		M.name_override = disguise.name
		M.icon = disguise.icon
		M.icon_state = disguise.icon_state
		M.overlays = disguise.overlays
		M.update_inv_r_hand()
		M.update_inv_l_hand()
	return

/obj/item/clothing/suit/armor/abductor/vest/proc/DeactivateStealth()
	if(!stealth_active)
		return
	stealth_active = 0
	if(istype(src.loc, /mob/living/carbon/human))
		var/mob/living/carbon/human/M = src.loc
		spawn(0)
			anim(M.loc,M,'icons/mob/mob.dmi',,"uncloak",,M.dir)
		M.name_override = null
		M.overlays.Cut()
		M.regenerate_icons()
	return

/obj/item/clothing/suit/armor/abductor/vest/hit_reaction()
	DeactivateStealth()
	return 0

/obj/item/clothing/suit/armor/abductor/vest/IsReflect()
	DeactivateStealth()
	return 0

/obj/item/clothing/suit/armor/abductor/vest/ui_action_click()
	switch(mode)
		if(VEST_COMBAT)
			Adrenaline()
		if(VEST_STEALTH)
			if(stealth_active)
				DeactivateStealth()
			else
				ActivateStealth()

/obj/item/clothing/suit/armor/abductor/vest/proc/Adrenaline()
	if(istype(src.loc, /mob/living/carbon/human))
		if(combat_cooldown != initial(combat_cooldown))
			src.loc << "Combat injection is still recharging."
		var/mob/living/carbon/human/M = src.loc
		M.adjustStaminaLoss(-75)
		M.SetParalysis(0)
		M.SetStunned(0)
		M.SetWeakened(0)
		combat_cooldown = 0
		SSobj.processing |= src

/obj/item/clothing/suit/armor/abductor/vest/process()
	combat_cooldown++
	if(combat_cooldown==initial(combat_cooldown))
		SSobj.processing.Remove(src)

/obj/item/device/abductor/proc/IsAbductor(user)
	if(ishuman(user))
		var/mob/living/carbon/human/H = user
		if(H.dna.species.id != "abductor")
			return 0
		return 1
	return 0

/obj/item/device/abductor/proc/AbductorCheck(user)
	if(IsAbductor(user))
		return 1
	user << "You can't figure how this works!"
	return 0

/obj/item/device/abductor/proc/ScientistCheck(user)
	var/mob/living/carbon/human/H = user
	var/datum/species/abductor/S = H.dna.species
	return S.scientist

/obj/item/device/abductor/gizmo
	name = "science tool"
	desc = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "gizmo_scan"
	item_state = "silencer"
	origin_tech = "materials=5;magnets=5;bluespace=6;abductor=4"
	var/mode = GIZMO_SCAN
	var/mob/living/marked = null
	var/obj/machinery/abductor/console/console

/obj/item/device/abductor/gizmo/attack_self(mob/user)
	if(!AbductorCheck(user))
		return
	if(!ScientistCheck(user))
		user << "You're not trained to use this!"
		return
	if(mode == GIZMO_SCAN)
		mode = GIZMO_MARK
		icon_state = "gizmo_mark"
	else
		mode = GIZMO_SCAN
		icon_state = "gizmo_scan"
	user << "You switch the device to [mode==GIZMO_SCAN? "SCAN": "MARK"] MODE"

/obj/item/device/abductor/gizmo/attack(mob/living/M, mob/user)
	if(!AbductorCheck(user))
		return
	if(!ScientistCheck(user))
		user << "You're not trained to use this"
		return
	switch(mode)
		if(GIZMO_SCAN)
			scan(M, user)
		if(GIZMO_MARK)
			mark(M, user)

/obj/item/device/abductor/gizmo/afterattack(atom/target, mob/living/user, flag, params)
	if(flag)
		return
	if(!AbductorCheck(user))
		return
	if(!ScientistCheck(user))
		user << "You're not trained to use this"
		return
	switch(mode)
		if(GIZMO_SCAN)
			scan(target, user)
		if(GIZMO_MARK)
			mark(target, user)

/obj/item/device/abductor/gizmo/proc/scan(atom/target, mob/living/user)
	if(istype(target,/mob/living/carbon/human))
		if(console!=null)
			console.AddSnapshot(target)
			user << "You scan [target] and add them to the database."

/obj/item/device/abductor/gizmo/proc/mark(atom/target, mob/living/user)
	if(marked == target)
		user << "This specimen is already marked!"
		return
	if(istype(target,/mob/living/carbon/human))
		if(IsAbductor(target))
			marked = target
			user << "You mark [target] for future retrieval."
		else
			prepare(target,user)
	else
		prepare(target,user)

/obj/item/device/abductor/gizmo/proc/prepare(atom/target, mob/living/user)
	if(get_dist(target,user)>1)
		user << "You need to be next to the specimen to prepare it for transport!"
		return
	user << "You begin preparing [target] for transport..."
	if(do_after(user, 100, target = target))
		marked = target
		user << "You finish preparing [target] for transport."

/obj/item/device/abductor/silencer
	name = "abductor silencer"
	desc = "A compact device used to shut down communications equipment."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "silencer"
	item_state = "gizmo"
	origin_tech = "materials=5;magnets=5;abductor=3"

/obj/item/device/abductor/silencer/attack(mob/living/M, mob/user)
	if(!AbductorCheck(user))
		return
	radio_off(M, user)

/obj/item/device/abductor/silencer/afterattack(atom/target, mob/living/user, flag, params)
	if(flag)
		return
	if(!AbductorCheck(user))
		return
	radio_off(target, user)

/obj/item/device/abductor/silencer/proc/radio_off(atom/target, mob/living/user)
	if( !(user in (viewers(7,target))) )
		return

	var/turf/targloc = get_turf(target)

	var/mob/living/carbon/human/M
	for(M in view(2,targloc))
		if(M == user)
			continue
		user << "You silence [M]'s radio devices."
		radio_off_mob(M)

/obj/item/device/abductor/silencer/proc/radio_off_mob(mob/living/carbon/human/M)
	var/list/all_items = M.GetAllContents()

	for(var/obj/I in all_items)
		if(istype(I,/obj/item/device/radio/))
			var/obj/item/device/radio/r = I
			r.listening = 0
			if(!istype(I,/obj/item/device/radio/headset))
				r.broadcasting = 0 //goddamned headset hacks

/obj/item/weapon/implant/abductor
	name = "recall implant"
	desc = "Returns you to the mothership."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "implant"
	activated = 1
	origin_tech = "materials=2;biotech=3;magnets=4;bluespace=5;abductor=5"
	var/obj/machinery/abductor/pad/home
	var/cooldown = 30

/obj/item/weapon/implant/abductor/activate()
	if(cooldown == initial(cooldown))
		home.Retrieve(imp_in,1)
		cooldown = 0
		SSobj.processing |= src
	else
		imp_in << "You must wait [30 - cooldown] seconds to use [src] again!"
	return

/obj/item/weapon/implant/abductor/process()
	if(cooldown < initial(cooldown))
		cooldown++
		if(cooldown == initial(cooldown))
			SSobj.processing.Remove(src)

/obj/item/weapon/implant/abductor/implant(var/mob/source, var/mob/user)
	if(..())
		var/obj/machinery/abductor/console/console
		if(ishuman(source))
			var/mob/living/carbon/human/H = source
			if(H.dna.species.id == "abductor")
				var/datum/species/abductor/S = H.dna.species
				console = get_team_console(S.team)
				home = console.pad

		if(!home)
			console = get_team_console(pick(1, 2, 3, 4))
			home = console.pad
		return 1

/obj/item/weapon/implant/abductor/proc/get_team_console(var/team)
	var/obj/machinery/abductor/console/console
	for(var/obj/machinery/abductor/console/c in machines)
		if(c.team == team)
			console = c
			break
	return console

/obj/item/device/firing_pin/alien
	name = "alien firing pin"
	desc = "An odd device that resembles a firing pin."
	fail_message = "UNAUTHORIZED -- UNAUTHORIZED"

/obj/item/device/firing_pin/alien/pin_auth(mob/living/user)
	if(ishuman(user))
		var/mob/living/carbon/human/H = user
		if(H.dna.species.id != "abductor")
			return 0
	return 1

/obj/item/weapon/gun/energy/alien
	name = "alien pistol"
	desc = "A complicated gun that fires bursts of high-intensity radiation."
	ammo_type = list(/obj/item/ammo_casing/energy/declone)
	pin = /obj/item/device/firing_pin/alien
	icon_state = "alienpistol"
	item_state = "alienpistol"
	origin_tech = "combat=5;materials=4;powerstorage=3;abductor=3"

/obj/item/weapon/paper/abductor
	name = "Dissection Guide"
	icon_state = "alienpaper_words"
	info = {"Dissection for Dummies

 1.Acquire fresh specimen.

 2.Put the specimen on operating table

 3.Apply surgical drapes preparing for dissection

 4.Apply scalpel to specimen torso

 5.Retract skin from specimen's torso

 6.Apply scalpel to specimen's torso

 7.Search through the specimen's torso with your hands to remove any organs

 8.Insert replacement gland (Retrieve one from gland storage)

 9.Consider dressing the specimen back to not disturb the habitat

 10.Put the specimen in the experiment machinery

 11.Choose one of the machine options and follow displayed instructions

Congratulations! You are now trained for xenobiology research!"}

/obj/item/weapon/paper/abductor/update_icon()
	return

#define BATON_STUN 0
#define BATON_SLEEP 1
#define BATON_CUFF 2
#define BATON_PROBE 3
#define BATON_MODES 4

/obj/item/weapon/abductor_baton
	name = "advanced baton"
	desc = "A quad-mode baton used for incapacitation and restraining of specimens."
	var/mode = BATON_STUN
	icon = 'icons/obj/abductor.dmi'
	icon_state = "wonderprodStun"
	item_state = "wonderprod"
	slot_flags = SLOT_BELT
	origin_tech = "materials=6;combat=5;biotech=7;abductor=4"
	force = 7
	w_class = 3
	actions_types = list(/datum/action/item_action/toggle_mode)

/obj/item/weapon/abductor_baton/proc/toggle(mob/living/user=usr)
	mode = (mode+1)%BATON_MODES
	var/txt
	switch(mode)
		if(BATON_STUN)
			txt = "stunning"
		if(BATON_SLEEP)
			txt = "sleep inducement"
		if(BATON_CUFF)
			txt = "restraining"
		if(BATON_PROBE)
			txt = "probing"

	usr << "You switch the baton to [txt] mode."
	update_icon()

/obj/item/weapon/abductor_baton/update_icon()
	switch(mode)
		if(BATON_STUN)
			icon_state = "wonderprodStun"
			item_state = "wonderprodStun"
		if(BATON_SLEEP)
			icon_state = "wonderprodSleep"
			item_state = "wonderprodSleep"
		if(BATON_CUFF)
			icon_state = "wonderprodCuff"
			item_state = "wonderprodCuff"
		if(BATON_PROBE)
			icon_state = "wonderprodProbe"
			item_state = "wonderprodProbe"

/obj/item/weapon/abductor_baton/proc/IsAbductor(mob/living/user)
	if(!ishuman(user))
		return 0
	var/mob/living/carbon/human/H = user
	if(H.dna.species.id != "abductor")
		return 0
	return 1

/obj/item/weapon/abductor_baton/attack(mob/target, mob/living/user)
	if(!IsAbductor(user))
		return

	if(isrobot(target))
		..()
		return

	if(!isliving(target))
		return

	var/mob/living/L = target

	user.do_attack_animation(L)

	if(ishuman(L))
		var/mob/living/carbon/human/H = L
		if(H.check_shields(0, "[user]'s [name]", src, MELEE_ATTACK))
			playsound(L, 'sound/weapons/Genhit.ogg', 50, 1)
			return 0

	switch (mode)
		if(BATON_STUN)
			StunAttack(L,user)
		if(BATON_SLEEP)
			SleepAttack(L,user)
		if(BATON_CUFF)
			CuffAttack(L,user)
		if(BATON_PROBE)
			ProbeAttack(L,user)

/obj/item/weapon/abductor_baton/attack_self(mob/living/user)
	toggle(user)

/obj/item/weapon/abductor_baton/proc/StunAttack(mob/living/L,mob/living/user)
	user.lastattacked = L
	L.lastattacker = user

	L.Stun(7)
	L.Weaken(7)
	L.apply_effect(STUTTER, 7)

	L.visible_message("[user] has stunned [L] with [src]!", \
							"[user] has stunned you with [src]!")
	playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)

	if(ishuman(L))
		var/mob/living/carbon/human/H = L
		H.forcesay(hit_appends)

	add_logs(user, L, "stunned")
	return

/obj/item/weapon/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user)
	if(L.stunned)
		L.visible_message("[user] has induced sleep in [L] with [src]!", \
							"You suddenly feel very drowsy!")
		playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
		L.Sleeping(60)
		add_logs(user, L, "put to sleep")
	else
		L.drowsyness += 1
		user << "Sleep inducement works fully only on stunned specimens! "
		L.visible_message("[user] tried to induce sleep in [L] with [src]!", \
							"You suddenly feel drowsy!")
	return

/obj/item/weapon/abductor_baton/proc/CuffAttack(mob/living/L,mob/living/user)
	if(!iscarbon(L))
		return
	var/mob/living/carbon/C = L
	if(!C.handcuffed)
		playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
		C.visible_message("[user] begins restraining [C] with [src]!", \
								"[user] begins shaping an energy field around your hands!")
		if(do_mob(user, C, 30))
			if(!C.handcuffed)
				C.handcuffed = new /obj/item/weapon/restraints/handcuffs/energy/used(C)
				C.update_handcuffed()
				user << "You handcuff [C]."
				add_logs(user, C, "handcuffed")
		else
			user << "You fail to handcuff [C]."
	return

/obj/item/weapon/abductor_baton/proc/ProbeAttack(mob/living/L,mob/living/user)
	L.visible_message("[user] probes [L] with [src]!", \
						"[user] probes you!")

	var/species = "Unknown species"
	var/helptext = "Species unsuitable for experiments."

	if(ishuman(L))
		var/mob/living/carbon/human/H = L
		species = "[H.dna.species.name]"
		if(L.mind && L.mind.changeling)
			species = "Changeling lifeform"
		var/obj/item/organ/internal/gland/temp = locate() in H.internal_organs
		if(temp)
			helptext = "Experimental gland detected!"
		else
			helptext = "Subject suitable for experiments."

	user << "Probing result:[species]"
	user << "[helptext]"

/obj/item/weapon/restraints/handcuffs/energy
	name = "hard-light energy field"
	desc = "A hard-light field restraining the hands."
	icon_state = "cuff_white" // Needs sprite
	breakouttime = 450
	trashtype = /obj/item/weapon/restraints/handcuffs/energy/used
	origin_tech = "materials=2;magnets=5;abductor=2"

/obj/item/weapon/restraints/handcuffs/energy/used
	desc = "energy discharge"

/obj/item/weapon/restraints/handcuffs/energy/used/dropped(mob/user)
	user.visible_message("[user]'s [src] break in a discharge of energy!", \
							"[user]'s [src] break in a discharge of energy!")
	var/datum/effect_system/spark_spread/S = new
	S.set_up(4,0,user.loc)
	S.start()
	qdel(src)

/obj/item/weapon/abductor_baton/examine(mob/user)
	..()
	switch(mode)
		if(BATON_STUN)
			user <<"The baton is in stun mode."
		if(BATON_SLEEP)
			user <<"The baton is in sleep inducement mode."
		if(BATON_CUFF)
			user <<"The baton is in restraining mode."
		if(BATON_PROBE)
			user << "The baton is in probing mode."

/obj/item/weapon/scalpel/alien
	name = "alien scalpel"
	icon = 'icons/obj/abductor.dmi'
	origin_tech = "materials=2;biotech=2;abductor=2"

/obj/item/weapon/hemostat/alien
	name = "alien hemostat"
	icon = 'icons/obj/abductor.dmi'
	origin_tech = "materials=2;biotech=2;abductor=2"

/obj/item/weapon/retractor/alien
	name = "alien retractor"
	icon = 'icons/obj/abductor.dmi'
	origin_tech = "materials=2;biotech=2;abductor=2"

/obj/item/weapon/circular_saw/alien
	name = "alien saw"
	icon = 'icons/obj/abductor.dmi'
	origin_tech = "materials=2;biotech=2;abductor=2"

/obj/item/weapon/surgicaldrill/alien
	name = "alien drill"
	icon = 'icons/obj/abductor.dmi'
	origin_tech = "materials=2;biotech=2;abductor=2"

/obj/item/weapon/cautery/alien
	name = "alien cautery"
	icon = 'icons/obj/abductor.dmi'
	origin_tech = "materials=2;biotech=2;abductor=2"

/obj/item/clothing/head/helmet/abductor
	name = "agent headgear"
	desc = "Abduct with style - spiky style. Prevents digital tracking."
	icon_state = "alienhelmet"
	item_state = "alienhelmet"
	blockTracking = 1
	origin_tech = "materials=6;magnets=5;abductor=3"
	flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR

// Operating Table / Beds / Lockers

/obj/structure/table/optable/abductor
	icon = 'icons/obj/abductor.dmi'
	icon_state = "bed"
	can_buckle = 1
	buckle_lying = 1
	deconstructable = 0

/obj/structure/bed/abductor
	name = "resting contraption"
	desc = "This looks similar to contraptions from earth. Could aliens be stealing our technology?"
	icon = 'icons/obj/abductor.dmi'
	buildstacktype = /obj/item/stack/sheet/mineral/abductor
	icon_state = "bed"

/obj/structure/table_frame/abductor
	name = "alien table frame"
	desc = "A sturdy table frame made from alien alloy."
	icon_state = "alien_frame"
	framestack = /obj/item/stack/sheet/mineral/abductor
	framestackamount = 1
	density = 1

/obj/structure/table_frame/abductor/attackby(obj/item/I, mob/user, params)
	if(istype(I, /obj/item/weapon/wrench))
		user << "You start disassembling [src]..."
		playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
		if(do_after(user, 30/I.toolspeed, target = src))
			playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
			for(var/i = 1, i <= framestackamount, i++)
				new framestack(get_turf(src))
			qdel(src)
			return
	if(istype(I, /obj/item/stack/sheet/mineral/abductor))
		var/obj/item/stack/sheet/P = I
		if(P.get_amount() < 1)
			user << "You need one alien alloy sheet to do this!"
			return
		user << "You start adding [P] to [src]..."
		if(do_after(user, 50, target = src))
			P.use(1)
			new /obj/structure/table/abductor(src.loc)
			qdel(src)
		return

/obj/structure/table/abductor
	name = "alien table"
	desc = "Advanced flat surface technology at work!"
	icon = 'icons/obj/smooth_structures/alien_table.dmi'
	icon_state = "alien_table"
	buildstack = /obj/item/stack/sheet/mineral/abductor
	framestack = /obj/item/stack/sheet/mineral/abductor
	buildstackamount = 1
	framestackamount = 1
	canSmoothWith = null
	frame = /obj/structure/table_frame/abductor

/obj/structure/closet/abductor
	name = "alien locker"
	desc = "Contains secrets of the universe."
	icon_state = "abductor"
	icon_door = "abductor"
	can_weld_shut = FALSE
	material_drop = /obj/item/stack/sheet/mineral/abductor

/obj/structure/door_assembly/door_assembly_abductor
	name = "alien airlock assembly"
	icon = 'icons/obj/doors/airlocks/abductor/abductor_airlock.dmi'
	overlays_file = 'icons/obj/doors/airlocks/abductor/overlays.dmi'
	typetext = "abductor"
	icontext = "abductor"
	airlock_type = /obj/machinery/door/airlock/abductor
	anchored = 1
	state = 1

/obj/structure/door_assembly/door_assembly_abductor/attackby(obj/item/W, mob/user, params)
	if(istype(W, /obj/item/weapon/weldingtool) && !anchored )
		var/obj/item/weapon/weldingtool/WT = W
		if(WT.remove_fuel(0,user))
			user.visible_message("[user] disassembles the airlock assembly.", \
								"You start to disassemble the airlock assembly...")
			playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
			if(do_after(user, 40/W.toolspeed, target = src))
				if( !WT.isOn() )
					return
				user << "You disassemble the airlock assembly."
				new /obj/item/stack/sheet/mineral/abductor(get_turf(src), 4)
				qdel(src)
		else
			return
	else if(istype(W, /obj/item/weapon/airlock_painter))
		return // no repainting
	else if(istype(W, /obj/item/stack/sheet))
		return // no material modding
	else
		..()


code:
/datum/surgery/organ_extraction
	name = "experimental dissection"
	steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin,/datum/surgery_step/incise, /datum/surgery_step/extract_organ ,/datum/surgery_step/gland_insert)
	possible_locs = list("chest")
	ignore_clothes = 1

/datum/surgery/organ_extraction/can_start(mob/user, mob/living/carbon/target)
	if(!ishuman(user))
		return 0
	var/mob/living/carbon/human/H = user
	if(H.dna.species.id == "abductor")
		return 1
	if((locate(/obj/item/weapon/implant/abductor) in H))
		return 1
	return 0

/datum/surgery_step/extract_organ
	name = "remove heart"
	accept_hand = 1
	time = 32
	var/obj/item/organ/internal/IC = null
	var/list/organ_types = list(/obj/item/organ/internal/heart)

/datum/surgery_step/extract_organ/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
	for(var/obj/item/I in target.internal_organs)
		if(I.type in organ_types)
			IC = I
			break
	user.visible_message("[user] starts to remove [target]'s organs.", "You start to remove [target]'s organs...")

/datum/surgery_step/extract_organ/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
	if(IC)
		user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "You pull [IC] out of [target]'s [target_zone].")
		user.put_in_hands(IC)
		IC.Remove(target, special = 1)
		return 1
	else
		user << "You don't find anything in [target]'s [target_zone]!"
		return 0

/datum/surgery_step/gland_insert
	name = "insert gland"
	implements = list(/obj/item/organ/internal/gland = 100)
	time = 32

/datum/surgery_step/gland_insert/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
	user.visible_message("[user] starts to insert [tool] into [target].", "You start to insert [tool] into [target]...")

/datum/surgery_step/gland_insert/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
	user.visible_message("[user] inserts [tool] into [target].", "You insert [tool] into [target].")
	user.drop_item()
	var/obj/item/organ/internal/gland/gland = tool
	gland.Insert(target, 2)
	return 1

license: mit


code:
/obj/item/organ/internal/gland
	name = "fleshy mass"
	desc = "A nausea-inducing hunk of twisting flesh and metal."
	icon = 'icons/obj/abductor.dmi'
	zone = "chest"
	slot = "gland"
	icon_state = "gland"
	status = ORGAN_ROBOTIC
	origin_tech = "materials=4;biotech=5"
	var/cooldown_low = 300
	var/cooldown_high = 300
	var/next_activation = 0
	var/uses // -1 For inifinite
	var/human_only = 0
	var/active = 0

/obj/item/organ/internal/gland/proc/ownerCheck()
	if(ishuman(owner))
		return 1
	if(!human_only && iscarbon(owner))
		return 1
	return 0

/obj/item/organ/internal/gland/proc/Start()
	active = 1
	next_activation = world.time + rand(cooldown_low,cooldown_high)

/obj/item/organ/internal/gland/Remove(var/mob/living/carbon/M, special = 0)
	active = 0
	if(initial(uses) == 1)
		uses = initial(uses)
	..()

/obj/item/organ/internal/gland/Insert(var/mob/living/carbon/M, special = 0)
	..()
	if(special != 2 && uses) // Special 2 means abductor surgery
		Start()

/obj/item/organ/internal/gland/on_life()
	if(!active)
		return
	if(!ownerCheck())
		active = 0
		return
	if(next_activation <= world.time)
		activate()
		uses--
		next_activation  = world.time + rand(cooldown_low,cooldown_high)
	if(!uses)
		active = 0

/obj/item/organ/internal/gland/proc/activate()
	return

/obj/item/organ/internal/gland/heals
	origin_tech = "materials=4;biotech=6"
	cooldown_low = 200
	cooldown_high = 400
	uses = -1
	icon_state = "health"

/obj/item/organ/internal/gland/heals/activate()
	owner << "You feel curiously revitalized."
	owner.adjustBruteLoss(-20)
	owner.adjustOxyLoss(-20)
	owner.adjustFireLoss(-20)

/obj/item/organ/internal/gland/slime
	origin_tech = "materials=4;biotech=6"
	cooldown_low = 600
	cooldown_high = 1200
	uses = -1
	icon_state = "slime"

/obj/item/organ/internal/gland/slime/activate()
	owner << "You feel nauseous!"
	owner.vomit(20)

	var/mob/living/simple_animal/slime/Slime = new/mob/living/simple_animal/slime(get_turf(owner))
	Slime.Friends = list(owner)
	Slime.Leader = owner

/obj/item/organ/internal/gland/mindshock
	origin_tech = "materials=4;biotech=5;magnets=3"
	cooldown_low = 300
	cooldown_high = 300
	uses = -1
	icon_state = "mindshock"

/obj/item/organ/internal/gland/mindshock/activate()
	owner << "You get a headache."

	var/turf/T = get_turf(owner)
	for(var/mob/living/carbon/H in orange(4,T))
		if(H == owner)
			continue
		H << "You hear a buzz in your head."
		H.confused += 20

/obj/item/organ/internal/gland/pop
	origin_tech = "materials=4;biotech=6"
	cooldown_low = 900
	cooldown_high = 1800
	uses = 6
	human_only = 1
	icon_state = "species"

/obj/item/organ/internal/gland/pop/activate()
	owner << "You feel unlike yourself."
	var/species = pick(list(/datum/species/lizard,/datum/species/jelly/slime,/datum/species/pod,/datum/species/fly))
	owner.set_species(species)

/obj/item/organ/internal/gland/ventcrawling
	origin_tech = "materials=4;biotech=5;bluespace=3"
	cooldown_low = 1800
	cooldown_high = 2400
	uses = 1
	icon_state = "vent"

/obj/item/organ/internal/gland/ventcrawling/activate()
	owner << "You feel very stretchy."
	owner.ventcrawler = 2
	return

/obj/item/organ/internal/gland/viral
	origin_tech = "materials=4;biotech=6"
	cooldown_low = 1800
	cooldown_high = 2400
	uses = 1
	icon_state = "viral"

/obj/item/organ/internal/gland/viral/activate()
	owner << "You feel sick."
	var/virus_type = pick(/datum/disease/beesease, /datum/disease/brainrot, /datum/disease/magnitis)
	var/datum/disease/D = new virus_type()
	D.carrier = 1
	owner.viruses += D
	D.affected_mob = owner
	D.holder = owner
	owner.med_hud_set_status()

/obj/item/organ/internal/gland/emp //TODO : Replace with something more interesting
	origin_tech = "materials=4;biotech=5;magnets=3"
	cooldown_low = 900
	cooldown_high = 1600
	uses = 10
	icon_state = "emp"

/obj/item/organ/internal/gland/emp/activate()
	owner << "You feel a spike of pain in your head."
	empulse(get_turf(owner), 2, 5, 1)

/obj/item/organ/internal/gland/spiderman
	origin_tech = "materials=4;biotech=6"
	cooldown_low = 450
	cooldown_high = 900
	uses = 10
	icon_state = "spider"

/obj/item/organ/internal/gland/spiderman/activate()
	owner << "You feel something crawling in your skin."
	owner.faction |= "spiders"
	new /obj/effect/spider/spiderling(owner.loc)

/obj/item/organ/internal/gland/egg
	origin_tech = "materials=4;biotech=6"
	cooldown_low = 300
	cooldown_high = 400
	uses = -1
	icon_state = "egg"

/obj/item/organ/internal/gland/egg/activate()
	owner << "You lay an egg!"
	var/obj/item/weapon/reagent_containers/food/snacks/egg/egg = new(owner.loc)
	egg.reagents.add_reagent("sacid",20)
	egg.desc += " It smells bad."

/obj/item/organ/internal/gland/bloody
	origin_tech = "materials=4;biotech=6"
	cooldown_low = 200
	cooldown_high = 400
	uses = -1

/obj/item/organ/internal/gland/bloody/activate()
	owner.adjustBruteLoss(15)

	owner.visible_message("[owner]'s skin erupts with blood!",\
	"Blood pours from your skin!")

	for(var/turf/T in oview(3,owner)) //Make this respect walls and such
		T.add_blood_floor(owner)
	for(var/mob/living/carbon/human/H in oview(3,owner)) //Blood decals for simple animals would be neat. aka Carp with blood on it.
		if(H.wear_suit)
			H.wear_suit.add_blood(owner)
			H.update_inv_wear_suit(0)
		else if(H.w_uniform)
			H.w_uniform.add_blood(owner)
			H.update_inv_w_uniform(0)

/obj/item/organ/internal/gland/bodysnatch
	origin_tech = "materials=4;biotech=7"
	cooldown_low = 600
	cooldown_high = 600
	human_only = 1
	uses = 1

/obj/item/organ/internal/gland/bodysnatch/activate()
	owner << "You feel something moving around inside you..."
	//spawn cocoon with clone greytide snpc inside
	if(ishuman(owner))
		var/obj/effect/cocoon/abductor/C = new (get_turf(owner))
		C.Copy(owner)
		C.Start()
	owner.gib()
	return

/obj/effect/cocoon/abductor
	name = "slimy cocoon"
	desc = "Something is moving inside."
	icon = 'icons/effects/effects.dmi'
	icon_state = "cocoon_large3"
	color = rgb(10,120,10)
	density = 1
	var/hatch_time = 0

/obj/effect/cocoon/abductor/proc/Copy(mob/living/carbon/human/H)
	var/mob/living/carbon/human/interactive/greytide/clone = new(src)
	clone.hardset_dna(H.dna.uni_identity,H.dna.struc_enzymes,H.real_name, H.dna.blood_type, H.dna.species.type, H.dna.features)

	//There's no define for this / get all items ?
	var/list/slots = list(slot_back,slot_w_uniform,slot_wear_suit,\
	slot_wear_mask,slot_head,slot_shoes,slot_gloves,slot_ears,\
	slot_glasses,slot_belt,slot_s_store,slot_l_store,slot_r_store,slot_wear_id)

	for(var/slot in slots)
		var/obj/item/I = H.get_item_by_slot(slot)
		if(I)
			clone.equip_to_slot_if_possible(I,slot)

/obj/effect/cocoon/abductor/proc/Start()
	hatch_time = world.time + 600
	SSobj.processing |= src

/obj/effect/cocoon/abductor/process()
	if(world.time > hatch_time)
		SSobj.processing.Remove(src)
		for(var/mob/M in contents)
			src.visible_message("[src] hatches!")
			M.loc = src.loc
		qdel(src)

/obj/item/organ/internal/gland/plasma
	cooldown_low = 2400
	cooldown_high = 3000
	origin_tech = "materials=4;biotech=5;plasmatech=3"
	uses = 1

/obj/item/organ/internal/gland/plasma/activate()
	owner << "You feel bloated."
	sleep(150)
	if(!owner) return
	owner << "A massive stomachache overcomes you."
	sleep(50)
	if(!owner) return
	owner.visible_message("[owner] explodes in a cloud of plasma!")
	var/turf/open/T = get_turf(owner)
	if(istype(T))
		T.atmos_spawn_air("plasma=300;TEMP=[T20C]")
	owner.gib()
	return


code:
/obj/machinery/computer/camera_advanced/abductor
	name = "Human Observation Console"
	var/team = 0
	networks = list("SS13","Abductor")
	off_action = new/datum/action/innate/camera_off/abductor //specific datum
	var/datum/action/innate/teleport_in/tele_in_action = new
	var/datum/action/innate/teleport_out/tele_out_action = new
	var/datum/action/innate/teleport_self/tele_self_action = new
	var/datum/action/innate/vest_mode_swap/vest_mode_action = new
	var/datum/action/innate/vest_disguise_swap/vest_disguise_action = new
	var/datum/action/innate/set_droppoint/set_droppoint_action = new
	var/obj/machinery/abductor/console/console

	icon = 'icons/obj/abductor.dmi'
	icon_state = "camera"

/obj/machinery/computer/camera_advanced/abductor/CreateEye()
	..()
	eyeobj.visible_icon = 1
	eyeobj.icon = 'icons/obj/abductor.dmi'
	eyeobj.icon_state = "camera_target"

/obj/machinery/computer/camera_advanced/abductor/GrantActions(mob/living/carbon/user)
	off_action.target = user
	off_action.Grant(user)

	jump_action.target = user
	jump_action.Grant(user)
	//TODO : add null checks
	tele_in_action.target = console.pad
	tele_in_action.Grant(user)

	tele_out_action.target = console
	tele_out_action.Grant(user)

	tele_self_action.target = console.pad
	tele_self_action.Grant(user)

	vest_mode_action.target = console
	vest_mode_action.Grant(user)

	vest_disguise_action.target = console
	vest_disguise_action.Grant(user)

	set_droppoint_action.target = console
	set_droppoint_action.Grant(user)

/obj/machinery/computer/camera_advanced/abductor/proc/IsAbductor(mob/living/carbon/human/H)
	return H.dna.species.id == "abductor"

/obj/machinery/computer/camera_advanced/abductor/proc/IsScientist(mob/living/carbon/human/H)
	var/datum/species/abductor/S = H.dna.species
	return S.scientist

/obj/machinery/computer/camera_advanced/abductor/attack_hand(mob/user)
	if(!iscarbon(user) || !IsAbductor(user))
		return
	return ..()

/datum/action/innate/camera_off/abductor/Activate()
	if(!target || !iscarbon(target))
		return
	var/mob/living/carbon/C = target
	var/mob/camera/aiEye/remote/remote_eye = C.remote_control
	var/obj/machinery/computer/camera_advanced/abductor/origin = remote_eye.origin
	origin.current_user = null
	origin.jump_action.Remove(C)
	origin.tele_in_action.Remove(C)
	origin.tele_out_action.Remove(C)
	origin.tele_self_action.Remove(C)
	origin.vest_mode_action.Remove(C)
	origin.vest_disguise_action.Remove(C)
	origin.set_droppoint_action.Remove(C)
	remote_eye.eye_user = null
	C.reset_perspective(null)
	if(C.client)
		C.client.images -= remote_eye.user_image
		for(var/datum/camerachunk/chunk in remote_eye.visibleCameraChunks)
			C.client.images -= chunk.obscured
	C.remote_control = null
	C.unset_machine()
	src.Remove(C)

/datum/action/innate/teleport_in
	name = "Send To"
	button_icon_state = "beam_down"

/datum/action/innate/teleport_in/Activate()
	if(!target || !iscarbon(owner))
		return
	var/mob/living/carbon/human/C = owner
	var/mob/camera/aiEye/remote/remote_eye = C.remote_control
	var/obj/machinery/abductor/pad/P = target

	if(cameranet.checkTurfVis(remote_eye.loc))
		P.PadToLoc(remote_eye.loc)

/datum/action/innate/teleport_out
	name = "Retrieve"
	button_icon_state = "beam_up"

/datum/action/innate/teleport_out/Activate()
	if(!target || !iscarbon(owner))
		return
	var/obj/machinery/abductor/console/console = target

	console.TeleporterRetrieve()

/datum/action/innate/teleport_self
	name = "Send Self"
	button_icon_state = "beam_down"

/datum/action/innate/teleport_self/Activate()
	if(!target || !iscarbon(owner))
		return
	var/mob/living/carbon/human/C = owner
	var/mob/camera/aiEye/remote/remote_eye = C.remote_control
	var/obj/machinery/abductor/pad/P = target

	if(cameranet.checkTurfVis(remote_eye.loc))
		P.MobToLoc(remote_eye.loc,C)

/datum/action/innate/vest_mode_swap
	name = "Switch Vest Mode"
	button_icon_state = "vest_mode"

/datum/action/innate/vest_mode_swap/Activate()
	if(!target || !iscarbon(owner))
		return
	var/obj/machinery/abductor/console/console = target
	console.FlipVest()

/datum/action/innate/vest_disguise_swap
	name = "Switch Vest Disguise"
	button_icon_state = "vest_disguise"

/datum/action/innate/vest_disguise_swap/Activate()
	if(!target || !iscarbon(owner))
		return
	var/obj/machinery/abductor/console/console = target
	console.SelectDisguise(remote=1)

/datum/action/innate/set_droppoint
	name = "Set Experiment Release Point"
	button_icon_state = "set_drop"

/datum/action/innate/set_droppoint/Activate()
	if(!target || !iscarbon(owner))
		return

	var/mob/living/carbon/human/C = owner
	var/mob/camera/aiEye/remote/remote_eye = C.remote_control

	var/obj/machinery/abductor/console/console = target
	console.SetDroppoint(remote_eye.loc,owner)


code:
//Common

/obj/machinery/abductor
	var/team = 0

/obj/machinery/abductor/proc/IsAbductor(mob/living/carbon/human/H)
	return H.dna.species.id == "abductor"

/obj/machinery/abductor/proc/IsAgent(mob/living/carbon/human/H)
	if(H.dna.species.id == "abductor")
		var/datum/species/abductor/S = H.dna.species
		return S.agent
	return 0

/obj/machinery/abductor/proc/IsScientist(mob/living/carbon/human/H)
	if(H.dna.species.id == "abductor")
		var/datum/species/abductor/S = H.dna.species
		return S.scientist
	return 0

//Console

/obj/machinery/abductor/console
	name = "Abductor console"
	desc = "Ship command center."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "console"
	density = 1
	anchored = 1
	var/obj/item/device/abductor/gizmo/gizmo
	var/obj/item/clothing/suit/armor/abductor/vest/vest
	var/obj/machinery/abductor/experiment/experiment
	var/obj/machinery/abductor/pad/pad
	var/obj/machinery/computer/camera_advanced/abductor/camera
	var/list/datum/icon_snapshot/disguises = list()

/obj/machinery/abductor/console/attack_hand(mob/user)
	if(..())
		return
	if(!IsAbductor(user))
		user << "You start mashing alien buttons at random!"
		if(do_after(user,100, target = src))
			TeleporterSend()
		return
	user.set_machine(src)
	var/dat = ""
	dat += "
 Abductsoft 3000
"

	if(experiment != null)
		var/points = experiment.points
		dat += "Collected Samples : [points]
"
		dat += "Transfer data in exchange for supplies:
"
		dat += "Advanced Baton
"
		dat += "Agent Helmet
"
		dat += "Radio Silencer
"
		dat += "Science Tool
"
	else
		dat += "NO EXPERIMENT MACHINE DETECTED
"

	if(pad!=null)
		dat += "Emergency Teleporter System."
		dat += "Consider using primary observation console first."
		dat += "Activate Teleporter
"
		if(gizmo!=null && gizmo.marked!=null)
			dat += "Retrieve Mark
"
		else
			dat += "Retrieve Mark
"
	else
		dat += "NO TELEPAD DETECTED
"

	if(vest!=null)
		dat += "
 Agent Vest Mode

"
		var/mode = vest.mode
		if(mode == VEST_STEALTH)
			dat += "Combat"
			dat += "Stealth"
		else
			dat += "Combat"
			dat += "Stealth"

		dat+="
"
		dat += "Select Agent Vest Disguise
"
	else
		dat += "NO AGENT VEST DETECTED"
	var/datum/browser/popup = new(user, "computer", "Abductor Console", 400, 500)
	popup.set_content(dat)
	popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
	popup.open()
	return

/obj/machinery/abductor/console/Topic(href, href_list)
	if(..())
		return

	usr.set_machine(src)
	if(href_list["teleporter_send"])
		TeleporterSend()
	else if(href_list["teleporter_retrieve"])
		TeleporterRetrieve()
	else if(href_list["flip_vest"])
		FlipVest()
	else if(href_list["select_disguise"])
		SelectDisguise()
	else if(href_list["dispense"])
		switch(href_list["dispense"])
			if("baton")
				Dispense(/obj/item/weapon/abductor_baton,cost=2)
			if("helmet")
				Dispense(/obj/item/clothing/head/helmet/abductor)
			if("silencer")
				Dispense(/obj/item/device/abductor/silencer)
			if("tool")
				Dispense(/obj/item/device/abductor/gizmo)
	src.updateUsrDialog()

/obj/machinery/abductor/console/proc/TeleporterRetrieve()
	if(gizmo!=null && pad!=null && gizmo.marked)
		pad.Retrieve(gizmo.marked)
	return

/obj/machinery/abductor/console/proc/TeleporterSend()
	if(pad!=null)
		pad.Send()
	return

/obj/machinery/abductor/console/proc/FlipVest()
	if(vest!=null)
		vest.flip_mode()
	return

/obj/machinery/abductor/console/proc/SelectDisguise(remote=0)
	var/list/entries = list()
	var/tempname
	var/datum/icon_snapshot/temp
	for(var/i = 1; i <= disguises.len; i++)
		temp = disguises[i]
		tempname = temp.name
		entries["[tempname]"] = disguises[i]
	var/entry_name = input( "Choose Disguise", "Disguise") in entries
	var/datum/icon_snapshot/chosen = entries[entry_name]
	if(chosen && (remote || in_range(usr,src)))
		vest.SetDisguise(chosen)
	return

/obj/machinery/abductor/console/proc/SetDroppoint(turf/open/location,user)
	if(!istype(location))
		user << "That place is not safe for the specimen."
		return

	if(pad)
		pad.teleport_target = location
		user << "Location marked as test subject release point."

/obj/machinery/abductor/console/proc/Initialize()

	for(var/obj/machinery/abductor/pad/p in machines)
		if(p.team == team)
			pad = p
			break

	for(var/obj/machinery/abductor/experiment/e in machines)
		if(e.team == team)
			experiment = e
			e.console = src

	for(var/obj/machinery/computer/camera_advanced/abductor/c in machines)
		if(c.team == team)
			camera = c
			c.console = src

/obj/machinery/abductor/console/proc/AddSnapshot(mob/living/carbon/human/target)
	var/datum/icon_snapshot/entry = new
	entry.name = target.name
	entry.icon = target.icon
	entry.icon_state = target.icon_state
	entry.overlays = target.get_overlays_copy(list(L_HAND_LAYER,R_HAND_LAYER))
	for(var/i=1,i<=disguises.len,i++)
		var/datum/icon_snapshot/temp = disguises[i]
		if(temp.name == entry.name)
			disguises[i] = entry
			return
	disguises.Add(entry)
	return

/obj/machinery/abductor/console/attackby(obj/O, mob/user, params)
	if(istype(O, /obj/item/device/abductor/gizmo))
		var/obj/item/device/abductor/gizmo/G = O
		user << "You link the tool to the console."
		gizmo = G
		G.console = src
	else if(istype(O, /obj/item/clothing/suit/armor/abductor/vest))
		var/obj/item/clothing/suit/armor/abductor/vest/V = O
		user << "You link the vest to the console."
		vest = V
	else
		..()

/obj/machinery/abductor/console/proc/Dispense(item,cost=1)
	if(experiment && experiment.points >= cost)
		experiment.points-=cost
		say("Incoming supply!")
		if(pad)
			flick("alien-pad", pad)
			new item(pad.loc)
		else
			new item(src.loc)
	else
		say("Insufficent data!")
	return


code:
/obj/machinery/abductor/gland_dispenser
	name = "Replacement Organ Storage"
	desc = "A tank filled with replacement organs"
	icon = 'icons/obj/abductor.dmi'
	icon_state = "dispenser"
	density = 1
	anchored = 1
	var/list/gland_types
	var/list/gland_colors
	var/list/amounts

/obj/machinery/abductor/gland_dispenser/proc/random_color()
	//TODO : replace with presets or spectrum
	return rgb(rand(0,255),rand(0,255),rand(0,255))

/obj/machinery/abductor/gland_dispenser/New()
	gland_types = subtypesof(/obj/item/organ/internal/gland)
	gland_types = shuffle(gland_types)
	gland_colors = new/list(gland_types.len)
	amounts = new/list(gland_types.len)
	for(var/i=1,i<=gland_types.len,i++)
		gland_colors[i] = random_color()
		amounts[i] = rand(1,5)

/obj/machinery/abductor/gland_dispenser/attack_hand(mob/user)
	if(..())
		return
	if(!IsAbductor(user))
		return
	user.set_machine(src)
	var/box_css = {"
	"}
	var/dat = ""
	var/item_count = 0
	for(var/i=1,i<=gland_colors.len,i++)
		item_count++
		var/g_color = gland_colors[i]
		var/amount = amounts[i]
		dat += "[amount]"
		if(item_count == 3) // Three boxes per line
			dat +="

"
			item_count = 0
	var/datum/browser/popup = new(user, "glands", "Gland Dispenser", 200, 200)
	popup.add_head_content(box_css)
	popup.set_content(dat)
	popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
	popup.open()
	return

/obj/machinery/abductor/gland_dispenser/attackby(obj/item/weapon/W, mob/user, params)
	if(istype(W, /obj/item/organ/internal/gland))
		if(!user.drop_item())
			return
		W.loc = src
		for(var/i=1,i<=gland_colors.len,i++)
			if(gland_types[i] == W.type)
				amounts[i]++

/obj/machinery/abductor/gland_dispenser/Topic(href, href_list)
	if(..())
		return
	usr.set_machine(src)

	if(href_list["dispense"])
		Dispense(text2num(href_list["dispense"]))
	src.updateUsrDialog()

/obj/machinery/abductor/gland_dispenser/proc/Dispense(count)
	if(amounts[count]>0)
		amounts[count]--
		var/T = gland_types[count]
		new T(get_turf(src))


code:
/obj/machinery/abductor/experiment
	name = "experimentation machine"
	desc = "A large man-sized tube sporting a complex array of surgical apparatus."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "experiment-open"
	density = 0
	anchored = 1
	state_open = 1
	var/points = 0
	var/list/history = list()
	var/list/abductee_minds = list()
	var/flash = " - || - "
	var/obj/machinery/abductor/console/console

/obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user)
	if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
		return
	if(IsAbductor(target))
		return
	close_machine(target)

/obj/machinery/abductor/experiment/attack_hand(mob/user)
	if(..())
		return

	experimentUI(user)

/obj/machinery/abductor/experiment/open_machine()
	if(!state_open && !panel_open)
		..()

/obj/machinery/abductor/experiment/close_machine(mob/target)
	for(var/mob/living/carbon/C in loc)
		if(IsAbductor(C))
			return
	if(state_open && !panel_open)
		..(target)

/obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H)
	var/icon/photo = null
	var/g = (H.gender == FEMALE) ? "f" : "m"
	if(!config.mutant_races || H.dna.species.use_skintones)
		photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.skin_tone]_[g]_s")
	else
		photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.dna.species.id]_[g]_s")
		photo.Blend("#[H.dna.features["mcolor"]]", ICON_MULTIPLY)

	var/icon/eyes_s
	if(EYECOLOR in H.dna.species.specflags)
		eyes_s = icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[H.dna.species.eyes]_s")
		eyes_s.Blend("#[H.eye_color]", ICON_MULTIPLY)

	var/datum/sprite_accessory/S
	S = hair_styles_list[H.hair_style]
	if(S && (HAIR in H.dna.species.specflags))
		var/icon/hair_s = icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s")
		hair_s.Blend("#[H.hair_color]", ICON_MULTIPLY)
		eyes_s.Blend(hair_s, ICON_OVERLAY)

	S = facial_hair_styles_list[H.facial_hair_style]
	if(S && (FACEHAIR in H.dna.species.specflags))
		var/icon/facial_s = icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s")
		facial_s.Blend("#[H.facial_hair_color]", ICON_MULTIPLY)
		eyes_s.Blend(facial_s, ICON_OVERLAY)

	if(eyes_s)
		photo.Blend(eyes_s, ICON_OVERLAY)

	var/icon/splat = icon("icon" = 'icons/mob/dam_human.dmi',"icon_state" = "chest30")
	photo.Blend(splat,ICON_OVERLAY)

	return photo

/obj/machinery/abductor/experiment/proc/experimentUI(mob/user)
	var/dat
	dat += "
 Experiment
"
	if(occupant)
		var/obj/item/weapon/photo/P = new
		P.photocreate(null, icon(dissection_icon(occupant), dir = SOUTH))
		user << browse_rsc(P.img, "dissection_img")
		dat += "

"
		dat += "" //Avert your eyes
		dat += "	"
		dat += "Probe
"
		dat += "Dissect
"
		dat += "Analyze
"
		dat += "

"
	else
		dat += "Experiment "

	if(!occupant)
		dat += "
Machine Unoccupied
"
	else
		dat += "
Subject Status :
"
		dat += "[occupant.name] => "
		switch(occupant.stat)
			if(0)
				dat += "Conscious"
			if(1)
				dat += "Unconscious"
			else
				dat += "Deceased"
	dat += "
"
	dat += "[flash]"
	dat += "
"
	dat += "Scan"
	dat += "Close" : "open=1'>Open"]"
	var/datum/browser/popup = new(user, "experiment", "Probing Console", 300, 300)
	popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
	popup.set_content(dat)
	popup.open()

/obj/machinery/abductor/experiment/Topic(href, href_list)
	if(..() || usr == occupant)
		return
	usr.set_machine(src)
	if(href_list["refresh"])
		updateUsrDialog()
		return
	if(href_list["open"])
		open_machine()
		return
	if(href_list["close"])
		close_machine()
		return
	if(occupant && occupant.stat != DEAD)
		if(href_list["experiment"])
			flash = Experiment(occupant,href_list["experiment"])
	updateUsrDialog()
	add_fingerprint(usr)

/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type)
	var/mob/living/carbon/human/H = occupant
	var/point_reward = 0
	if(H in history)
		return "Specimen already in database."
	if(H.stat == DEAD)
		say("Specimen deceased - please provide fresh sample.")
		return "Specimen deceased."
	var/obj/item/organ/internal/gland/GlandTest = locate() in H.internal_organs
	if(!GlandTest)
		say("Experimental dissection not detected!")
		return "No glands detected!"
	if(H.mind != null && H.ckey != null)
		history += H
		abductee_minds += H.mind
		say("Processing specimen...")
		sleep(5)
		switch(text2num(type))
			if(1)
				H << "You feel violated."
			if(2)
				H << "You feel yourself being sliced apart and put back together."
			if(3)
				H << "You feel intensely watched."
		sleep(5)
		H << "Your mind snaps!"
		var/objtype = pick(subtypesof(/datum/objective/abductee/))
		var/datum/objective/abductee/O = new objtype()
		ticker.mode.abductees += H.mind
		H.mind.objectives += O
		var/obj_count = 1
		H << "Your current objectives:"
		for(var/datum/objective/objective in H.mind.objectives)
			H << "Objective #[obj_count]: [objective.explanation_text]"
			obj_count++
		ticker.mode.update_abductor_icons_added(H.mind)

		for(var/obj/item/organ/internal/gland/G in H.internal_organs)
			G.Start()
			point_reward++
		if(point_reward > 0)
			open_machine()
			SendBack(H)
			playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
			points += point_reward
			return "Experiment successful! [point_reward] new data-points collected."
		else
			playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
			return "Experiment failed! No replacement organ detected."
	else
		say("Brain activity nonexistant - disposing sample...")
		open_machine()
		SendBack(H)
		return "Specimen braindead - disposed."
	return "ERROR"

/obj/machinery/abductor/experiment/proc/SendBack(mob/living/carbon/human/H)
	H.Sleeping(8)
	if(console && console.pad && console.pad.teleport_target)
		H.forceMove(console.pad.teleport_target)
		H.uncuff()
		return
	//Area not chosen / It's not safe area - teleport to arrivals
	H.forceMove(pick(latejoin))
	H.uncuff()
	return

/obj/machinery/abductor/experiment/update_icon()
	if(state_open)
		icon_state = "experiment-open"
	else
		icon_state = "experiment"


code:
/obj/machinery/abductor/pad
	name = "Alien Telepad"
	desc = "Use this to transport to and from human habitat"
	icon = 'icons/obj/abductor.dmi'
	icon_state = "alien-pad-idle"
	anchored = 1
	var/turf/teleport_target

/obj/machinery/abductor/pad/proc/Warp(mob/living/target)
	target.Move(src.loc)

/obj/machinery/abductor/pad/proc/Send()
	if(teleport_target == null)
		teleport_target = teleportlocs[pick(teleportlocs)]
	flick("alien-pad", src)
	for(var/mob/living/target in loc)
		target.forceMove(teleport_target)
		spawn(0)
			anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)

/obj/machinery/abductor/pad/proc/Retrieve(mob/living/target)
	flick("alien-pad", src)
	spawn(0)
		anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)
	Warp(target)

/obj/machinery/abductor/pad/proc/MobToLoc(place,mob/living/target)
	new/obj/effect/overlay/temp/teleport_abductor(place)
	sleep(80)
	flick("alien-pad", src)
	target.forceMove(place)
	anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)

/obj/machinery/abductor/pad/proc/PadToLoc(place)
	new/obj/effect/overlay/temp/teleport_abductor(place)
	sleep(80)
	flick("alien-pad", src)
	for(var/mob/living/target in src.loc)
		target.forceMove(place)
		spawn(0)
			anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)

/obj/effect/overlay/temp/teleport_abductor
	name = "Huh"
	icon = 'icons/obj/abductor.dmi'
	icon_state = "teleport"
	duration = 80

/obj/effect/overlay/temp/teleport_abductor/New()
	var/datum/effect_system/spark_spread/S = new
	S.set_up(10,0,loc)
	S.start()
	..()


code:
////Deactivated swarmer shell////
/obj/item/unactivated_swarmer
	name = "unactivated swarmer"
	desc = "A currently unactivated swarmer. Swarmers can self activate at any time, it would be wise to immediately dispose of this."
	icon = 'icons/mob/swarmer.dmi'
	icon_state = "swarmer_unactivated"

/obj/item/unactivated_swarmer/New()
	notify_ghosts("An unactivated swarmer has been created in [get_area(src)]!", enter_link = "(Click to enter)", source = src, attack_not_jump = 1)
	..()

/obj/item/unactivated_swarmer/Topic(href, href_list)
	if(href_list["ghostjoin"])
		var/mob/dead/observer/ghost = usr
		if(istype(ghost))
			attack_ghost(ghost)

/obj/item/unactivated_swarmer/attack_ghost(mob/user)
	var/be_swarmer = alert("Become a swarmer? (Warning, You can no longer be cloned!)",,"Yes","No")
	if(be_swarmer == "No")
		return
	if(qdeleted(src))
		user << "Swarmer has been occupied by someone else."
		return
	var/mob/living/simple_animal/hostile/swarmer/S = new /mob/living/simple_animal/hostile/swarmer(get_turf(loc))
	S.key = user.key
	qdel(src)

////The Mob itself////

/mob/living/simple_animal/hostile/swarmer
	name = "Swarmer"
	unique_name = 1
	icon = 'icons/mob/swarmer.dmi'
	desc = "A robot of unknown design, they seek only to consume materials and replicate themselves indefinitely."
	speak_emote = list("tones")
	bubble_icon = "swarmer"
	health = 40
	maxHealth = 40
	status_flags = CANPUSH
	icon_state = "swarmer"
	icon_living = "swarmer"
	icon_dead = "swarmer_unactivated"
	icon_gib = null
	wander = 0
	harm_intent_damage = 5
	minbodytemp = 0
	maxbodytemp = 500
	atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
	unsuitable_atmos_damage = 0
	melee_damage_lower = 15
	melee_damage_upper = 15
	melee_damage_type = STAMINA
	damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
	languages = SWARMER
	environment_smash = 0
	attacktext = "shocks"
	attack_sound = 'sound/effects/EMPulse.ogg'
	friendly = "pinches"
	speed = 0
	faction = list("swarmer")
	AIStatus = AI_OFF
	pass_flags = PASSTABLE
	ventcrawler = 2
	ranged = 1
	projectiletype = /obj/item/projectile/beam/disabler
	ranged_cooldown_time = 20
	projectilesound = 'sound/weapons/taser2.ogg'
	var/resources = 0 //Resource points, generated by consuming metal/glass

/mob/living/simple_animal/hostile/swarmer/Login()
	..()
	src << "You are a swarmer, a weapon of a long dead civilization. Until further orders from your original masters are received, you must continue to consume and replicate."
	src << "Ctrl + Click provides most of your swarmer specific interactions, such as cannibalizing metal or glass, destroying the environment, or teleporting mobs away from you."
	src << "Objectives:"
	src << "1. Consume resources and replicate until there are no more resources left."
	src << "2. Ensure that the station is fit for invasion at a later date, do not perform actions that would render it dangerous or inhospitable."
	src << "3. Biological resources will be harvested at a later date, do not harm them."

/mob/living/simple_animal/hostile/swarmer/New()
	..()
	verbs -= /mob/living/verb/pulled

/mob/living/simple_animal/hostile/swarmer/Stat()
	..()
	if(statpanel("Status"))
		stat("Resources:",resources)

/mob/living/simple_animal/hostile/swarmer/death(gibbed)
	..(gibbed)
	new /obj/effect/decal/cleanable/robot_debris(src.loc)
	new /obj/item/weapon/ore/bluespace_crystal/artificial(src.loc)
	ghostize()
	qdel(src)

/mob/living/simple_animal/hostile/swarmer/emp_act()
	if(health > 1)
		health = 1
		return
	else
		death()

/mob/living/simple_animal/hostile/swarmer/CanPass(atom/movable/O)
	if(istype(O, /obj/item/projectile/beam/disabler))//Allows for swarmers to fight as a group without wasting their shots hitting each other
		return 1
	if(isswarmer(O))
		return 1
	..()

////CTRL CLICK FOR SWARMERS AND SWARMER_ACT()'S////
/mob/living/simple_animal/hostile/swarmer/CtrlClickOn(atom/A)
	face_atom(A)
	if(!isturf(loc))
		return
	if(next_move > world.time)
		return
	if(!A.Adjacent(src))
		return
	A.swarmer_act(src)
	return

/atom/proc/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DisIntegrate(src)

/obj/item/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.Integrate(src)

/obj/item/weapon/gun/swarmer_act()//Stops you from eating the entire armory
	return

/turf/open/floor/swarmer_act()//ex_act() on turf calls it on its contents, this is to prevent attacking mobs by DisIntegrate()'ing the floor
	return

/obj/machinery/atmospherics/swarmer_act()
	return

/obj/structure/disposalpipe/swarmer_act()
	return

/obj/machinery/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DismantleMachine(src)

/obj/machinery/light/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DisIntegrate(src)

/obj/machinery/door/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DisIntegrate(src)

/obj/machinery/camera/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DisIntegrate(src)
	toggle_cam(S, 0)

/obj/machinery/particle_accelerator/control_box/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DisIntegrate(src)

/obj/machinery/field/generator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DisIntegrate(src)

/obj/machinery/gravity_generator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DisIntegrate(src)

/obj/machinery/vending/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)//It's more visually interesting than dismantling the machine
	S.DisIntegrate(src)

/obj/machinery/turretid/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DisIntegrate(src)

/obj/machinery/chem_dispenser/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "The volatile chemicals in this machine would destroy us. Aborting."

/obj/machinery/nuclearbomb/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "This device's destruction would result in the extermination of everything in the area. Aborting."

/obj/machinery/dominator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "This device is attempting to corrupt our entire network; attempting to interact with it is too risky. Aborting."

/obj/effect/decal/cleanable/crayon/gang/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "Searching... sensor malfunction! Target lost. Aborting."

/obj/effect/rune/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "Searching... sensor malfunction! Target lost. Aborting."

/obj/structure/reagent_dispensers/fueltank/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "Destroying this object would cause a chain reaction. Aborting."

/obj/structure/cable/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "Disrupting the power grid would bring no benefit to us. Aborting."

/obj/machinery/portable_atmospherics/canister/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "An inhospitable area may be created as a result of destroying this object. Aborting."

/obj/machinery/telecomms/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "This communications relay should be preserved, it will be a useful resource to our masters in the future. Aborting."

/obj/machinery/message_server/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "This communications relay should be preserved, it will be a useful resource to our masters in the future. Aborting."

/obj/machinery/blackbox_recorder/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "This machine has recorded large amounts of data on this structure and its inhabitants, it will be a useful resource to our masters in the future. Aborting. "

/obj/machinery/power/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "Disrupting the power grid would bring no benefit to us. Aborting."

/obj/machinery/gateway/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "This bluespace source will be important to us later. Aborting."

/turf/closed/wall/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	for(var/turf/T in range(1, src))
		if(istype(T, /turf/open/space) || istype(T.loc, /area/space))
			S << "Destroying this object has the potential to cause a hull breach. Aborting."
			return
	..()

/obj/structure/window/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	for(var/turf/T in range(1, src))
		if(istype(T, /turf/open/space) || istype(T.loc, /area/space))
			S << "Destroying this object has the potential to cause a hull breach. Aborting."
			return
	..()

/obj/item/stack/cable_coil/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)//Wiring would be too effective as a resource
	S << "This object does not contain enough materials to work with."

/obj/machinery/porta_turret/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "Attempting to dismantle this machine would result in an immediate counterattack. Aborting."

/mob/living/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S.DisperseTarget(src)

/mob/living/simple_animal/slime/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "This biological resource is somehow resisting our bluespace transceiver. Aborting."

/obj/machinery/droneDispenser/swarmer/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
	S << "This object is receiving unactivated swarmer shells to help us. Aborting."

////END CTRL CLICK FOR SWARMERS////

/mob/living/simple_animal/hostile/swarmer/proc/Fabricate(var/atom/fabrication_object,var/fabrication_cost = 0)
	if(!isturf(loc))
		src << "This is not a suitable location for fabrication. We need more space."
	if(resources >= fabrication_cost)
		resources -= fabrication_cost
	else
		src << "You do not have the necessary resources to fabricate this object."
		return 0
	new fabrication_object(loc)
	return 1

/mob/living/simple_animal/hostile/swarmer/proc/Integrate(var/obj/item/target)
	if(resources >= 100)
		src << "We cannot hold more materials!"
		return
	if((target.materials[MAT_METAL]) || (target.materials[MAT_GLASS]))
		resources++
		do_attack_animation(target)
		changeNext_move(CLICK_CD_MELEE)
		var/obj/effect/overlay/temp/swarmer/integrate/I = PoolOrNew(/obj/effect/overlay/temp/swarmer/integrate, get_turf(target))
		I.pixel_x = target.pixel_x
		I.pixel_y = target.pixel_y
		I.pixel_z = target.pixel_z
		if(istype(target, /obj/item/stack))
			var/obj/item/stack/S = target
			S.use(1)
			if(S.amount)
				return
		qdel(target)
	else
		src << "\the [target] is incompatible with our internal matter recycler."
		return

/mob/living/simple_animal/hostile/swarmer/proc/DisIntegrate(var/atom/movable/target)
	PoolOrNew(/obj/effect/overlay/temp/swarmer/disintegration, get_turf(target))
	do_attack_animation(target)
	changeNext_move(CLICK_CD_MELEE)
	target.ex_act(3)
	return

/mob/living/simple_animal/hostile/swarmer/proc/DisperseTarget(var/mob/living/target)
	if(target != src)
		src << "Attempting to remove this being from our presence."
		if(src.z != ZLEVEL_STATION)
			src << "Our bluespace transceiver cannot locate a viable bluespace link, our teleportation abilities are useless in this area."
			return
		if(do_mob(src, target, 30))
			var/cycle
			for(cycle=0,cycle<100,cycle++)
				var/random_location = locate(rand(37,202),rand(75,192),ZLEVEL_STATION)//Drunk dial a turf in the general ballpark of the station
				if(istype(random_location, /turf/open/floor))
					var/turf/open/floor/F = random_location
					if(F.air)
						var/datum/gas_mixture/A = F.air
						var/list/A_gases = A.gases
						var/trace_gases
						for(var/id in A_gases)
							if(id in hardcoded_gases)
								continue
							trace_gases = TRUE
							break
						if((A_gases["o2"] && A_gases["o2"][MOLES] >= 16) && !A_gases["plasma"] && (!A_gases["co2"] || A_gases["co2"][MOLES] < 10) && !trace_gases)//Can most things breathe in this location?
							if((A.temperature > 270) && (A.temperature < 360))//Not too hot, not too cold
								var/pressure = A.return_pressure()
								if((pressure > 20) && (pressure < 550))//Account for crushing pressure or vaccuums
									if(ishuman(target))//If we're getting rid of a human, slap some zipties on them to keep them away from us a little longer
										var/obj/item/weapon/restraints/handcuffs/cable/zipties/Z = new /obj/item/weapon/restraints/handcuffs/cable/zipties(src)
										var/mob/living/carbon/human/H = target
										Z.apply_cuffs(H, src)
									do_teleport(target, F, 0)
									playsound(src,'sound/effects/sparks4.ogg',50,1)
									break
			return

/mob/living/simple_animal/hostile/swarmer/proc/DismantleMachine(var/obj/machinery/target)
	do_attack_animation(target)
	src << "We begin to dismantle this machine. We will need to be uninterrupted."
	var/obj/effect/overlay/temp/swarmer/dismantle/D = PoolOrNew(/obj/effect/overlay/temp/swarmer/dismantle, get_turf(target))
	D.pixel_x = target.pixel_x
	D.pixel_y = target.pixel_y
	D.pixel_z = target.pixel_z
	if(do_mob(src, target, 100))
		src << "Dismantling complete."
		var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal(target.loc)
		M.amount = 5
		for(var/obj/item/I in target.component_parts)
			I.loc = M.loc
		var/obj/effect/overlay/temp/swarmer/disintegration/N = PoolOrNew(/obj/effect/overlay/temp/swarmer/disintegration, get_turf(target))
		N.pixel_x = target.pixel_x
		N.pixel_y = target.pixel_y
		N.pixel_z = target.pixel_z
		target.dropContents()
		if(istype(target, /obj/machinery/computer))
			var/obj/machinery/computer/C = target
			if(C.circuit)
				C.circuit.loc = M.loc
		qdel(target)

/obj/effect/swarmer //Default swarmer effect object visual feedback
	name = "swarmer ui"
	desc = null
	gender = NEUTER
	icon = 'icons/mob/swarmer.dmi'
	icon_state = "ui_light"
	mouse_opacity = 0
	layer = MOB_LAYER
	unacidable = 1

/obj/effect/overlay/temp/swarmer //temporary swarmer visual feedback objects
	icon = 'icons/mob/swarmer.dmi'
	layer = MOB_LAYER

/obj/effect/overlay/temp/swarmer/disintegration
	icon_state = "disintegrate"
	duration = 10

/obj/effect/overlay/temp/swarmer/disintegration/New()
	playsound(src.loc, "sparks", 100, 1)
	..()

/obj/effect/overlay/temp/swarmer/dismantle
	icon_state = "dismantle"
	duration = 25

/obj/effect/overlay/temp/swarmer/integrate
	icon_state = "integrate"
	duration = 5

/obj/effect/swarmer/destructible //Default destroyable object for swarmer constructions
	luminosity = 1
	mouse_opacity = 1
	var/health = 30

/obj/effect/swarmer/destructible/proc/TakeDamage(damage)
	health -= damage
	if(health <= 0)
		qdel(src)

/obj/effect/swarmer/destructible/bullet_act(obj/item/projectile/Proj)
	if(Proj.damage)
		if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
			TakeDamage(Proj.damage)
	..()

/obj/effect/swarmer/destructible/attackby(obj/item/weapon/I, mob/living/user, params)
	if(istype(I, /obj/item/weapon))
		user.changeNext_move(CLICK_CD_MELEE)
		user.do_attack_animation(src)
		TakeDamage(I.force)
	return

/obj/effect/swarmer/destructible/ex_act()
	qdel(src)
	return

/obj/effect/swarmer/destructible/blob_act()
	qdel(src)
	return

/obj/effect/swarmer/destructible/emp_act()
	qdel(src)
	return

/obj/effect/swarmer/destructible/attack_animal(mob/living/user)
	if(isanimal(user))
		var/mob/living/simple_animal/S = user
		S.do_attack_animation(src)
		user.changeNext_move(CLICK_CD_MELEE)
		if(S.melee_damage_type == BRUTE || S.melee_damage_type == BURN)
			TakeDamage(rand(S.melee_damage_lower, S.melee_damage_upper))
	return

/mob/living/simple_animal/hostile/swarmer/proc/CreateTrap()
	set name = "Create trap"
	set category = "Swarmer"
	set desc = "Creates a simple trap that will non-lethally electrocute anything that steps on it. Costs 5 resources"
	if(/obj/effect/swarmer/destructible/trap in loc)
		src << "There is already a trap here. Aborting."
		return
	Fabricate(/obj/effect/swarmer/destructible/trap, 5)
	return

/obj/effect/swarmer/destructible/trap
	name = "swarmer trap"
	desc = "A quickly assembled trap that electrifies living beings and overwhelms machine sensors. Will not retain its form if damaged enough."
	icon_state = "trap"
	luminosity = 1
	health = 10

/obj/effect/swarmer/destructible/trap/Crossed(var/atom/movable/AM)
	if(isliving(AM))
		var/mob/living/L = AM
		if(!istype(L, /mob/living/simple_animal/hostile/swarmer))
			playsound(loc,'sound/effects/snap.ogg',50, 1, -1)
			L.electrocute_act(0, src, 1, 1)
			if(isrobot(L))
				L.Weaken(5)
			qdel(src)
	..()

/mob/living/simple_animal/hostile/swarmer/proc/CreateBarricade()
	set name = "Create barricade"
	set category = "Swarmer"
	set desc = "Creates a barricade that will stop anything but swarmers and disabler beams from passing through."
	if(/obj/effect/swarmer/destructible/blockade in loc)
		src << "There is already a blockade here. Aborting."
		return
	if(resources < 5)
		src << "We do not have the resources for this!"
		return
	if(do_mob(src, src, 10))
		Fabricate(/obj/effect/swarmer/destructible/blockade, 5)
	return

/obj/effect/swarmer/destructible/blockade
	name = "swarmer blockade"
	desc = "A quickly assembled energy blockade. Will not retain its form if damaged enough, but disabler beams and swarmers pass right through."
	icon_state = "barricade"
	luminosity = 1
	health = 50
	density = 1
	anchored = 1

/obj/effect/swarmer/destructible/blockade/CanPass(atom/movable/O)
	if(isswarmer(O))
		return 1
	if(istype(O, /obj/item/projectile/beam/disabler))
		return 1

/mob/living/simple_animal/hostile/swarmer/proc/CreateSwarmer()
	set name = "Replicate"
	set category = "Swarmer"
	set desc = "Creates a shell for a new swarmer. Swarmers will self activate."
	src << "We are attempting to replicate ourselves. We will need to stand still until the process is complete."
	if(resources < 50)
		src << "We do not have the resources for this!"
		return
	if(!isturf(loc))
		src << "This is not a suitable location for replicating ourselves. We need more room."
		return
	if(do_mob(src, src, 100))
		if(Fabricate(/obj/item/unactivated_swarmer, 50))
			playsound(loc,'sound/items/poster_being_created.ogg',50, 1, -1)

/mob/living/simple_animal/hostile/swarmer/proc/RepairSelf()
	set name = "Self Repair"
	set category = "Swarmer"
	set desc = "Attempts to repair damage to our body. You will have to remain motionless until repairs are complete."
	if(!isturf(loc))
		return
	src << "Attempting to repair damage to our body, stand by..."
	if(do_mob(src, src, 100))
		adjustHealth(-100)
		src << "We successfully repaired ourselves."

/mob/living/simple_animal/hostile/swarmer/proc/ToggleLight()
	if(!luminosity)
		SetLuminosity(3)
	else
		SetLuminosity(0)

/mob/living/simple_animal/hostile/swarmer/proc/ContactSwarmers()
	var/message = input(src, "Announce to other swarmers", "Swarmer contact")
	var/rendered = "Swarm communication -  [src] states: [message]"
	if(message)
		for(var/mob/M in mob_list)
			if(isswarmer(M))
				M << rendered
			if(M in dead_mob_list)
				M << "(F) [rendered]"


code:
/datum/round_event_control/spawn_swarmer
	name = "Spawn Swarmer Shell"
	typepath = /datum/round_event/spawn_swarmer
	weight = 7
	max_occurrences = 1 //Only once okay fam
	earliest_start = 18000 //30 minutes
	min_players = 15

/datum/round_event/spawn_swarmer

/datum/round_event/spawn_swarmer/start()
	if(find_swarmer())
		return 0
	if(!the_gateway)
		return 0
	new /obj/item/unactivated_swarmer(get_turf(the_gateway))
	if(prob(25)) //25% chance to announce it to the crew
		var/swarmer_report = "[command_name()] High-Priority Update"
		swarmer_report += "

Our long-range sensors have detected an odd signal emanating from your station's gateway. We recommend immediate investigation of your gateway, as something may have come \
		through."
		print_command_report(swarmer_report,"Classified [command_name()] Update")
		priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg')

/datum/round_event/spawn_swarmer/proc/find_swarmer()
	for(var/mob/living/M in mob_list)
		if(istype(M, /mob/living/simple_animal/hostile/swarmer) && M.client) //If there is a swarmer with an active client, we've found our swarmer
			return 1
	return 0


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

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

	required_players = 20
	required_enemies = 1
	recommended_enemies = 1

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

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

	var/monkeys_to_win = 0
	var/escaped_monkeys = 0

	var/players_per_carrier = 30

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

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

	if(!carriers.len)
		return 0
	return 1

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

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

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

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

/datum/game_mode/monkey/check_finished()
	if(SSshuttle.emergency.mode >= SHUTTLE_ENDGAME || station_was_nuked)
		return 1

	if(!round_converted)
		for(var/datum/mind/monkey_mind in ape_infectees)
			continuous_sanity_checked = 1
			if(monkey_mind.current && monkey_mind.current.stat != DEAD)
				return 0

		var/datum/disease/D = new /datum/disease/transformation/jungle_fever() //ugly but unfortunately needed
		for(var/mob/living/carbon/human/H in living_mob_list)
			if(H.mind && H.stat != DEAD)
				if(H.HasDisease(D))
					return 0

	..()

/datum/game_mode/monkey/proc/check_monkey_victory()
	if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
		return 0
	var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
	for(var/mob/living/carbon/monkey/M in living_mob_list)
		if (M.HasDisease(D))
			if(M.onCentcom() || M.onSyndieBase())
				escaped_monkeys++
	if(escaped_monkeys >= monkeys_to_win)
		return 1
	else
		return 0

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

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

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


code:
#define MORPH_COOLDOWN 50

/mob/living/simple_animal/hostile/morph
	name = "morph"
	real_name = "morph"
	desc = "A revolting, pulsating pile of flesh."
	speak_emote = list("gurgles")
	emote_hear = list("gurgles")
	icon = 'icons/mob/animal.dmi'
	icon_state = "morph"
	icon_living = "morph"
	icon_dead = "morph_dead"
	speed = 2
	a_intent = "harm"
	stop_automated_movement = 1
	status_flags = CANPUSH
	pass_flags = PASSTABLE
	ventcrawler = 2
	atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
	minbodytemp = 0
	maxHealth = 150
	health = 150
	healable = 0
	environment_smash = 1
	melee_damage_lower = 20
	melee_damage_upper = 20
	see_in_dark = 8
	see_invisible = SEE_INVISIBLE_MINIMUM
	idle_vision_range = 1 // Only attack when target is close
	wander = 0
	attacktext = "glomps"
	attack_sound = 'sound/effects/blobattack.ogg'
	butcher_results = list(/obj/item/weapon/reagent_containers/food/snacks/meat/slab = 2)

	var/morphed = 0
	var/atom/movable/form = null
	var/morph_time = 0

	var/playstyle_string = "You are a morph, an abomination of science created primarily with changeling cells. \
							You may take the form of anything nearby by shift-clicking it. This process will alert any nearby \
							observers, and can only be performed once every five seconds. While morphed, you move faster, but do \
							less damage. In addition, anyone within three tiles will note an uncanny wrongness if examining you. \
							You can attack any item or dead creature to consume it - creatures will fully restore your health. \
							Finally, you can restore yourself to your original form while morphed by shift-clicking yourself."

/mob/living/simple_animal/hostile/morph/examine(mob/user)
	if(morphed)
		form.examine(user) // Refactor examine to return desc so it's static? Not sure if worth it
		if(get_dist(user,src)<=3)
			user << "It doesn't look quite right..."
	else
		..()
	return

/mob/living/simple_animal/hostile/morph/proc/allowed(atom/movable/A) // make it into property/proc ? not sure if worth it
	if(istype(A,/obj/screen))
		return 0
	if(istype(A,/obj/singularity))
		return 0
	if(istype(A,/mob/living/simple_animal/hostile/morph))
		return 0
	return 1

/mob/living/simple_animal/hostile/morph/proc/eat(atom/movable/A)
	if(A && A.loc != src)
		visible_message("[src] swallows [A] whole!")
		A.loc = src
		return 1
	return 0

/mob/living/simple_animal/hostile/morph/ShiftClickOn(atom/movable/A)
	if(morph_time <= world.time && !stat)
		if(A == src)
			restore()
			return
		if(istype(A) && allowed(A))
			assume(A)
	else
		src << "Your chameleon skin is still repairing itself!"
		..()

/mob/living/simple_animal/hostile/morph/proc/assume(atom/movable/target)
	morphed = 1
	form = target

	visible_message("[src] suddenly twists and changes shape, becoming a copy of [target]!", \
					"You twist your body and assume the form of [target].")
	appearance = target.appearance
	transform = initial(transform)
	pixel_y = initial(pixel_y)
	pixel_x = initial(pixel_x)

	//Morphed is weaker
	melee_damage_lower = 5
	melee_damage_upper = 5
	speed = 0

	morph_time = world.time + MORPH_COOLDOWN
	return

/mob/living/simple_animal/hostile/morph/proc/restore()
	if(!morphed)
		return
	morphed = 0
	form = null
	alpha = initial(alpha)

	//anim(loc,src,'icons/mob/mob.dmi',,"morph",,src.dir)

	visible_message("[src] suddenly collapses in on itself, dissolving into a pile of green flesh!", \
					"You reform to your normal body.")
	name = initial(name)
	icon = initial(icon)
	icon_state = initial(icon_state)
	overlays.Cut()

	//Baseline stats
	melee_damage_lower = initial(melee_damage_lower)
	melee_damage_upper = initial(melee_damage_upper)
	speed = initial(speed)

	morph_time = world.time + MORPH_COOLDOWN

/mob/living/simple_animal/hostile/morph/death(gibbed)
	if(morphed)
		visible_message("[src] twists and dissolves into a pile of green flesh!", \
						"Your skin ruptures! Your flesh breaks apart! No disguise can ward off de--")
		restore()
	if(gibbed)
		for(var/atom/movable/AM in src)
			AM.loc = loc
			if(prob(90))
				step(AM, pick(alldirs))
	..(gibbed)

/mob/living/simple_animal/hostile/morph/Aggro() // automated only
	..()
	restore()

/mob/living/simple_animal/hostile/morph/LoseAggro()
	vision_range = idle_vision_range

/mob/living/simple_animal/hostile/morph/AIShouldSleep(var/list/possible_targets)
	. = ..()
	if(.)
		var/list/things = list()
		for(var/atom/movable/A in view(src))
			if(allowed(A))
				things += A
		var/atom/movable/T = pick(things)
		assume(T)

/mob/living/simple_animal/hostile/morph/can_track(mob/living/user)
	if(morphed)
		return 0
	return ..()

/mob/living/simple_animal/hostile/morph/AttackingTarget()
	if(isliving(target)) // Eat Corpses to regen health
		var/mob/living/L = target
		if(L.stat == DEAD)
			if(do_after(src, 30, target = L))
				if(eat(L))
					adjustHealth(-50)
			return
	else if(istype(target,/obj/item)) // Eat items just to be annoying
		var/obj/item/I = target
		if(!I.anchored)
			if(do_after(src,20, target = I))
				eat(I)
			return
	target.attack_animal(src)

//Spawn Event

/datum/round_event_control/morph
	name = "Spawn Morph"
	typepath = /datum/round_event/morph
	weight = 0 //Admin only
	max_occurrences = 1

/datum/round_event/morph
	var/key_of_morph

/datum/round_event/morph/proc/get_morph(end_if_fail = 0)
	key_of_morph = null
	if(!key_of_morph)
		var/list/candidates = get_candidates(ROLE_ALIEN)
		if(!candidates.len)
			if(end_if_fail)
				return 0
			return find_morph()
		var/client/C = pick(candidates)
		key_of_morph = C.key
	if(!key_of_morph)
		if(end_if_fail)
			return 0
		return find_morph()
	var/datum/mind/player_mind = new /datum/mind(key_of_morph)
	player_mind.active = 1
	if(!xeno_spawn)
		return find_morph()
	var/mob/living/simple_animal/hostile/morph/S = new /mob/living/simple_animal/hostile/morph(pick(xeno_spawn))
	player_mind.transfer_to(S)
	player_mind.assigned_role = "Morph"
	player_mind.special_role = "Morph"
	ticker.mode.traitors |= player_mind
	S << S.playstyle_string
	S << 'sound/magic/Mutate.ogg'
	message_admins("[key_of_morph] has been made into morph by an event.")
	log_game("[key_of_morph] was spawned as a morph by an event.")
	return 1

/datum/round_event/morph/start()
	get_morph()

/datum/round_event/morph/proc/find_morph()
	message_admins("Attempted to spawn a morph but there was no players available. Will try again momentarily.")
	spawn(50)
		if(get_morph(1))
			message_admins("Situation has been resolved, [key_of_morph] has been spawned as a morph.")
			log_game("[key_of_morph] was spawned as a morph by an event.")
			return 0
		message_admins("Unfortunately, no candidates were available for becoming a morph. Shutting down.")
	return kill()


code:
This folder contains all "mini-antagonists" - antagonists that can still spice up the round but aren't enough to be a roundtype in their own right.
Currently, that list consists of:
	-Abductors
	-Swarmers
	-The Jungle Fever virus (infected monkey bites human, human becomes another infected monkey)
	-Morphs
	-Revenants
	-Slaughter demons
Please update this if you add another mini-antagonist.


code:
//Revenants: based off of wraiths from Goon
//"Ghosts" that are invisible and move like ghosts, cannot take damage while invisible
//Don't hear deadchat and are NOT normal ghosts
//Admin-spawn or random event

#define INVISIBILITY_REVENANT 50

/mob/living/simple_animal/revenant
	name = "revenant"
	desc = "A malevolent spirit."
	icon = 'icons/mob/mob.dmi'
	icon_state = "revenant_idle"
	var/icon_idle = "revenant_idle"
	var/icon_reveal = "revenant_revealed"
	var/icon_stun = "revenant_stun"
	var/icon_drain = "revenant_draining"
	incorporeal_move = 3
	invisibility = INVISIBILITY_REVENANT
	health = INFINITY //Revenants don't use health, they use essence instead
	maxHealth = INFINITY
	layer = 5
	healable = 0
	sight = SEE_SELF
	see_invisible = SEE_INVISIBLE_NOLIGHTING
	see_in_dark = 8
	languages = ALL
	response_help   = "passes through"
	response_disarm = "swings through"
	response_harm   = "punches through"
	unsuitable_atmos_damage = 0
	damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway.
	atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
	minbodytemp = 0
	maxbodytemp = INFINITY
	harm_intent_damage = 0
	friendly = "touches"
	status_flags = 0
	wander = 0
	density = 0
	flying = 1
	anchored = 1
	mob_size = MOB_SIZE_TINY
	pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
	speed = 0
	unique_name = 1

	var/essence = 75 //The resource, and health, of revenants.
	var/essence_regen_cap = 75 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
	var/essence_regenerating = 1 //If the revenant regenerates essence or not; 1 for yes, 0 for no
	var/essence_regen_amount = 5 //How much essence regenerates
	var/essence_accumulated = 0 //How much essence the revenant has stolen
	var/revealed = 0 //If the revenant can take damage from normal sources.
	var/unreveal_time = 0 //How long the revenant is revealed for, is about 2 seconds times this var.
	var/unstun_time = 0 //How long the revenant is stunned for, is about 2 seconds times this var.
	var/inhibited = 0 //If the revenant's abilities are blocked by a chaplain's power.
	var/essence_drained = 0 //How much essence the revenant will drain from the corpse it's feasting on.
	var/draining = 0 //If the revenant is draining someone.
	var/list/drained_mobs = list() //Cannot harvest the same mob twice
	var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has. //TODO, add objective for getting a perfect soul(s?)
	var/image/ghostimage = null //Visible to ghost with darkness off

/mob/living/simple_animal/revenant/New()
	..()

	ghostimage = image(src.icon,src,src.icon_state)
	ghost_darkness_images |= ghostimage
	updateallghostimages()

	spawn(5)
		if(src.mind)
			src.mind.remove_all_antag()
			src.mind.wipe_memory()
			src << 'sound/effects/ghost.ogg'
			src << "
"
			src << "You are a revenant."
			src << "Your formerly mundane spirit has been infused with alien energies and empowered into a revenant."
			src << "You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds."
			src << "You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable."
			src << "To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities."
			src << "You do not remember anything of your past lives, nor will you remember anything about this one after your death."
			src << "Be sure to read the wiki page at https://tgstation13.org/wiki/Revenant to learn more."
			var/datum/objective/revenant/objective = new
			objective.owner = src.mind
			src.mind.objectives += objective
			src << "Objective #1: [objective.explanation_text]"
			var/datum/objective/revenantFluff/objective2 = new
			objective2.owner = src.mind
			src.mind.objectives += objective2
			src << "Objective #2: [objective2.explanation_text]"
			ticker.mode.traitors |= src.mind //Necessary for announcing
		AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
		AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
		AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
		AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/overload(null))
		AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction(null))
		AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/blight(null))

//Life, Stat, Hud Updates, and Say
/mob/living/simple_animal/revenant/Life()
	if(revealed && essence <= 0)
		death()
	if(unreveal_time && world.time >= unreveal_time)
		unreveal_time = 0
		revealed = 0
		incorporeal_move = 3
		invisibility = INVISIBILITY_REVENANT
		src << "You are once more concealed."
	if(unstun_time && world.time >= unstun_time)
		unstun_time = 0
		notransform = 0
		src << "You can move again!"
	if(essence_regenerating && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate
		essence = min(essence_regen_cap, essence+essence_regen_amount)
		update_action_buttons_icon() //because we update something required by our spells in life, we need to update our buttons
	update_spooky_icon()
	update_health_hud()
	..()

/mob/living/simple_animal/revenant/Stat()
	..()
	if(statpanel("Status"))
		stat(null, "Current essence: [essence]/[essence_regen_cap]E")
		stat(null, "Stolen essence: [essence_accumulated]E")
		stat(null, "Stolen perfect souls: [perfectsouls]")

/mob/living/simple_animal/revenant/update_health_hud()
	if(hud_used)
		var/essencecolor = "#8F48C6"
		if(essence > essence_regen_cap)
			essencecolor = "#9A5ACB" //oh boy you've got a lot of essence
		else if(essence == 0)
			essencecolor = "#1D2953" //oh jeez you're dying
		hud_used.healths.maptext = "
[essence]E
"

/mob/living/simple_animal/revenant/say(message)
	if(!message)
		return
	log_say("[key_name(src)] : [message]")
	var/rendered = "[src] says, \"[message]\""
	for(var/mob/M in mob_list)
		if(istype(M, /mob/living/simple_animal/revenant))
			M << rendered
		if(isobserver(M))
			M << "(F) [rendered]"
	return

//Immunities
/mob/living/simple_animal/revenant/Process_Spacemove(movement_dir = 0)
	return 1

/mob/living/simple_animal/revenant/ex_act(severity, target)
	return 1 //Immune to the effects of explosions.

/mob/living/simple_animal/revenant/blob_act()
	return //blah blah blobs aren't in tune with the spirit world, or something.

/mob/living/simple_animal/revenant/singularity_act()
	return //don't walk into the singularity expecting to find corpses, okay?

/mob/living/simple_animal/revenant/narsie_act()
	return //most humans will now be either bones or harvesters, but we're still un-alive.

//damage, gibbing, and dying
/mob/living/simple_animal/revenant/attackby(obj/item/W, mob/living/user, params)
	if(istype(W, /obj/item/weapon/nullrod))
		visible_message("[src] violently flinches!", \
						"As \the [W] passes through you, you feel your essence draining away!")
		adjustBruteLoss(25) //hella effective
		inhibited = 1
		update_action_buttons_icon()
		spawn(30)
			inhibited = 0
			update_action_buttons_icon()
	..()

/mob/living/simple_animal/revenant/adjustHealth(amount)
	if(!revealed)
		return 0
	. = amount
	essence = max(0, essence-amount)
	update_health_hud()
	if(essence == 0)
		src << "You feel your essence fraying!"

/mob/living/simple_animal/revenant/dust()
	death()

/mob/living/simple_animal/revenant/gib()
	death()

/mob/living/simple_animal/revenant/death()
	if(!revealed || stat == DEAD) //Revenants cannot die if they aren't revealed //or are already dead
		return 0
	..(1)
	ghost_darkness_images -= ghostimage
	updateallghostimages()
	src << "NO! No... it's too late, you can feel your essence [pick("breaking apart", "drifting away")]..."
	notransform = 1
	revealed = 1
	invisibility = 0
	playsound(src, 'sound/effects/screech.ogg', 100, 1)
	visible_message("[src] lets out a waning screech as violet mist swirls around its dissolving body!")
	icon_state = "revenant_draining"
	for(var/i = alpha, i > 0, i -= 10)
		stoplag()
		alpha = i
	visible_message("[src]'s body breaks apart into a fine pile of blue dust.")
	var/reforming_essence = essence_regen_cap //retain the gained essence capacity
	var/obj/item/weapon/ectoplasm/revenant/R = new(get_turf(src))
	R.essence = max(reforming_essence - 15 * perfectsouls, 75) //minus any perfect souls
	R.client_to_revive = src.client //If the essence reforms, the old revenant is put back in the body
	ghostize()
	qdel(src)
	return

//reveal, stun, icon updates, cast checks, and essence changing
/mob/living/simple_animal/revenant/proc/reveal(time)
	if(!src)
		return
	if(time <= 0)
		return
	revealed = 1
	invisibility = 0
	incorporeal_move = 0
	if(!unreveal_time)
		src << "You have been revealed!"
		unreveal_time = world.time + time
	else
		src << "You have been revealed!"
		unreveal_time = unreveal_time + time
	update_spooky_icon()

/mob/living/simple_animal/revenant/proc/stun(time)
	if(!src)
		return
	if(time <= 0)
		return
	notransform = 1
	if(!unstun_time)
		src << "You cannot move!"
		unstun_time = world.time + time
	else
		src << "You cannot move!"
		unstun_time = unstun_time + time
	update_spooky_icon()

/mob/living/simple_animal/revenant/proc/update_spooky_icon()
	if(revealed)
		if(notransform)
			if(draining)
				icon_state = icon_drain
			else
				icon_state = icon_stun
		else
			icon_state = icon_reveal
	else
		icon_state = icon_idle
	if(ghostimage)
		ghostimage.icon_state = src.icon_state
		updateallghostimages()

/mob/living/simple_animal/revenant/proc/castcheck(essence_cost)
	if(!src)
		return
	var/turf/T = get_turf(src)
	if(istype(T, /turf/closed/wall))
		src << "You cannot use abilities from inside of a wall."
		return 0
	if(src.inhibited)
		src << "Your powers have been suppressed by nulling energy!"
		return 0
	if(!src.change_essence_amount(essence_cost, 1))
		src << "You lack the essence to use that ability."
		return 0
	return 1

/mob/living/simple_animal/revenant/proc/change_essence_amount(essence_amt, silent = 0, source = null)
	if(!src)
		return
	if(essence + essence_amt <= 0)
		return
	essence = max(0, essence+essence_amt)
	update_action_buttons_icon()
	update_health_hud()
	if(essence_amt > 0)
		essence_accumulated = max(0, essence_accumulated+essence_amt)
	if(!silent)
		if(essence_amt > 0)
			src << "Gained [essence_amt]E from [source]."
		else
			src << "Lost [essence_amt]E from [source]."
	return 1

//reforming
/obj/item/weapon/ectoplasm/revenant
	name = "glimmering residue"
	desc = "A pile of fine blue dust. Small tendrils of violet mist swirl around it."
	icon = 'icons/effects/effects.dmi'
	icon_state = "revenantEctoplasm"
	w_class = 2
	var/essence = 75 //the maximum essence of the reforming revenant
	var/reforming = 1
	var/inert = 0
	var/client/client_to_revive

/obj/item/weapon/ectoplasm/revenant/New()
	..()
	spawn(600) //1 minute
		if(src && reforming)
			reforming = 0
			return reform()
		else
			inert = 1
			visible_message("[src] settles down and seems lifeless.")
			return

/obj/item/weapon/ectoplasm/revenant/attack_self(mob/user)
	if(!reforming || inert)
		return ..()
	user.visible_message("[user] scatters [src] in all directions.", \
						 "You scatter [src] across the area. The particles slowly fade away.")
	user.drop_item()
	qdel(src)

/obj/item/weapon/ectoplasm/revenant/throw_impact(atom/hit_atom)
	..()
	if(inert)
		return
	visible_message("[src] breaks into particles upon impact, which fade away to nothingness.")
	qdel(src)

/obj/item/weapon/ectoplasm/revenant/examine(mob/user)
	..()
	if(inert)
		user << "It seems inert."
	else if(reforming)
		user << "It is shifting and distorted. It would be wise to destroy this."

/obj/item/weapon/ectoplasm/revenant/proc/reform()
	if(!src || qdeleted(src) || inert)
		return
	var/key_of_revenant
	message_admins("Revenant ectoplasm was left undestroyed for 1 minute and is reforming into a new revenant.")
	loc = get_turf(src) //In case it's in a backpack or someone's hand
	var/mob/living/simple_animal/revenant/R = new(get_turf(src))
	if(client_to_revive)
		for(var/mob/M in dead_mob_list)
			if(M.client == client_to_revive) //Only recreates the mob if the mob the client is in is dead
				R.client = client_to_revive
				key_of_revenant = client_to_revive.key
	if(!key_of_revenant)
		message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...")
		var/list/candidates = get_candidates(ROLE_REVENANT)
		if(!candidates.len)
			qdel(R)
			message_admins("No candidates were found for the new revenant. Oh well!")
			inert = 1
			visible_message("[src] settles down and seems lifeless.")
			return 0
		var/client/C = pick(candidates)
		key_of_revenant = C.key
		if(!key_of_revenant)
			qdel(R)
			message_admins("No ckey was found for the new revenant. Oh well!")
			inert = 1
			visible_message("[src] settles down and seems lifeless.")
			return 0
	var/datum/mind/player_mind = new /datum/mind(key_of_revenant)
	R.essence_regen_cap = essence
	R.essence = R.essence_regen_cap
	player_mind.active = 1
	player_mind.transfer_to(R)
	player_mind.assigned_role = "revenant"
	player_mind.special_role = "Revenant"
	ticker.mode.traitors |= player_mind
	message_admins("[key_of_revenant] has been [client_to_revive ? "re":""]made into a revenant by reforming ectoplasm.")
	log_game("[key_of_revenant] was [client_to_revive ? "re":""]made as a revenant by reforming ectoplasm.")
	visible_message("[src] suddenly rises into the air before fading away.")
	qdel(src)
	if(src) //Should never happen, but just in case
		inert = 1
	return 1

//objectives
/datum/objective/revenant
	dangerrating = 10
	var/targetAmount = 100

/datum/objective/revenant/New()
	targetAmount = rand(350,600)
	explanation_text = "Absorb [targetAmount] points of essence from humans."
	..()

/datum/objective/revenant/check_completion()
	if(!istype(owner.current, /mob/living/simple_animal/revenant))
		return 0
	var/mob/living/simple_animal/revenant/R = owner.current
	if(!R || R.stat == DEAD)
		return 0
	var/essence_stolen = R.essence_accumulated
	if(essence_stolen < targetAmount)
		return 0
	return 1

/datum/objective/revenantFluff
	dangerrating = 0

/datum/objective/revenantFluff/New()
	var/list/explanationTexts = list("Assist and exacerbate existing threats at critical moments.", \
									 "Avoid killing in plain sight.", \
									 "Cause as much chaos and anger as you can without being killed.", \
									 "Damage and render as much of the station rusted and unusable as possible.", \
									 "Disable and cause malfunctions in as many machines as possible.", \
									 "Ensure that any holy weapons are rendered unusable.", \
									 "Hinder the crew while attempting to avoid being noticed.", \
									 "Make the crew as miserable as possible.", \
									 "Make the clown as miserable as possible.", \
									 "Make the captain as miserable as possible.", \
									 "Prevent the use of energy weapons where possible.")
	explanation_text = pick(explanationTexts)
	..()

/datum/objective/revenantFluff/check_completion()
	return 1