code:
//original code and idea from Alfie275 (luna era) and ISaidNo (goonservers) - with thanks

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Xenoarchaeological finds

/datum/find
	var/find_type = 0				//random according to the digsite type
	var/excavation_required = 0		//random 5-95%
	var/view_range = 20				//how close excavation has to come to show an overlay on the turf
	var/clearance_range = 3			//how close excavation has to come to extract the item
									//if excavation hits var/excavation_required exactly, it's contained find is extracted cleanly without the ore
	var/prob_delicate = 90			//probability it requires an active suspension field to not insta-crumble
	var/dissonance_spread = 1		//proportion of the tile that is affected by this find
									//used in conjunction with analysis machines to determine correct suspension field type

/datum/find/New(var/digsite, var/exc_req)
	excavation_required = exc_req
	find_type = get_random_find_type(digsite)
	clearance_range = rand(2,6)
	dissonance_spread = rand(1500,2500) / 100

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Strange rocks

//have all strange rocks be cleared away using welders for now
/obj/item/weapon/strangerock
	name = "Strange rock"
	desc = "Seems to have some unusal strata evident throughout it."
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "strange"
	var/obj/item/weapon/inside
	var/method = 0// 0 = fire, 1 = brush, 2 = pick
	var/datum/geosample/geologic_data
	origin_tech = "materials=5"

/obj/item/weapon/strangerock/New(loc, var/inside_item_type = 0)
	..(loc)

	//method = rand(0,2)
	if(inside_item_type)
		inside = new/obj/item/weapon/archaeological_find(src, new_item_type = inside_item_type)
		if(!inside)
			inside = locate() in contents

/*/obj/item/weapon/strangerock/ex_act(var/severity)
	if(severity && prob(30))
		src.visible_message("The [src] crumbles away, leaving some dust and gravel behind.")*/

/obj/item/weapon/strangerock/attackby(obj/item/weapon/W as obj, mob/user as mob)
	if(istype(W,/obj/item/weapon/weldingtool/))
		var/obj/item/weapon/weldingtool/w = W
		if(w.isOn())
			if(w.get_fuel() >= 4 && !src.method)
				if(inside)
					inside.loc = get_turf(src)
					for(var/mob/M in viewers(world.view, user))
						M.show_message("[src] burns away revealing [inside].",1)
				else
					for(var/mob/M in viewers(world.view, user))
						M.show_message("[src] burns away into nothing.",1)
				qdel(src)
				w.remove_fuel(4)
			else
				for(var/mob/M in viewers(world.view, user))
					M.show_message("A few sparks fly off [src], but nothing else happens.",1)
				w.remove_fuel(1)
			return

	else if(istype(W,/obj/item/device/core_sampler/))
		var/obj/item/device/core_sampler/S = W
		S.sample_item(src, user)
		return

	..()
	if(prob(33))
		src.visible_message("[src] crumbles away, leaving some dust and gravel behind.")
		qdel(src)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Archaeological finds

/obj/item/weapon/archaeological_find
	name = "object"
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "ano01"
	var/find_type = 0

/obj/item/weapon/archaeological_find/New(loc, var/new_item_type)
//	AddToProfiler()
	if(new_item_type)
		find_type = new_item_type
	else
		find_type = rand(1,34)	//update this when you add new find types

	var/item_type = "object"
	icon_state = "unknown[rand(1,4)]"
	var/additional_desc = ""
	var/obj/item/weapon/new_item
	var/source_material = ""
	var/apply_material_decorations = 1
	var/apply_image_decorations = 0
	var/material_descriptor = ""
	var/apply_prefix = 1
	if(prob(40))
		material_descriptor = pick("rusted ","dusty ","archaic ","fragile ")
	source_material = pick("cordite","quadrinium","steel","titanium","aluminium","ferritic-alloy","plasteel","duranium")

	var/talkative = 0
	if(prob(5))
		talkative = 1

	//for all items here:
	//icon_state
	//item_state
	switch(find_type)
		if(1)
			item_type = "bowl"
			new_item = new /obj/item/weapon/reagent_containers/glass(src.loc)
			new_item.icon = 'icons/obj/xenoarchaeology.dmi'
			new_item.icon_state = "bowl"
			apply_image_decorations = 1
			if(prob(20))
				additional_desc = "There appear to be [pick("dark","faintly glowing","pungent","bright")] [pick("red","purple","green","blue")] stains inside."
		if(2)
			item_type = "urn"
			new_item = new /obj/item/weapon/reagent_containers/glass(src.loc)
			new_item.icon = 'icons/obj/xenoarchaeology.dmi'
			new_item.icon_state = "urn"
			apply_image_decorations = 1
			if(prob(20))
				additional_desc = "It [pick("whispers faintly","makes a quiet roaring sound","whistles softly","thrums quietly","throbs")] if you put it to your ear."
		if(3)
			item_type = "[pick("fork","spoon","knife")]"
			if(prob(25))
				new_item = new /obj/item/weapon/kitchen/utensil/fork(src.loc)
			else if(prob(50))
				new_item = new /obj/item/weapon/kitchen/utensil/knife(src.loc)
			else
				new_item = new /obj/item/weapon/kitchen/utensil/spoon(src.loc)
			additional_desc = "[pick("It's like no [item_type] you've ever seen before",\
			"It's a mystery how anyone is supposed to eat with this",\
			"You wonder what the creator's mouth was shaped like")]."
		if(4)
			item_type = "statuette"
			icon_state = "statuette"
			additional_desc = "It depicts a [pick("small","ferocious","wild","pleasing","hulking")] \
			[pick("alien figure","rodent-like creature","reptilian alien","primate","unidentifiable object")] \
			[pick("performing unspeakable acts","posing heroically","in a fetal position","cheering","sobbing","making a plaintive gesture","making a rude gesture")]."
		if(5)
			item_type = "instrument"
			icon_state = "instrument"
			if(prob(30))
				apply_image_decorations = 1
				additional_desc = "[pick("You're not sure how anyone could have played this",\
				"You wonder how many mouths the creator had",\
				"You wonder what it sounds like",\
				"You wonder what kind of music was made with it")]."
		if(6)
			item_type = "[pick("bladed knife","serrated blade","sharp cutting implement")]"
			new_item = new /obj/item/weapon/kitchenknife(src.loc)
			additional_desc = "[pick("It doesn't look safe.",\
			"It looks wickedly jagged",\
			"There appear to be [pick("dark red","dark purple","dark green","dark blue")] stains along the edges")]."
		if(7)
			//assuming there are 10 types of coins
			var/chance = 10
			for(var/type in typesof(/obj/item/weapon/coin))
				if(prob(chance))
					new_item = new type(src.loc)
					break
				chance += 10

			item_type = new_item.name
			apply_prefix = 0
			apply_material_decorations = 0
			apply_image_decorations = 1
		if(8)
			item_type = "handcuffs"
			new_item = new /obj/item/weapon/restraints/handcuffs(src.loc)
			additional_desc = "[pick("They appear to be for securing two things together","Looks kinky","Doesn't seem like a children's toy")]."
		if(9)
			item_type = "[pick("wicked","evil","byzantine","dangerous")] looking [pick("device","contraption","thing","trap")]"
			apply_prefix = 0
			new_item = new /obj/item/weapon/restraints/legcuffs/beartrap(src.loc)
			additional_desc = "[pick("It looks like it could take a limb off",\
			"Could be some kind of animal trap",\
			"There appear to be [pick("dark red","dark purple","dark green","dark blue")] stains along part of it")]."
		if(10)
			item_type = "[pick("cylinder","tank","chamber")]"
			new_item = new /obj/item/weapon/lighter(src.loc)
			additional_desc = "There is a tiny device attached."
			if(prob(30))
				apply_image_decorations = 1
		if(11)
			item_type = "box"
			new_item = new /obj/item/weapon/storage/box(src.loc)
			new_item.icon = 'icons/obj/xenoarchaeology.dmi'
			new_item.icon_state = "box"
			if(prob(30))
				apply_image_decorations = 1
		if(12)
			item_type = "[pick("cylinder","tank","chamber")]"
			if(prob(25))
				new_item = new /obj/item/weapon/tank/internals/air(src.loc)
			else if(prob(50))
				new_item = new /obj/item/weapon/tank/internals/anesthetic(src.loc)
			else
				new_item = new /obj/item/weapon/tank/internals/plasma(src.loc)
			icon_state = pick("oxygen","oxygen_fr","oxygen_f","plasma","anesthetic")
			additional_desc = "It [pick("gloops","sloshes")] slightly when you shake it."
		if(13)
			item_type = "tool"
			if(prob(25))
				new_item = new /obj/item/weapon/wrench(src.loc)
			else if(prob(25))
				new_item = new /obj/item/weapon/crowbar(src.loc)
			else
				new_item = new /obj/item/weapon/screwdriver(src.loc)
			additional_desc = "[pick("It doesn't look safe.",\
			"You wonder what it was used for",\
			"There appear to be [pick("dark red","dark purple","dark green","dark blue")] stains on it")]."
		if(14)
			apply_material_decorations = 0
			var/list/possible_spawns = list()
			possible_spawns += /obj/item/stack/sheet/metal
			possible_spawns += /obj/item/stack/sheet/plasteel
			possible_spawns += /obj/item/stack/sheet/glass
			possible_spawns += /obj/item/stack/sheet/rglass
			possible_spawns += /obj/item/stack/sheet/mineral/plasma
		//	possible_spawns += /obj/item/stack/sheet/mineral/mythril
			possible_spawns += /obj/item/stack/sheet/mineral/gold
			possible_spawns += /obj/item/stack/sheet/mineral/silver
		//	possible_spawns += /obj/item/stack/sheet/mineral/enruranium
			possible_spawns += /obj/item/stack/sheet/mineral/sandstone
			possible_spawns += /obj/item/stack/sheet/mineral/silver

			var/new_type = pick(possible_spawns)
			new_item = new new_type(get_turf(src))
			new_item:amount = rand(5,45)
		if(15)
			if(prob(75))
				new_item = new /obj/item/weapon/pen(src.loc)
			else
				new_item = new /obj/item/weapon/pen/sleepy(src.loc)
			if(prob(30))
				apply_image_decorations = 1
		if(16)
			apply_prefix = 0
			if(prob(25))
				item_type = "smooth green crystal"
				icon_state = "Green lump"
			else if(prob(33))
				item_type = "irregular purple crystal"
				icon_state = "Phazon"
			else if(prob(50))
				item_type = "rough red crystal"
				icon_state = "changerock"
			else
				item_type = "smooth red crystal"
				icon = 'icons/obj/mining.dmi'
				icon_state = "ore"

			additional_desc = pick("It shines faintly as it catches the light.","It appears to have a faint inner glow.","It seems to draw you inward as you look it at.","Something twinkles faintly as you look at it.","It's mesmerizing to behold.")

			apply_material_decorations = 0
			if(prob(10))
				apply_image_decorations = 1
		if(17)
			//cultblade
			apply_prefix = 0
			new_item = new /obj/item/weapon/melee/cultblade(src.loc)
			apply_material_decorations = 0
			apply_image_decorations = 0
		if(18)
			new_item = new /obj/item/device/radio/beacon(src.loc)
			talkative = 0
			new_item.icon_state = "unknown[rand(1,4)]"
			new_item.icon = 'icons/obj/xenoarchaeology.dmi'
			new_item.desc = ""
		if(19)
			apply_prefix = 0
			new_item = new /obj/item/weapon/claymore(src.loc)
			new_item.force = 10
			item_type = new_item.name
		if(20)
			//arcane clothing
			apply_prefix = 0
			var/list/possible_spawns = list(/obj/item/clothing/head/culthood,
			/obj/item/clothing/head/magus,
			/obj/item/clothing/head/culthood/alt,
			/obj/item/clothing/head/helmet/space/cult)

			var/new_type = pick(possible_spawns)
			new_item = new new_type(src.loc)
		if(21)
			//soulstone
			apply_prefix = 0
			new_item = new /obj/item/device/soulstone(src.loc)
			item_type = new_item.name
			apply_material_decorations = 0
		if(22)
			new_item = new/obj/item/weapon/shard (src.loc)

			apply_prefix = 0
			apply_image_decorations = 0
			apply_material_decorations = 0
		if(23)
			apply_prefix = 0
			new_item = new /obj/item/stack/rods(src.loc)
			apply_image_decorations = 0
			apply_material_decorations = 0
		if(24)
			var/list/possible_spawns = typesof(/obj/item/weapon/stock_parts)
			possible_spawns -= /obj/item/weapon/stock_parts
			possible_spawns -= /obj/item/weapon/stock_parts/subspace

			var/new_type = pick(possible_spawns)
			new_item = new new_type(src.loc)
			item_type = new_item.name
			apply_material_decorations = 0
		if(25)
			apply_prefix = 0
			new_item = new /obj/item/weapon/katana(src.loc)
			new_item.force = 10
			item_type = new_item.name
		if(26)
			//energy gun
			var/spawn_type = pick(\
			/obj/item/weapon/gun/energy/laser/practice,\
			/obj/item/weapon/gun/energy/laser,\
			/obj/item/weapon/gun/energy/xray,\
			/obj/item/weapon/gun/energy/laser/captain)
			if(spawn_type)
				var/obj/item/weapon/gun/energy/new_gun = new spawn_type(src.loc)
				new_item = new_gun
				new_gun.pin = new /obj/item/device/firing_pin(new_gun)
				new_item.icon = 'icons/obj/xenoarchaeology.dmi'
				new_item.icon_state = "egun[rand(1,6)]"
				new_gun.desc = "This is an antique energy weapon, you're not sure if it will fire or not."
				new_gun.charge_states = 0 //let's prevent it from losing that great icon if we charge it

				//5% chance to explode when first fired
				//10% chance to have an unchargeable cell
				//15% chance to gain a random amount of starting energy, otherwise start with an empty cell
				if(prob(5))
					new_gun.power_supply.rigged = 1
				if(prob(10))
					new_gun.power_supply.maxcharge = 0
				if(prob(15))
					new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge)
				else
					new_gun.power_supply.charge = 0

			item_type = "gun"
		if(27)
			//revolver
			var/obj/item/weapon/gun/projectile/revolver/new_gun = new /obj/item/weapon/gun/projectile/revolver(src.loc)
			new_item = new_gun
			new_item.icon_state = "gun[rand(1,4)]"
			new_item.icon = 'icons/obj/xenoarchaeology.dmi'

			//let's get some ammunition in this gun : weighted to pick available ammo
		/*	new_gun.caliber = pick(50;list("357" = 1),
								   10;list("75" = 1),
								   30;list("38" = 1),
								   10;list("12mm" = 1)) */
			new_gun.mag_type = pick (30;/obj/item/ammo_box/magazine/m10mm,
									50;/obj/item/ammo_box/magazine/internal/cylinder,
									10;/obj/item/ammo_box/magazine/m50,
									10;/obj/item/ammo_box/magazine/m45)

			new_gun.chambered = null

			new_gun.magazine = new new_gun.mag_type

			//33% chance to fill it with a random amount of bullets
			new_gun.magazine.max_ammo = rand(1,12)
			if(prob(33))
				var/num_bullets = rand(1,new_gun.magazine.max_ammo)
				if(num_bullets < new_gun.magazine.stored_ammo.len)
					new_gun.magazine.stored_ammo.len = 0
					for(var/i = 1, i <= num_bullets, i++)
						var/A = new_gun.magazine.ammo_type
						new_gun.magazine.give_round(new A)
				else
					if(new_gun.magazine.stored_ammo.len > num_bullets)
						new_gun.magazine.stored_ammo.len = num_bullets
			else
				new_gun.magazine.stored_ammo.len = 0

			item_type = "gun"
		if(28)
			//completely unknown alien device
			if(prob(50))
				apply_image_decorations = 0
		if(29)
			//fossil bone/skull
			//new_item = new /obj/item/weapon/fossil/base(src.loc)

			//the replacement item propogation isn't working, and it's messy code anyway so just do it here
			var/list/candidates = list("/obj/item/weapon/fossil/bone"=9,"/obj/item/weapon/fossil/skull"=3,
			"/obj/item/weapon/fossil/skull/horned"=2)
			var/spawn_type = pickweight(candidates)
			new_item = new spawn_type(src.loc)

			apply_prefix = 0
			additional_desc = "A fossilised part of an alien, long dead."
			apply_image_decorations = 0
			apply_material_decorations = 0
		if(30)
			//fossil shell
			new_item = new /obj/item/weapon/fossil/shell(src.loc)
			apply_prefix = 0
			additional_desc = "A fossilised, pre-Stygian alien crustacean."
			apply_image_decorations = 0
			apply_material_decorations = 0
			if(prob(10))
				apply_image_decorations = 1
		if(31)
			//fossil plant
			new_item = new /obj/item/weapon/fossil/plant(src.loc)
			item_type = new_item.name
			additional_desc = "A fossilised shred of alien plant matter."
			apply_image_decorations = 0
			apply_material_decorations = 0
			apply_prefix = 0
		if(32)
			//humanoid remains
			apply_prefix = 0
			item_type = "humanoid [pick("remains","skeleton")]"
			icon = 'icons/effects/blood.dmi'
			icon_state = "remains"
			additional_desc = pick("They appear almost human.",\
			"They are contorted in a most gruesome way.",\
			"They look almost peaceful.",\
			"The bones are yellowing and old, but remarkably well preserved.",\
			"The bones are scored by numerous burns and partially melted.",\
			"The are battered and broken, in some cases less than splinters are left.",\
			"The mouth is wide open in a death rictus, the victim would appear to have died screaming.")
			apply_image_decorations = 0
			apply_material_decorations = 0
		if(33)
			//robot remains
			apply_prefix = 0
			item_type = "[pick("mechanical","robotic","cyborg")] [pick("remains","chassis","debris")]"
			icon = 'icons/mob/robots.dmi'
			icon_state = "remainsrobot"
			additional_desc = pick("Almost mistakeable for the remains of a modern cyborg.",\
			"They are barely recognisable as anything other than a pile of waste metals.",\
			"It looks like the battered remains of an ancient robot chassis.",\
			"The chassis is rusting and old, but remarkably well preserved.",\
			"The chassis is scored by numerous burns and partially melted.",\
			"The chassis is battered and broken, in some cases only chunks of metal are left.",\
			"A pile of wires and crap metal that looks vaguely robotic.")
			apply_image_decorations = 0
			apply_material_decorations = 0
		if(34)
			//xenos remains
			apply_prefix = 0
			item_type = "alien [pick("remains","skeleton")]"
			icon = 'icons/effects/blood.dmi'
			icon_state = "remainsxeno"
			additional_desc = pick("It looks vaguely reptilian, but with more teeth.",\
			"They are faintly unsettling.",\
			"There is a faint aura of unease about them.",\
			"The bones are yellowing and old, but remarkably well preserved.",\
			"The bones are scored by numerous burns and partially melted.",\
			"The are battered and broken, in some cases less than splinters are left.",\
			"This creature would have been twisted and monstrous when it was alive.",\
			"It doesn't look human.")
			apply_image_decorations = 0
			apply_material_decorations = 0
		if(35)
			//masks
			apply_material_decorations = 0
			var/list/possible_spawns = list()
			possible_spawns += /obj/item/clothing/mask/happy
			//possible_spawns += /obj/item/clothing/mask/stone WHEN I CODE IT //NEVER EVER
			var/new_type = pick(possible_spawns)
			new_item = new new_type(src.loc)

	var/decorations = ""
	if(apply_material_decorations)
		source_material = pick("cordite","quadrinium","steel","titanium","aluminium","ferritic-alloy","plasteel","duranium")
		desc = "A [material_descriptor ? "[material_descriptor] " : ""][item_type] made of [source_material], all craftsmanship is of [pick("the lowest","low","average","high","the highest")] quality."

		var/list/descriptors = list()
		if(prob(30))
			descriptors.Add("is encrusted with [pick("","synthetic ","multi-faceted ","uncut ","sparkling ") + pick("rubies","emeralds","diamonds","opals","lapiz lazuli")]")
		if(prob(30))
			descriptors.Add("is studded with [pick("gold","silver","aluminium","titanium")]")
		if(prob(30))
			descriptors.Add("is encircled with bands of [pick("quadrinium","cordite","ferritic-alloy","plasteel","duranium")]")
		if(prob(30))
			descriptors.Add("menaces with spikes of [pick("solid plasma","uranium","white pearl","black steel")]")
		if(descriptors.len > 0)
			decorations = "It "
			for(var/index=1, index <= descriptors.len, index++)
				if(index > 1)
					if(index == descriptors.len)
						decorations += " and "
					else
						decorations += ", "
				decorations += descriptors[index]
			decorations += "."
		if(decorations)
			desc += " " + decorations

	var/engravings = ""
	if(apply_image_decorations)
		engravings = "[pick("Engraved","Carved","Etched")] on the item is [pick("an image of","a frieze of","a depiction of")] \
		[pick("an alien humanoid","an amorphic blob","a short, hairy being","a rodent-like creature","a robot","a primate","a reptilian alien","an unidentifiable object","a statue","a starship","unusual devices","a structure")] \
		[pick("surrounded by","being held aloft by","being struck by","being examined by","communicating with")] \
		[pick("alien humanoids","amorphic blobs","short, hairy beings","rodent-like creatures","robots","primates","reptilian aliens")]"
		if(prob(50))
			engravings += ", [pick("they seem to be enjoying themselves","they seem extremely angry","they look pensive","they are making gestures of supplication","the scene is one of subtle horror","the scene conveys a sense of desperation","the scene is completely bizarre")]"
		engravings += "."

		if(desc)
			desc += " "
		desc += engravings

	if(apply_prefix)
		name = "[pick("Strange ","Ancient ","Alien ","")][item_type]"
	else
		name = item_type

	if(desc)
		desc += " "
	desc += additional_desc
	if(!desc)
		desc = "This item is completely [pick("alien","bizarre")]."

	//icon and icon_state should have already been set
	if(new_item)
		new_item.name = name
		new_item.desc = src.desc

		if(talkative && istype(new_item,/obj/item/weapon))
			new_item.listening_to_players = 1
			new_item.heard_words = list()
			if(prob(25))
				new_item.speaking_to_players = 1
				SSobj.processing.Add(new_item)
		var/turf/T = get_turf(src)
		if(istype(T, /turf/simulated/mineral))
			T:last_find = new_item
		del(src)

	else if(talkative)
		listening_to_players = 1
		if(prob(25))
			if(!heard_words) heard_words = list()
			speaking_to_players = 1
			SSobj.processing.Add(src)


code:
#define ARCHAEO_BOWL 1
#define ARCHAEO_URN 2
#define ARCHAEO_CUTLERY 3
#define ARCHAEO_STATUETTE 4
#define ARCHAEO_INSTRUMENT 5
#define ARCHAEO_KNIFE 6
#define ARCHAEO_COIN 7
#define ARCHAEO_HANDCUFFS 8
#define ARCHAEO_BEARTRAP 9
#define ARCHAEO_LIGHTER 10
#define ARCHAEO_BOX 11
#define ARCHAEO_GASTANK 12
#define ARCHAEO_TOOL 13
#define ARCHAEO_METAL 14
#define ARCHAEO_PEN 15
#define ARCHAEO_CRYSTAL 16
#define ARCHAEO_CULTBLADE 17
#define ARCHAEO_TELEBEACON 18
#define ARCHAEO_CLAYMORE 19
#define ARCHAEO_CULTROBES 20
#define ARCHAEO_SOULSTONE 21
#define ARCHAEO_SHARD 22
#define ARCHAEO_RODS 23
#define ARCHAEO_STOCKPARTS 24
#define ARCHAEO_KATANA 25
#define ARCHAEO_LASER 26
#define ARCHAEO_GUN 27
#define ARCHAEO_UNKNOWN 28
#define ARCHAEO_FOSSIL 29
#define ARCHAEO_SHELL 30
#define ARCHAEO_PLANT 31
#define ARCHAEO_REMAINS_HUMANOID 32
#define ARCHAEO_REMAINS_ROBOT 33
#define ARCHAEO_REMAINS_XENO 34
#define ARCHAEO_MASK 35
#define MAX_ARCHAEO 35
//eggs
//droppings
//footprints
//alien clothing

//DNA sampling from fossils, or a new archaeo type specifically for it?

//descending order of likeliness to spawn
#define DIGSITE_GARDEN 1
#define DIGSITE_ANIMAL 2
#define DIGSITE_HOUSE 3
#define DIGSITE_TECHNICAL 4
#define DIGSITE_TEMPLE 5
#define DIGSITE_WAR 6

/proc/get_responsive_reagent(var/find_type)
	switch(find_type)
		if(ARCHAEO_BOWL)
			return "mercury"
		if(ARCHAEO_URN)
			return "mercury"
		if(ARCHAEO_CUTLERY)
			return "mercury"
		if(ARCHAEO_STATUETTE)
			return "mercury"
		if(ARCHAEO_INSTRUMENT)
			return "mercury"
		if(ARCHAEO_COIN)
			return "iron"
		if(ARCHAEO_KNIFE)
			return "iron"
		if(ARCHAEO_HANDCUFFS)
			return "mercury"
		if(ARCHAEO_BEARTRAP)
			return "mercury"
		if(ARCHAEO_LIGHTER)
			return "mercury"
		if(ARCHAEO_BOX)
			return "mercury"
		if(ARCHAEO_GASTANK)
			return "mercury"
		if(ARCHAEO_TOOL)
			return "iron"
		if(ARCHAEO_METAL)
			return "iron"
		if(ARCHAEO_PEN)
			return "mercury"
		if(ARCHAEO_CRYSTAL)
			return "nitrogen"
		if(ARCHAEO_CULTBLADE)
			return "potassium"
		if(ARCHAEO_TELEBEACON)
			return "potassium"
		if(ARCHAEO_CLAYMORE)
			return "iron"
		if(ARCHAEO_CULTROBES)
			return "potassium"
		if(ARCHAEO_SOULSTONE)
			return "nitrogen"
		if(ARCHAEO_SHARD)
			return "nitrogen"
		if(ARCHAEO_RODS)
			return "iron"
		if(ARCHAEO_STOCKPARTS)
			return "potassium"
		if(ARCHAEO_KATANA)
			return "iron"
		if(ARCHAEO_LASER)
			return "iron"
		if(ARCHAEO_GUN)
			return "iron"
		if(ARCHAEO_UNKNOWN)
			return "mercury"
		if(ARCHAEO_FOSSIL)
			return "carbon"
		if(ARCHAEO_SHELL)
			return "carbon"
		if(ARCHAEO_PLANT)
			return "carbon"
		if(ARCHAEO_REMAINS_HUMANOID)
			return "carbon"
		if(ARCHAEO_REMAINS_ROBOT)
			return "carbon"
		if(ARCHAEO_REMAINS_XENO)
			return "carbon"
		if(ARCHAEO_MASK)
			return "mercury"
	return "plasma"

//see /turf/unsimulated/mineral/New() in code/modules/mining/mine_turfs.dm
/proc/get_random_digsite_type()
	return pick(100;DIGSITE_GARDEN,95;DIGSITE_ANIMAL,90;DIGSITE_HOUSE,85;DIGSITE_TECHNICAL,80;DIGSITE_TEMPLE,75;DIGSITE_WAR)

/proc/get_random_find_type(var/digsite)

	var/find_type = 0
	switch(digsite)
		if(DIGSITE_GARDEN)
			find_type = pick(\
			100;ARCHAEO_PLANT,\
			25;ARCHAEO_SHELL,\
			25;ARCHAEO_FOSSIL,\
			5;ARCHAEO_BEARTRAP\
			)
		if(DIGSITE_ANIMAL)
			find_type = pick(\
			100;ARCHAEO_FOSSIL,\
			50;ARCHAEO_SHELL,\
			50;ARCHAEO_PLANT,\
			25;ARCHAEO_BEARTRAP\
			)
		if(DIGSITE_HOUSE)
			find_type = pick(\
			100;ARCHAEO_BOWL,\
			100;ARCHAEO_URN,\
			100;ARCHAEO_CUTLERY,\
			100;ARCHAEO_STATUETTE,\
			100;ARCHAEO_INSTRUMENT,\
			100;ARCHAEO_PEN,\
			100;ARCHAEO_LIGHTER,\
			100;ARCHAEO_BOX,\
			75;ARCHAEO_COIN,\
			75;ARCHAEO_UNKNOWN,\
			50;ARCHAEO_SHARD,\
			50;ARCHAEO_RODS,\
			25;ARCHAEO_METAL\
			)
		if(DIGSITE_TECHNICAL)
			find_type = pick(\
			100;ARCHAEO_METAL,\
			100;ARCHAEO_GASTANK,\
			100;ARCHAEO_TELEBEACON,\
			100;ARCHAEO_TOOL,\
			100;ARCHAEO_STOCKPARTS,\
			75;ARCHAEO_SHARD,\
			75;ARCHAEO_RODS,\
			75;ARCHAEO_UNKNOWN,\
			50;ARCHAEO_HANDCUFFS,\
			50;ARCHAEO_BEARTRAP,\
			)
		if(DIGSITE_TEMPLE)
			find_type = pick(\
			200;ARCHAEO_CULTROBES,\
			100;ARCHAEO_URN,\
			100;ARCHAEO_BOWL,\
			100;ARCHAEO_KNIFE,\
			100;ARCHAEO_CRYSTAL,\
			75;ARCHAEO_MASK,\
			75;ARCHAEO_CULTBLADE,\
			50;ARCHAEO_SOULSTONE,\
			50;ARCHAEO_UNKNOWN,\
			25;ARCHAEO_HANDCUFFS,\
			25;ARCHAEO_BEARTRAP,\
			10;ARCHAEO_KATANA,\
			10;ARCHAEO_CLAYMORE,\
			10;ARCHAEO_SHARD,\
			10;ARCHAEO_RODS,\
			10;ARCHAEO_METAL\
			)
		if(DIGSITE_WAR)
			find_type = pick(\
			100;ARCHAEO_GUN,\
			100;ARCHAEO_KNIFE,\
			75;ARCHAEO_LASER,\
			75;ARCHAEO_KATANA,\
			75;ARCHAEO_CLAYMORE,\
			50;ARCHAEO_UNKNOWN,\
			50;ARCHAEO_CULTROBES,\
			50;ARCHAEO_CULTBLADE,\
			25;ARCHAEO_HANDCUFFS,\
			25;ARCHAEO_BEARTRAP,\
			25;ARCHAEO_TOOL\
			)
	return find_type

var/list/responsive_carriers = list( \
	"carbon", \
	"potassium", \
	"hydrogen", \
	"nitrogen", \
	"mercury", \
	"iron", \
	"chlorine", \
	"phosphorus", \
	"plasma")

var/list/finds_as_strings = list( \
	"Trace organic cells", \
	"Long exposure particles", \
	"Trace water particles", \
	"Crystalline structures", \
	"Metallic derivative", \
	"Metallic composite", \
	"Metamorphic/igneous rock composite", \
	"Metamorphic/sedimentary rock composite", \
	"Anomalous material" )

#undef ARCHAEO_BOWL
#undef ARCHAEO_URN
#undef ARCHAEO_CUTLERY
#undef ARCHAEO_STATUETTE
#undef ARCHAEO_INSTRUMENT
#undef ARCHAEO_KNIFE
#undef ARCHAEO_COIN
#undef ARCHAEO_HANDCUFFS
#undef ARCHAEO_BEARTRAP
#undef ARCHAEO_LIGHTER
#undef ARCHAEO_BOX
#undef ARCHAEO_GASTANK
#undef ARCHAEO_TOOL
#undef ARCHAEO_METAL
#undef ARCHAEO_PEN
#undef ARCHAEO_CRYSTAL
#undef ARCHAEO_CULTBLADE
#undef ARCHAEO_TELEBEACON
#undef ARCHAEO_CLAYMORE
#undef ARCHAEO_CULTROBES
#undef ARCHAEO_SOULSTONE
#undef ARCHAEO_SHARD
#undef ARCHAEO_RODS
#undef ARCHAEO_STOCKPARTS
#undef ARCHAEO_KATANA
#undef ARCHAEO_LASER
#undef ARCHAEO_GUN
#undef ARCHAEO_UNKNOWN
#undef ARCHAEO_FOSSIL
#undef ARCHAEO_SHELL
#undef ARCHAEO_PLANT
#undef ARCHAEO_REMAINS_HUMANOID
#undef ARCHAEO_REMAINS_ROBOT
#undef ARCHAEO_REMAINS_XENO
#undef ARCHAEO_MASK

#undef DIGSITE_GARDEN
#undef DIGSITE_ANIMAL
#undef DIGSITE_HOUSE
#undef DIGSITE_TECHNICAL
#undef DIGSITE_TEMPLE
#undef DIGSITE_WAR

license: mit


code:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// fossils

/obj/item/weapon/fossil
	name = "Fossil"
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "bone"
	desc = "It's a fossil."

/obj/item/weapon/fossil/base/New()
	var/list/l = list("/obj/item/weapon/fossil/bone"=9,"/obj/item/weapon/fossil/skull"=3,
	"/obj/item/weapon/fossil/skull/horned"=2)
	var/t = pickweight(l)
	var/obj/item/weapon/W = new t(src.loc)
	var/turf/T = get_turf(src)
	if(istype(T, /turf/simulated/mineral))
		T:last_find = W
	del src

/obj/item/weapon/fossil/bone
	name = "Fossilised bone"
	icon_state = "bone"
	desc = "It's a fossilised bone."

/obj/item/weapon/fossil/skull
	name = "Fossilised skull"
	icon_state = "skull"
	desc = "It's a fossilised skull."

/obj/item/weapon/fossil/skull/horned
	icon_state = "hskull"
	desc = "It's a fossilised, horned skull."

/obj/item/weapon/fossil/skull/attackby(obj/item/weapon/W as obj, mob/user as mob)
	if(istype(W,/obj/item/weapon/fossil/bone))
		var/obj/o = new /obj/skeleton(get_turf(src))
		var/a = new /obj/item/weapon/fossil/bone
		var/b = new src.type
		o.contents.Add(a)
		o.contents.Add(b)
		del W
		del src

/obj/skeleton
	name = "Incomplete skeleton"
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "uskel"
	desc = "Incomplete skeleton."
	var/bnum = 1
	var/breq
	var/bstate = 0
	var/plaque_contents = "Unnamed alien creature"

/obj/skeleton/New()
	src.breq = rand(6)+3
	src.desc = "An incomplete skeleton, looks like it could use [src.breq-src.bnum] more bones."

/obj/skeleton/attackby(obj/item/weapon/W as obj, mob/user as mob)
	if(istype(W,/obj/item/weapon/fossil/bone))
		if(!bstate)
			bnum++
			src.contents.Add(new/obj/item/weapon/fossil/bone)
			del W
			if(bnum==breq)
				usr = user
				icon_state = "skel"
				src.bstate = 1
				src.density = 1
				src.name = "alien skeleton display"
				if(src.contents.Find(/obj/item/weapon/fossil/skull/horned))
					src.desc = "A creature made of [src.contents.len-1] assorted bones and a horned skull. The plaque reads \'[plaque_contents]\'."
				else
					src.desc = "A creature made of [src.contents.len-1] assorted bones and a skull. The plaque reads \'[plaque_contents]\'."
			else
				src.desc = "Incomplete skeleton, looks like it could use [src.breq-src.bnum] more bones."
				user << "Looks like it could use [src.breq-src.bnum] more bones."
		else
			..()
	else if(istype(W,/obj/item/weapon/pen))
		plaque_contents = copytext(sanitize(input(user, "What would you like to write on the plaque?", "Skeleton plaque", null) as text|null), 1, 1648) //length of WGW in characters - niggly said i should
		if (!plaque_contents || !Adjacent(user) || user.stat) return
		user.visible_message("[user] writes something on the base of [src].","You relabel the plaque on the base of \icon[src] [src].")
		if(src.contents.Find(/obj/item/weapon/fossil/skull/horned))
			src.desc = "A creature made of [src.contents.len-1] assorted bones and a horned skull. The plaque reads \'[plaque_contents]\'."
		else
			src.desc = "A creature made of [src.contents.len-1] assorted bones and a skull. The plaque reads \'[plaque_contents]\'."
	else
		..()

//shells and plants do not make skeletons
/obj/item/weapon/fossil/shell
	name = "Fossilised shell"
	icon_state = "shell"
	desc = "It's a fossilised shell."

/obj/item/weapon/fossil/plant
	name = "Fossilised plant"
	icon_state = "plant1"
	desc = "It's fossilised plant remains."

/obj/item/weapon/fossil/plant/New()
	icon_state = "plant[rand(1,4)]"


code:
//legacy crystal
/obj/machinery/crystal
	name = "Crystal"
	icon = 'icons/obj/mining.dmi'
	icon_state = "crystal"

/obj/machinery/crystal/New()
	if(prob(50))
		icon_state = "crystal2"

//large finds
				/*
				/obj/machinery/syndicate_beacon
				/obj/machinery/wish_granter
			if(18)
				item_type = "jagged green crystal"
				additional_desc = pick("It shines faintly as it catches the light.","It appears to have a faint inner glow.","It seems to draw you inward as you look it at.","Something twinkles faintly as you look at it.","It's mesmerizing to behold.")
				icon_state = "crystal"
				apply_material_decorations = 0
				if(prob(10))
					apply_image_decorations = 1
			if(19)
				item_type = "jagged pink crystal"
				additional_desc = pick("It shines faintly as it catches the light.","It appears to have a faint inner glow.","It seems to draw you inward as you look it at.","Something twinkles faintly as you look at it.","It's mesmerizing to behold.")
				icon_state = "crystal2"
				apply_material_decorations = 0
				if(prob(10))
					apply_image_decorations = 1
				*/
			//machinery type artifacts?


code:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Formerly talking crystals - these procs are now modular so that you can make any /obj/item/weapon 'parrot' player speech back to them
// This could be extended to atoms, but it's bad enough as is
// I genuinely tried to Add and Remove them from var and proc lists, but just couldn't get it working

/obj/item/weapon
	var/list/heard_words
	var/lastsaid
	var/listening_to_players = 0
	var/speaking_to_players = 0

/obj/item/weapon/process()
	if(!speaking_to_players)
		SSobj.processing.Remove(src)
		return
	if(prob(10) && world.timeofday >= lastsaid && heard_words.len >= 1)
		SaySomething()

/obj/item/weapon/proc/catchMessage(var/msg, var/mob/source)
	if(speaking_to_players)
		var/list/seperate = list()
		if(findtext(msg,"(("))
			return
		else if(findtext(msg,"))"))
			return
		else if(findtext(msg," ")==0)
			return
		else
			/*var/l = length(msg)
			if(findtext(msg," ",l,l+1)==0)
				msg+=" "*/
			seperate = text2list(msg, " ")

		for(var/Xa = 1,Xa<seperate.len,Xa++)
			var/next = Xa + 1
			if(heard_words.len > 20 + rand(10,20))
				heard_words.Remove(heard_words[1])
			if(!heard_words["[lowertext(seperate[Xa])]"])
				heard_words["[lowertext(seperate[Xa])]"] = list()
			var/list/w = heard_words["[lowertext(seperate[Xa])]"]
			if(w)
				w.Add("[lowertext(seperate[next])]")
			//world << "Adding [lowertext(seperate[next])] to [lowertext(seperate[Xa])]"

		if(!rand(0, 5))
			spawn(2) SaySomething(pick(seperate))
	if(prob(30))
		for(var/mob/O in viewers(src))
			O.show_message("[src] hums for bit then stops...", 1)

/*/obj/item/weapon/talkingcrystal/proc/debug()
	//set src in view()
	for(var/v in heard_words)
		world << "[uppertext(v)]"
		var/list/d = heard_words["[v]"]
		for(var/X in d)
			world << "[X]"*/

/obj/item/weapon/proc/SaySomething(var/word = null)

	var/msg
	var/limit = rand(max(5,heard_words.len/2))+3
	var/text
	if(!word)
		text = "[pick(heard_words)]"
	else
		text = pick(text2list(word, " "))
	if(length(text)==1)
		text=uppertext(text)
	else
		var/cap = copytext(text,1,2)
		cap = uppertext(cap)
		cap += copytext(text,2,length(text)+1)
		text=cap
	var/q = 0
	msg+=text
	if(msg=="What" | msg == "Who" | msg == "How" | msg == "Why" | msg == "Are")
		q=1

	text=lowertext(text)
	for(var/ya,ya <= limit,ya++)

		if(heard_words.Find("[text]"))
			var/list/w = heard_words["[text]"]
			text=pick(w)
		else
			text = "[pick(heard_words)]"
		msg+=" [text]"
	if(q)
		msg+="?"
	else
		if(rand(0,10))
			msg+="."
		else
			msg+="!"

	var/list/listening = viewers(src)
	for(var/mob/M in mob_list)
		if (!M.client)
			continue //skip monkeys and leavers
		if (istype(M, /mob/new_player))
			continue
		if(M.stat == 2 &&  M.client.prefs.toggles & CHAT_GHOSTEARS)
			listening|=M

	for(var/mob/M in listening)
		M << "[src] reverberates, \"[msg]\""
	lastsaid = world.timeofday + rand(300,800)


code:
/obj/item/weapon/reagent_containers/food/snacks/grown/telriis_clump
	name = "telriis grass"
	desc = "A clump of telriis grass, not recommended for consumption by sentients."
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "telriisclump"
	New(var/loc, var/potency)
		..()
		reagents.add_reagent("pwine", potency * 5)
		reagents.add_reagent("nutriment", potency)
		bitesize = 1+round(reagents.total_volume / 2, 1)

/obj/item/weapon/reagent_containers/food/snacks/grown/thaadrabloom
	name = "thaa'dra bloom"
	desc = "Looks chewy, might be good to eat."
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "thaadrabloom"
	New(var/loc, var/potency)
		..()
		reagents.add_reagent("frostoil", potency * 1.5 + 5)
		reagents.add_reagent("nutriment", potency)
		bitesize = 1+round(reagents.total_volume / 2, 1)

/obj/item/weapon/reagent_containers/food/snacks/grown/jurlmah
	name = "jurl'mah pod"
	desc = "Bulbous and veiny, it appears to pulse slightly as you look at it."
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "jurlmahpod"
	New(var/loc, var/potency)
		..()
		reagents.add_reagent("serotrotium", potency)
		reagents.add_reagent("nutriment", potency)
		bitesize = 1+round(reagents.total_volume / 2, 1)

/obj/item/weapon/reagent_containers/food/snacks/grown/amauri
	name = "amauri fruit"
	desc = "It is small, round and hard. Its skin is a thick dark purple."
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "amaurifruit"
	New(var/loc, var/potency)
		..()
		reagents.add_reagent("zombiepowder", potency * 10)
		reagents.add_reagent("condensedcapsaicin", potency * 5)
		reagents.add_reagent("nutriment", potency)
		bitesize = 1+round(reagents.total_volume / 2, 1)

/obj/item/weapon/reagent_containers/food/snacks/grown/gelthi
	name = "gelthi berries"
	desc = "They feel fluffy and slightly warm to the touch."
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "gelthiberries"
	New(var/loc, var/potency)
		..()
		//this may prove a little strong
		reagents.add_reagent("stoxin", (potency * potency) / 5)
		reagents.add_reagent("capsaicin", (potency * potency) / 5)
		reagents.add_reagent("nutriment", potency)
		bitesize = 1+round(reagents.total_volume / 2, 1)

/obj/item/weapon/reagent_containers/food/snacks/grown/vale
	name = "vale leaves"
	desc = "Small, curly leaves covered in a soft pale fur."
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "valeleaves"
	New(var/loc, var/potency)
		..()
		reagents.add_reagent("paracetamol", potency * 5)
		reagents.add_reagent("dexalin", potency * 2)
		reagents.add_reagent("nutriment", potency)
		bitesize = 1+round(reagents.total_volume / 2, 1)

/obj/item/weapon/reagent_containers/food/snacks/grown/surik
	name = "surik fruit"
	desc = "Multiple layers of blue skin peeling away to reveal a spongey core, vaguely resembling an ear."
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "surikfruit"
	New(var/loc, var/potency)
		..()
		reagents.add_reagent("impedrezene", potency * 3)
		reagents.add_reagent("synaptizine", potency * 2)
		reagents.add_reagent("nutriment", potency)
		bitesize = 1+round(reagents.total_volume / 2, 1)


code:
/*
#define FIND_PLANT 1
#define FIND_BIO 2
#define FIND_METEORIC 3
#define FIND_ICE 4
#define FIND_CRYSTALLINE 5
#define FIND_METALLIC 6
#define FIND_IGNEOUS 7
#define FIND_METAMORPHIC 8
#define FIND_SEDIMENTARY 9
#define FIND_NOTHING 10
*/

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Rock sliver

/obj/item/weapon/rocksliver
	name = "rock sliver"
	desc = "It looks extremely delicate."
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "sliver1"	//0-4
	w_class = 1
	//item_state = "electronic"
	var/source_rock = "/turf/simulated/mineral/"
	var/datum/geosample/geological_data

/obj/item/weapon/rocksliver/New()
	. = ..()
	icon_state = "sliver[rand(1,3)]"
	pixel_x = rand(-8, 8)
	pixel_y = rand(-8, 0)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Geosample datum

/datum/geosample
	var/age = 0								//age can correspond to different archaeological finds
	var/age_thousand = 0
	var/age_million = 0
	var/age_billion = 0
	var/artifact_id = ""					//id of a nearby artifact, if there is one
	var/artifact_distance = -1				//proportional to distance
	var/source_mineral = "chlorine"			//machines will pop up a warning telling players that the sample may be confused
	var/total_spread = 0
	//
	//var/source_mineral
	//all potential finds are initialised to null, so nullcheck before you access them
	var/list/find_presence = list()

/datum/geosample/New(var/turf/simulated/mineral/container)
	UpdateTurf(container)

//this should only need to be called once
/datum/geosample/proc/UpdateTurf(var/turf/simulated/mineral/container)
	if(!container || !istype(container))
		return

	age = rand(1,999)

	if(container.mineralName)
		switch(container.mineralName)
			if("Uranium")
				age_million = rand(1, 704)
				age_thousand = rand(1,999)
				find_presence["potassium"] = rand(1,1000) / 100
				source_mineral = "potassium"
			if("Iron")
				age_thousand = rand(1, 999)
				age_million = rand(1, 999)
				find_presence["iron"] = rand(1,1000) / 100
				source_mineral = "iron"
			if("Diamond")
				age_thousand = rand(1,999)
				age_million = rand(1,999)
				find_presence["nitrogen"] = rand(1,1000) / 100
				source_mineral = "nitrogen"
			if("Gold")
				age_thousand = rand(1,999)
				age_million = rand(1,999)
				age_billion = rand(3,4)
				find_presence["iron"] = rand(1,1000) / 100
				source_mineral = "iron"
			if("Silver")
				age_thousand = rand(1,999)
				age_million = rand(1,999)
				find_presence["iron"] = rand(1,1000) / 100
				source_mineral = "iron"
			if("Plasma")
				age_thousand = rand(1,999)
				age_million = rand(1,999)
				age_billion = rand(10, 13)
				find_presence["plasma"] = rand(1,1000) / 100
				source_mineral = "plasma"
			if("Bananium")
				age = rand(-1,-999)				//thats the joke
				age_thousand = rand(-1,-999)
				find_presence["plasma"] = rand(1,1000) / 100
				source_mineral = "plasma"

	if(prob(75))
		find_presence["phosphorus"] = rand(1,500) / 100
	if(prob(25))
		find_presence["mercury"] = rand(1,500) / 100
	find_presence["chlorine"] = rand(500,2500) / 100

	//loop over finds, grab any relevant stuff
	for(var/datum/find/F in container.finds)
		var/responsive_reagent = get_responsive_reagent(F.find_type)
		find_presence[responsive_reagent] = F.dissonance_spread

	//loop over again to reset values to percentages
	var/total_presence = 0
	for(var/carrier in find_presence)
		total_presence += find_presence[carrier]
	for(var/carrier in find_presence)
		find_presence[carrier] = find_presence[carrier] / total_presence

	for(var/entry in find_presence)
		total_spread += find_presence[entry]

//have this separate from UpdateTurf() so that we dont have a billion turfs being updated (redundantly) every time an artifact spawns
/datum/geosample/proc/UpdateNearbyArtifactInfo(var/turf/simulated/mineral/container)
	if(!container || !istype(container))
		return

	if(container.artifact_find)
		artifact_distance = rand()
		artifact_id = container.artifact_find.artifact_id
	else
		if(master_controller) //Sanity check due to runtimes ~Z
			for(var/turf/simulated/mineral/T in master_controller.artifact_spawning_turfs)
				if(T.artifact_find)
					var/cur_dist = get_dist(container, T) * 2
					if( (artifact_distance < 0 || cur_dist < artifact_distance) && cur_dist <= T.artifact_find.artifact_detect_range )
						artifact_distance = cur_dist + rand() * 2 - 1
						artifact_id = T.artifact_find.artifact_id
				else
					master_controller.artifact_spawning_turfs.Remove(T)

/*
#undef FIND_PLANT
#undef FIND_BIO
#undef FIND_METEORIC
#undef FIND_ICE
#undef FIND_CRYSTALLINE
#undef FIND_METALLIC
#undef FIND_IGNEOUS
#undef FIND_METAMORPHIC
#undef FIND_SEDIMENTARY
#undef FIND_NOTHING
*/


code:
// This machine shows the age for extremely old finds

obj/machinery/anomaly/accelerator
	name = "Accelerator spectrometer"

obj/machinery/anomaly/accelerator/ScanResults()
	var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."

	var/datum/geosample/scanned_sample
	var/carrier_name
	var/num_reagents = 0

	for(var/datum/reagent/A in held_container.reagents.reagent_list)
		var/datum/reagent/R = A
		if(istype(R, /datum/reagent/analysis_sample))
			scanned_sample = R.data
		else
			carrier_name = R.id
		num_reagents++

	if(num_reagents == 2 && scanned_sample && carrier_name)
		var/specifity = GetResultSpecifity(scanned_sample, carrier_name)
		results = "Kinetic acceleration  of carrier ([carrier_name]) indicates age ([100 * specifity]% accuracy):

"

		if(scanned_sample.age_billion)
			var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - specifity) * (2 * rand() - 1)), 0)
			var/displayed_age_billions = scanned_sample.age_billion + max(scanned_sample.age_billion * ((1 - specifity) * (2 * rand() - 1)), 0)
			results += "[displayed_age_billions + displayed_age_millions / 1000] billion years.
"
		else if(scanned_sample.age_million)
			var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - specifity) * (4 * rand() - 2)), 0)
			var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - specifity) * (2 * rand() - 1)), 0)
			results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.
"
		else if(scanned_sample.age_thousand)
			var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - specifity) * (8 * rand() - 4)), 0)
			var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age * ((1 - specifity) * (4 * rand() - 2)), 0)
			results += "[displayed_age_thousands + displayed_age / 1000] thousand years.
"
		else
			var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - specifity) * (8 * rand() - 4)), 0)
			results += "[displayed_age] years.
"

		results += "
Warning, results only valid for ages on the scale of billions of years."

	return results


code:
//Handles how much the temperature changes on power use. (Joules/Kelvin)
//Equates to as much heat energy per kelvin as a quarter tile of air.
#define XENOARCH_HEAT_CAPACITY 5000

//Handles heat transfer to the air. (In watts)
//Can heat a single tile 2 degrees per tick.
#define XENOARCH_MAX_ENERGY_TRANSFER 4000

//How many joules of electrical energy produce how many joules of heat energy?
#define XENOARCH_HEAT_COEFFICIENT 3

/obj/machinery/anomaly
	name = "Analysis machine"
	desc = "A specialised, complex analysis machine."
	anchored = 1
	density = 1
	icon = 'icons/obj/virology.dmi'
	icon_state = "analyser"

	idle_power_usage = 20 //watts
	active_power_usage = 300 //Because  I need to make up numbers~

	var/obj/item/weapon/reagent_containers/glass/held_container
	var/obj/item/weapon/tank/fuel_container
	var/target_scan_ticks = 30
	var/report_num = 0
	var/scan_process = 0
	var/temperature = 273	//measured in kelvin, if this exceeds 1200, the machine is damaged and requires repairs
							//if this exceeds 600 and safety is enabled it will shutdown
							//temp greater than 600 also requires a safety prompt to initiate scanning
	var/max_temp = 450

/obj/machinery/anomaly/New()
	..()

	//for analysis debugging
	/*var/obj/item/weapon/reagent_containers/glass/solution_tray/S = new(src.loc)
	var/turf/unsimulated/mineral/diamond/D
	for(var/turf/unsimulated/mineral/diamond/M in world)
		D = M
		break
	S.reagents.add_reagent("analysis_sample", 1, D.geological_data)
	S.reagents.add_reagent("chlorine", 1, null)*/

/obj/machinery/anomaly/process()
	//not sure if everything needs to heat up, or just the GLPC
	var/datum/gas_mixture/env = loc.return_air()
	var/environmental_temp = env.temperature
	if(scan_process)
		if(scan_process++ > target_scan_ticks)
			FinishScan()
		else if(temperature > 400)
			src.visible_message("\icon[src] shuts down from the heat!", 2)
			scan_process = 0
		else if(temperature > 350 && prob(10))
			src.visible_message("\icon[src] bleets plaintively.", 2)
			if(temperature > 400)
				scan_process = 0

		//show we're busy
		if(prob(5))
			src.visible_message("\icon[src] [pick("whirrs","chuffs","clicks")][pick(" quietly"," softly"," sadly"," excitedly"," energetically"," angrily"," plaintively")].", 2)

		use_power = 2

		icon_state = "analyser_processing"
	else
		use_power = 1
		icon_state = "analyser"
		if(prob(10))
			flick(src, "analyser_processing")

	//Add 3000 joules when active.  This is about 0.6 degrees per tick.
	//May need adjustment
	if(use_power == 1)
		var/heat_added = active_power_usage *XENOARCH_HEAT_COEFFICIENT

		if(temperature < max_temp)
			temperature += heat_added/XENOARCH_HEAT_CAPACITY

		var/temperature_difference = abs(environmental_temp-temperature)
		var/datum/gas_mixture/removed = loc.remove_air(env.total_moles()*0.25)
		var/heat_capacity = removed.heat_capacity()

		heat_added = max(temperature_difference*heat_capacity, XENOARCH_MAX_ENERGY_TRANSFER)

		if(temperature > environmental_temp)
			//cool down to match the air
			temperature = max(TCMB, temperature - heat_added/XENOARCH_HEAT_CAPACITY)
			removed.temperature = max(TCMB, removed.temperature + heat_added/heat_capacity)

			if(temperature_difference > 10 && prob(5))
				src.visible_message("\icon[src] hisses softly.", 2)

		else
			//heat up to match the air
			temperature = max(TCMB, temperature + heat_added/XENOARCH_HEAT_CAPACITY)
			removed.temperature = max(TCMB, removed.temperature - heat_added/heat_capacity)

			if(temperature_difference > 10 && prob(5))
				src.visible_message("\icon[src] plinks quietly.", 2)

		env.merge(removed)

//this proc should be overriden by each individual machine
/obj/machinery/anomaly/attack_hand(var/mob/user as mob)
	if(..()) return
	if(stat & (NOPOWER|BROKEN))
		return
	user.machine = src
	var/dat = "[src.name]
"

	// AUTOFIXED BY fix_string_idiocy.py
	// C:\Users\Rob\Documents\Projects\vgstation13\code\modules\research\xenoarchaeology\machinery\analysis_base.dm:111: dat += "Module heat level: [temperature] kelvin
"
	dat += {"Module heat level: [temperature] kelvin

		Safeties set at 350k, shielding failure at 400k. Failure to maintain safe heat levels may result in equipment damage.

"}
	// END AUTOFIX
	if(scan_process)
		dat += "Scan in progress

"
	else
		dat += "[held_container ? "Eject beaker" : "No beaker inserted."]
"
		//dat += "[fuel_container ? "Eject fuel tank" : "No fuel tank inserted."]
"
		dat += "[held_container ? "Begin scanning" : ""]"

	// AUTOFIXED BY fix_string_idiocy.py
	// C:\Users\Rob\Documents\Projects\vgstation13\code\modules\research\xenoarchaeology\machinery\analysis_base.dm:120: dat += "
"
	dat += {"

		Refresh

		Close
"}
	// END AUTOFIX
	user << browse(dat, "window=anomaly;size=450x500")
	onclose(user, "anomaly")

obj/machinery/anomaly/attackby(obj/item/weapon/W as obj, mob/living/user as mob)
	if(istype(W, /obj/item/weapon/reagent_containers/glass))
		//var/obj/item/weapon/reagent_containers/glass/G = W
		if(held_container)
			user << "You must remove the [held_container] first."
		else
			user << "You put the [W] into the [src]."
			user.drop_item()
			W.loc = src

			held_container = W
			updateDialog()

		return 1 // avoid afterattack() being called
	/*else if(istype(W, /obj/item/weapon/tank))
		//var/obj/item/weapon/reagent_containers/glass/G = W
		if(fuel_container)
			user << "You must remove the [fuel_container] first."
		else
			user << "You put the [fuel_container] into the [src]."
			user.drop_item(W, src)
			fuel_container.loc = src
			fuel_container = W
			updateDialog()*/
	else
		return ..()

obj/machinery/anomaly/proc/ScanResults()
	//instantiate in children to produce unique scan behaviour
	return "Error initialising scanning components."

obj/machinery/anomaly/proc/FinishScan()
	scan_process = 0
	updateDialog()

	//determine the results and print a report
	if(held_container)
		src.visible_message("\icon[src] makes an insistent chime.", 2)
		var/obj/item/weapon/paper/P = new(src.loc)
		P.name = "[src] report #[++report_num]"
		P.info = "[src] analysis report #[report_num]

" + ScanResults()
		P.stamped = list(/obj/item/weapon/stamp)
		P.overlays = list("paper_stamped")
	else
		src.visible_message("\icon[src] makes a low buzzing noise.", 2)

obj/machinery/anomaly/Topic(href, href_list)
	if(..()) return
	usr.set_machine(src)
	if(href_list["close"])
		usr << browse(null, "window=anomaly")
		usr.machine = null
	if(href_list["eject_beaker"])
		held_container.loc = src.loc
		held_container = null
	if(href_list["eject_fuel"])
		fuel_container.loc = src.loc
		fuel_container = null
	if(href_list["begin"])
		if(temperature >= 350)
			var/proceed = input("Unsafe internal temperature detected, enter YES below to continue.","Warning")
			if(proceed == "YES" && !..()) //call parent again to run distance and power checks again.
				scan_process = 1
		else
			scan_process = 1

	updateUsrDialog()

//whether the carrier sample matches the possible finds
//results greater than a threshold of 0.6 means a positive result
obj/machinery/anomaly/proc/GetResultSpecifity(var/datum/geosample/scanned_sample, var/carrier_name)
	var/specifity = 0
	if(scanned_sample && carrier_name)

		if(scanned_sample.find_presence.Find(carrier_name))
			specifity = 0.75 * (scanned_sample.find_presence[carrier_name] / scanned_sample.total_spread) + 0.25
		else
			specifity = rand(0, 0.5)

	return specifity


code:
// This machine tells the distance to a nearby artifact, if there is one

obj/machinery/anomaly/fourier_transform
	name = "Fourier Transform spectroscope"

obj/machinery/anomaly/fourier_transform/ScanResults()
	var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."

	var/datum/geosample/scanned_sample
	var/carrier
	var/num_reagents = 0

	for(var/datum/reagent/A in held_container.reagents.reagent_list)
		var/datum/reagent/R = A
		if(istype(R, /datum/reagent/analysis_sample))
			scanned_sample = R.data
		else
			carrier = R.id
		num_reagents++

	if(num_reagents == 2 && scanned_sample && carrier)
		//all necessary components are present
		var/specifity = GetResultSpecifity(scanned_sample, carrier)
		var/distance = scanned_sample.artifact_distance
		if(distance > 0)
			distance += (2 * rand() - 1) * distance * 0.05
			results = "Fourier transform analysis on anomalous energy absorption through carrier ([carrier]) indicates source located inside emission radius ([95 * specifity]% accuracy): [distance]."
		else
			results = "Energy dispersion detected throughout sample consistent with background readings.<br>"
		if(carrier == scanned_sample.source_mineral)
			results += "Warning, analysis may be contaminated by high quantities of molecular carrier present throughout sample."

	return results


code:
// This machine shows the materials that are present

obj/machinery/anomaly/gas_chromatography
	name = "Gas Chromatography spectrometer"

obj/machinery/anomaly/gas_chromatography/ScanResults()
	var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."

	var/datum/geosample/scanned_sample
	var/carrier
	var/num_reagents = 0

	for(var/datum/reagent/A in held_container.reagents.reagent_list)
		var/datum/reagent/R = A
		if(istype(R, /datum/reagent/analysis_sample))
			scanned_sample = R.data
		else
			carrier = R.id
		num_reagents++

	if(num_reagents == 2 && scanned_sample)
		var/specifity = GetResultSpecifity(scanned_sample, carrier)
		results = "Chromatography partitioning analysis over carrier ([carrier]) indicates the following elements present ([100 * specifity]% accuracy):

"

		var/num_found = 0
		for(var/index=1,index <= scanned_sample.find_presence.len, index++)
			var/find = scanned_sample.find_presence[index]
			if(find && prob(100 * specifity))
				results += " - " + finds_as_strings[index] + "
"
				num_found++

		if(!num_found)
			results = "Chromatography partitioning results over carrier ([carrier]) to determine elemental makeup were inconclusive.
"

		if(!carrier)
			results += "
No carrier detected, scan accuracy affected.
"

	return results


code:
obj/machinery/anomaly/hyperspectral
	name = "Hyperspectral Imager"
	icon = 'icons/obj/xenoarchaeology.dmi'
	icon_state = "scanner"

obj/machinery/anomaly/hyperspectral/process()
	..()
	if(scan_process)
		icon_state = "scanner_active"
	else
		icon_state = "scanner"
		if(prob(10))
			flick(src, "scanner_active")

obj/machinery/anomaly/hyperspectral/ScanResults()
	var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."

	var/datum/geosample/scanned_sample
	var/carrier
	var/num_reagents = 0

	for(var/datum/reagent/A in held_container.reagents.reagent_list)
		var/datum/reagent/R = A
		if(istype(R, /datum/reagent/analysis_sample))
			scanned_sample = R.data
		else
			carrier = R.id
		num_reagents++

	if(num_reagents == 2 && scanned_sample && carrier)
		//all necessary components are present
		var/specifity = GetResultSpecifity(scanned_sample, carrier)
		results = "Spectral signature over carrier ([carrier]):
"
		if(specifity <= 0.25)
			//results += "
"
			results += ""
		else if(specifity <= 0.5)
			//results += "
"
			results += ""
		else if(specifity <= 0.75)
			//results += "
"
			results += ""
		else
			//results += "
"
			results += ""

		results += "
"
		if(scanned_sample.artifact_id)
			results += "Detected energy signatures [100 * (1 - specifity)]% consistent with standard background readings.
"
			if(prob( (specifity + 0.5 * (1 - specifity)) * 100))
				results += "Anomalous exotic energy signature isolated: [scanned_sample.artifact_id]."
		else
			results += "Detected energy signatures [95 + 5 * (2 * rand() - 1) * (1 - specifity)]% consistent with standard background readings."

	return results


code:
// This machine shows the amount of a certain material that is present

obj/machinery/anomaly/ion_mobility
	name = "Ion Mobility Spectrometer"
	desc = "A specialised, complex analysis machine."
	icon = 'icons/obj/virology.dmi'
	icon_state = "analyser"

obj/machinery/anomaly/ion_mobility/ScanResults()
	var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."

	var/datum/geosample/scanned_sample
	var/carrier
	var/num_reagents = 0

	for(var/datum/reagent/A in held_container.reagents.reagent_list)
		var/datum/reagent/R = A
		if(istype(R, /datum/reagent/analysis_sample))
			scanned_sample = R.data
		else
			carrier = R.id
		num_reagents++

	if(num_reagents == 2 && scanned_sample && carrier)
		//all necessary components are present
		results = "Kinetic analysis on sample's ionic residue in carrier ([carrier]) indicates the dissonance spread:

"
		var/found = 0
		if(scanned_sample.find_presence.Find(carrier))
			var/dis_ratio = scanned_sample.find_presence[carrier]
			var/desc_index = responsive_carriers.Find(carrier)
			results += " - [finds_as_strings[desc_index]]: [dis_ratio]
"
			found++
		/*
		for(var/index=1,index <= scanned_sample.find_presence.len, index++)
			var/find = scanned_sample.find_presence[index]
			//world << "index: [index], find: [find], response: [responsive_carriers[index]], carrier: [carrier]"
			if(find && responsive_carriers[index] == carrier)
				results += " - [finds_as_strings[index]] [find * 100]%
"
				found++
				*/
		if(!found)
			results = "Kinetic analysis on sample's ionic residue in carrier ([carrier]) to determine composition were inconclusive.
"
		if(carrier == scanned_sample.source_mineral)
			results += "Warning, analysis may be contaminated by high quantities of molecular carrier present throughout sample."

	return results


code:
// This machine shows the age for newer finds

obj/machinery/anomaly/isotope_ratio
	name = "Isotope ratio spectrometer"
	desc = "A specialised, complex analysis machine."
	icon = 'icons/obj/virology.dmi'
	icon_state = "analyser"

obj/machinery/anomaly/isotope_ratio/ScanResults()
	var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."

	var/datum/geosample/scanned_sample
	var/carrier_name
	var/num_reagents = 0

	for(var/datum/reagent/A in held_container.reagents.reagent_list)
		var/datum/reagent/R = A
		if(istype(R, /datum/reagent/analysis_sample))
			scanned_sample = R.data
		else
			carrier_name = R.id
		num_reagents++

	if(num_reagents == 2 && scanned_sample && carrier_name)
		var/accuracy = GetResultSpecifity(scanned_sample, carrier_name)
		accuracy += 0.5 * (1 - accuracy) / scanned_sample.total_spread
		if(!accuracy)
			accuracy = rand(0.01, 0.5)
		results = "Isotope decay analysis in carrier ([carrier_name]) indicates age ([100 * accuracy]% accuracy):

"

		if(scanned_sample.age_billion)
			//scramble the results
			var/displayed_age_thousands = rand(0, 999)
			var/displayed_age_millions = rand(0, 999)
			results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.
"
		else if(scanned_sample.age_million)
			var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - accuracy) * (2 * rand() - 1)), 0)
			var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - accuracy) * (4 * rand() - 2)), 0)
			results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.
"
		else if(scanned_sample.age_thousand)
			var/displayed_age = scanned_sample.age + scanned_sample.age * ((1 - accuracy) * (2 * rand() - 1))
			var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - accuracy) * (2 * rand() - 1)), 0)
			results += "[displayed_age_thousands + displayed_age / 1000] thousand years.
"
		else
			var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - accuracy) * (2 * rand() - 1)), 0)
			results += "[displayed_age] years.
"

		results += "
Warning, results only valid up to ages of one billion years."

	return results


code:
/obj/machinery/artifact_analyser
	name = "Anomaly Analyser"
	desc = "Studies the emissions of anomalous materials to discover their uses."
	icon = 'icons/obj/virology.dmi'
	icon_state = "isolator"
	anchored = 1
	density = 1
	var/scan_in_progress = 0
	var/scan_num = 0
	var/obj/scanned_obj
	var/obj/machinery/artifact_scanpad/owned_scanner = null
	var/scan_completion_time = 0
	var/scan_duration = 120
	var/obj/scanned_object
	var/report_num = 0

/obj/machinery/artifact_analyser/New()
	..()
	reconnect_scanner()

/obj/machinery/artifact_analyser/proc/reconnect_scanner()
	//connect to a nearby scanner pad
	owned_scanner = locate(/obj/machinery/artifact_scanpad) in get_step(src, dir)
	if(!owned_scanner)
		owned_scanner = locate(/obj/machinery/artifact_scanpad) in orange(1, src)

/obj/machinery/artifact_analyser/attack_hand(var/mob/user as mob)
	if(..()) return
	src.add_fingerprint(user)
	interact(user)

/obj/machinery/artifact_analyser/interact(mob/user)
	if(!owned_scanner)
		reconnect_scanner()
	if(..()) return
	if(stat & (NOPOWER|BROKEN) || get_dist(src, user) > 1)
		user.unset_machine(src)
		return

	var/dat = "Anomalous material analyser
"
	dat += "
"
	if(!owned_scanner)
		owned_scanner = locate() in orange(1, src)

	if(!owned_scanner)
		dat += "Unable to locate analysis pad.
"
	else if(scan_in_progress)
		dat += "Please wait. Analysis in progress.
"
		dat += "Halt scanning.
"
	else
		dat += "Scanner is ready.
"
		dat += "Begin scanning.
"

	dat += "
"
	dat += "
"
	dat += "Refresh Close"
	user << browse(dat, "window=artanalyser;size=450x500")
	user.set_machine(src)
	onclose(user, "artanalyser")

/obj/machinery/artifact_analyser/process()
	if(scan_in_progress && world.time > scan_completion_time)
		//finish scanning
		scan_in_progress = 0
		updateDialog()

		//print results
		var/results = ""
		if(!owned_scanner)
			reconnect_scanner()
		if(!owned_scanner)
			results = "Error communicating with scanner."
		else if(!scanned_object || scanned_object.loc != owned_scanner.loc)
			results = "Unable to locate scanned object. Ensure it was not moved in the process."
		else
			results = get_scan_info(scanned_object)

		src.visible_message("[name] states, \"Scanning complete.\"")
		var/obj/item/weapon/paper/P = new(src.loc)
		P.name = "[src] report #[++report_num]"
		P.info = "[src] analysis report #[report_num]
"
		P.info += "
"
		P.info += "\icon[scanned_object] [results]"
		P.stamped = list(/obj/item/weapon/stamp)
		P.overlays = list("paper_stamped")

		if(scanned_object && istype(scanned_object, /obj/machinery/artifact))
			var/obj/machinery/artifact/A = scanned_object
			A.anchored = 0
			A.being_used = 0

/obj/machinery/artifact_analyser/Topic(href, href_list)
	if(..()) return
	if(href_list["begin_scan"])
		if(!owned_scanner)
			reconnect_scanner()
		if(owned_scanner)
			var/artifact_in_use = 0
			for(var/obj/O in owned_scanner.loc)
				if(O == owned_scanner)
					continue
				if(O.invisibility)
					continue
				if(istype(scanned_object, /obj/machinery/artifact))
					var/obj/machinery/artifact/A = scanned_object
					if(A.being_used)
						artifact_in_use = 1
					else
						A.anchored = 1
						A.being_used = 1

				if(artifact_in_use)
					src.visible_message("[name] states, \"Cannot harvest. Too much interference.\"")
				else
					scanned_object = O
					scan_in_progress = 1
					scan_completion_time = world.time + scan_duration
					src.visible_message("[name] states, \"Scanning begun.\"")
				break
			if(!scanned_object)
				src.visible_message("[name] states, \"Unable to isolate scan target.\"")
	if(href_list["halt_scan"])
		scan_in_progress = 0
		src.visible_message("[name] states, \"Scanning halted.\"")

	if(href_list["close"])
		usr.unset_machine(src)
		usr << browse(null, "window=artanalyser")

	updateDialog()

//hardcoded responses, oh well
/obj/machinery/artifact_analyser/proc/get_scan_info(var/obj/scanned_obj)
	switch(scanned_obj.type)
		if(/obj/machinery/auto_cloner)
			return "Automated cloning pod - appears to rely on organic nanomachines with a self perpetuating \
			ecosystem involving self cannibalism and a symbiotic relationship with the contained liquid.

\
			Structure is composed of a carbo-titanium alloy with interlaced reinforcing energy fields, and the contained liquid \
			resembles proto-plasmic residue supportive of single cellular developmental conditions."
		if(/obj/machinery/power/supermatter)
			return "Super dense plasma clump - Appears to have been shaped or hewn, structure is composed of matter 2000% denser than ordinary carbon matter residue.\
			Potential application as unrefined plasma source."
		if(/obj/structure/constructshell)
			return "Tribal idol - Item resembles statues/emblems built by superstitious pre-warp civilisations to honour their gods. Material appears to be a \
			rock/plastcrete composite."
		if(/obj/machinery/giga_drill)
			return "Automated mining drill - structure composed of titanium-carbide alloy, with tip and drill lines edged in an alloy of diamond and plasma."
		if(/obj/structure/cult/pylon)
			return "Tribal pylon - Item resembles statues/emblems built by cargo cult civilisations to honour energy systems from post-warp civilisations."
		if(/obj/mecha/working/hoverpod)
			return "Vacuum capable repair pod - Item is a remarkably intact single man repair craft capable of flight in a vacuum. Outer shell composed of primarily \
			post-warp hull alloys, with internal wiring and circuitry consistent with modern electronics and engineering."
		if(/obj/machinery/replicator)
			return "Automated construction unit - Item appears to be able to synthesize synthetic items, some with simple internal circuitry. Method unknown, \
			phasing suggested?"
		if(/obj/structure/crystal)
			return "Crystal formation - Pseudo organic crystalline matrix, unlikely to have formed naturally. No known technology exists to synthesize this exact composition."
		if(/obj/machinery/artifact)
			//the fun one
			var/obj/machinery/artifact/A = scanned_obj
			var/out = "Anomalous alien device - Composed of an unknown alloy, "

			//primary effect
			if(A.my_effect)
				//what kind of effect the artifact has
				switch(A.my_effect.effect_type)
					if(1)
						out += "concentrated energy emissions"
					if(2)
						out += "intermittent psionic wavefront"
					if(3)
						out += "electromagnetic energy"
					if(4)
						out += "high frequency particles"
					if(5)
						out += "organically reactive exotic particles"
					if(6)
						out += "interdimensional/bluespace? phasing"
					if(7)
						out += "atomic synthesis"
					else
						out += "low level energy emissions"
				out += " have been detected "

				//how the artifact does it's effect
				switch(A.my_effect.effect)
					if(1)
						out += " emitting in an ambient energy field."
					if(2)
						out += " emitting in periodic bursts."
					else
						out += " interspersed throughout substructure and shell."

				if(A.my_effect.trigger >= 0 && A.my_effect.trigger <= 4)
					out += " Activation index involves physical interaction with artifact surface."
				else if(A.my_effect.trigger >= 5 && A.my_effect.trigger <= 8)
					out += " Activation index involves energetic interaction with artifact surface."
				else if(A.my_effect.trigger >= 9 && A.my_effect.trigger <= 12)
					out += " Activation index involves precise local atmospheric conditions."
				else
					out += " Unable to determine any data about activation trigger."

			//secondary:
			if(A.secondary_effect)
				//sciencey words go!
				out += "

Warning, internal scans indicate ongoing [pick("subluminous","subcutaneous","superstructural")] activity operating \
				independantly from primary systems. Auxiliary activity involves "

				//what kind of effect the artifact has
				switch(A.secondary_effect.effect_type)
					if(1)
						out += "concentrated energy emissions"
					if(2)
						out += "intermittent psionic wavefront"
					if(3)
						out += "electromagnetic energy"
					if(4)
						out += "high frequency particles"
					if(5)
						out += "organically reactive exotic particles"
					if(6)
						out += "interdimensional/bluespace? phasing"
					if(7)
						out += "atomic synthesis"
					else
						out += "low level radiation"

				//how the artifact does it's effect
				switch(A.secondary_effect.effect)
					if(1)
						out += " emitting in an ambient energy field."
					if(2)
						out += " emitting in periodic bursts."
					else
						out += " interspersed throughout substructure and shell."

				if(A.secondary_effect.trigger >= 0 && A.secondary_effect.trigger <= 4)
					out += " Activation index involves physical interaction with artifact surface, but subsystems indicate \
					anomalous interference with standard attempts at triggering."
				else if(A.secondary_effect.trigger >= 5 && A.secondary_effect.trigger <= 8)
					out += " Activation index involves energetic interaction with artifact surface, but subsystems indicate \
					anomalous interference with standard attempts at triggering."
				else if(A.secondary_effect.trigger >= 9 && A.secondary_effect.trigger <= 12)
					out += " Activation index involves precise local atmospheric conditions, but subsystems indicate \
					anomalous interference with standard attempts at triggering."
				else
					out += " Unable to determine any data about activation trigger."
			return out
		else
			//it was an ordinary item
			return "[scanned_obj.name] - Mundane application, composed of carbo-ferritic alloy composite."


code:
//cael - some changes here. the analysis pad is entirely new

/obj/machinery/artifact_analyser
	name = "Artifact Analyser"
	desc = "Studies the structure of artifacts to discover their uses."
	icon = 'icons/obj/virology.dmi'
	icon_state = "analyser"
	anchored = 1
	density = 1
	var/working = 0
	var/accuO = 0
	var/accuT = 0
	var/accuE1 = 0
	var/accuE2 = 0
	var/aorigin = "None"
	var/atrigger = "None"
	var/aeffect1 = "None"
	var/aeffect2 = "None"
	var/list/origin_bonuses
	var/list/trigger_bonuses
	var/list/function_bonuses
	var/list/range_bonuses
	var/cur_id = ""
	var/scan_num = 0
	var/obj/machinery/artifact/cur_artifact = null
	var/obj/machinery/analyser_pad/owned_pad = null
	var/list/allorigins = list("Ancient Robots","Martian","Wizard Federation","Extradimensional","Precursor")
	var/list/alltriggers = list("Contact with Living Organism","Heavy Impact","Contact with Energy Source","Contact with Hydrogen","Contact with Corrosive Substance","Contact with Volatile Substance","Contact with Toxins","Exposure to Heat")
	var/list/alleffects = list("Healing Device","Anti-biological Weapon","Non-lethal Stunning Trap","Mechanoid Repair Module","Mechanoid Deconstruction Device","Power Generator","Power Drain","Stellar Mineral Attractor","Agriculture Regulator","Shield Generator","Space-Time Displacer")
	var/list/allranges = list("Constant Short-Range Energy Field","Medium Range Energy Pulses","Long Range Energy Pulses","Extreme Range Energy Pulses","Requires contact with subject")

/obj/machinery/artifact_analyser/New()
	..()
	origin_bonuses = new/list()
	origin_bonuses["ancient"] = 0
	origin_bonuses["martian"] = 0
	origin_bonuses["wizard"] = 0
	origin_bonuses["eldritch"] = 0
	origin_bonuses["precursor"] = 0
	trigger_bonuses = new/list()
	trigger_bonuses["ancient"] = 0
	trigger_bonuses["martian"] = 0
	trigger_bonuses["wizard"] = 0
	trigger_bonuses["eldritch"] = 0
	trigger_bonuses["precursor"] = 0
	function_bonuses = new/list()
	function_bonuses["ancient"] = 0
	function_bonuses["martian"] = 0
	function_bonuses["wizard"] = 0
	function_bonuses["eldritch"] = 0
	function_bonuses["precursor"] = 0
	range_bonuses = new/list()
	range_bonuses["ancient"] = 0
	range_bonuses["martian"] = 0
	range_bonuses["wizard"] = 0
	range_bonuses["eldritch"] = 0
	range_bonuses["precursor"] = 0
	//
	spawn(10)
		owned_pad = locate() in orange(1, src)

/obj/machinery/artifact_analyser/attack_hand(var/mob/user as mob)
	if(stat & (NOPOWER|BROKEN))
		return
	user.machine = src
	var/dat = "Artifact Analyser
"
	dat += "

"
	if(!owned_pad)
		dat += "Unable to locate analysis pad.
"
		dat += "

"
	else if (!src.working)
		dat += "Artifact ID: [cur_id]
"
		dat += "Artifact Origin: [aorigin] ([accuO]%)
"
		dat += "Activation Trigger: [atrigger] ([accuT]%)
"
		dat += "Artifact Function: [aeffect1] ([accuE1]%)
"
		dat += "Artifact Range: [aeffect2] ([accuE2]%)

"
		dat += "

"
		dat += "Artifact ID is determined from unique energy emission signatures.
"
		dat += "Analyse Artifact (Scan number #[scan_num+1])
"
		dat += "Upload/update artifact scan
"
		dat += "Print Page
"
	else
		dat += "Please wait. Analysis in progress.
"
		dat += "

"
	//
	dat += "Close
"
	user << browse(dat, "window=artanalyser;size=450x500")
	onclose(user, "artanalyser")

/obj/machinery/artifact_analyser/process()
	if(stat & (NOPOWER|BROKEN))
		return
	use_power(350)
	//
	if(!owned_pad)
		for(var/obj/machinery/analyser_pad/pad in range(1))
			owned_pad = pad
			break

/obj/machinery/artifact_analyser/proc/AA_FailedAnalysis(var/failtype)
	switch(failtype)
		if(1)
			src.aorigin = "Failed to Identify"
			if (prob(20)) src.aorigin = pick(src.allorigins)
		if(2)
			src.atrigger = "Failed to Identify"
			if (prob(20)) src.atrigger = pick(src.alltriggers)
		if(3)
			src.aeffect1 = "Failed to Identify"
			if (prob(20)) src.aeffect1 = pick(src.alleffects)
		if(4)
			src.aeffect2 = "Failed to Identify"
			if (prob(20)) src.aeffect2 = pick(src.allranges)

/obj/machinery/artifact_analyser/proc/AA_Analyse()
	if(!cur_artifact)
		return
	src.accuO = 5 + rand(0,10) + origin_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
	src.accuT = 5 + rand(0,10) + trigger_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
	src.accuE1 = 5 + rand(0,10) + function_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
	src.accuE2 = 5 + rand(0,10) + range_bonuses[cur_artifact.origin] + cur_artifact.activated * 50

	//keep any correctly determined properties the same
	var/origin_correct = 0
	var/trigger_correct = 0
	var/function_correct = 0
	var/range_correct = 0
	if(cur_id == cur_artifact.display_id)
		if(src.aorigin == cur_artifact.origin)
			origin_correct = 1

		if(src.atrigger == cur_artifact.my_effect.trigger)
			trigger_correct = 1
		else if(src.atrigger == cur_artifact.my_effect.triggerX)
			trigger_correct = 1

		if(src.aeffect1 == cur_artifact.my_effect.effecttype)
			function_correct = 1

		if(src.aeffect2 == cur_artifact.my_effect.effectmode)
			range_correct = 1

	if (src.accuO > 100) src.accuO = 100
	if (src.accuT > 100) src.accuT = 100
	if (src.accuE1 > 100) src.accuE1 = 100
	if (src.accuE2 > 100) src.accuE2 = 100
	// Roll to generate report
	if (prob(accuO) || origin_correct)
		switch(cur_artifact.origin)
			if("ancient") src.aorigin = "Ancient Robots"
			if("martian") src.aorigin = "Martian"
			if("wizard") src.aorigin = "Wizard Federation"
			if("eldritch") src.aorigin = "Extradimensional"
			if("precursor") src.aorigin = "Precursor"
			else src.aorigin = "Unknown Origin"
		origin_bonuses[cur_artifact.origin] += 10
	else
		AA_FailedAnalysis(1)
		origin_bonuses[cur_artifact.origin] += 5
	if (prob(accuT) || trigger_correct)
		switch(cur_artifact.my_effect.trigger)
			if("touch") src.atrigger = "Contact with Living Organism"
			if("force") src.atrigger = "Heavy Impact"
			if("energy") src.atrigger = "Contact with Energy Source"
			if("chemical")
				switch(cur_artifact.my_effect.triggerX)
					if("hydrogen") src.atrigger = "Contact with Hydrogen"
					if("corrosive") src.atrigger = "Contact with Corrosive Substance"
					if("volatile") src.atrigger = "Contact with Volatile Substance"
					if("toxin") src.atrigger = "Contact with Toxins"
			if("heat") src.atrigger = "Exposure to Heat"
			else src.atrigger = "Unknown Trigger"
		trigger_bonuses[cur_artifact.origin] += 5
	else
		AA_FailedAnalysis(2)
		trigger_bonuses[cur_artifact.origin] += 1
	if (prob(accuE1) || function_correct)
		switch(cur_artifact.my_effect.effecttype)
			if("healing")  src.aeffect1 = "Healing Device"
			if("injure") src.aeffect1 = "Anti-biological Weapon"
			// if("stun") src.aeffect1 = "Non-lethal Stunning Trap"
			if("roboheal") src.aeffect1 = "Mechanoid Repair Module"
			if("robohurt") src.aeffect1 = "Mechanoid Deconstruction Device"
			if("cellcharge") src.aeffect1 = "Power Generator"
			if("celldrain") src.aeffect1 = "Power Drain"
			if("planthelper") src.aeffect1 = "Agriculture Regulator"
			if("forcefield") src.aeffect1 = "Shield Generator"
			if("teleport") src.aeffect1 = "Space-Time Displacer"
			else src.aeffect1 = "Unknown Effect"
		function_bonuses[cur_artifact.origin] += 5
	else
		AA_FailedAnalysis(3)
		function_bonuses[cur_artifact.origin] += 1
	if (prob(accuE2) || range_correct)
		switch(cur_artifact.my_effect.effectmode)
			if("aura") src.aeffect2 = "Constant Short-Range Energy Field"
			if("pulse")
				if(cur_artifact.my_effect.aurarange > 7) src.aeffect2 = "Long Range Energy Pulses"
				else src.aeffect2 = "Medium Range Energy Pulses"
			if("worldpulse") src.aeffect2 = "Extreme Range Energy Pulses"
			if("contact") src.aeffect2 = "Requires contact with subject"
			else src.aeffect2 = "Unknown Range"
		range_bonuses[cur_artifact.origin] += 5
	else
		AA_FailedAnalysis(4)
		range_bonuses[cur_artifact.origin] += 1

	cur_artifact.name = "alien artifact ([cur_artifact.display_id])"
	cur_artifact.desc = "A large alien device. It has a small tag near the bottom that reads \"[cur_artifact.display_id]\"."
	cur_id = cur_artifact.display_id
	cur_artifact.my_effect.artifact_id = cur_artifact.display_id

/obj/machinery/artifact_analyser/Topic(href, href_list)
	if(..()) return 1
	if(href_list["analyse"])
		if(owned_pad)
			var/turf/pad_turf = get_turf(owned_pad)
			var/findarti = 0
			for(var/obj/machinery/artifact/A in pad_turf.contents)
				findarti++
				cur_artifact = A
			if (findarti == 1)
				if(cur_artifact && cur_artifact.being_used)
					var/message = "[src] states, \"Cannot analyse. Excess energy drain is disrupting signal.\""
					src.visible_message(message, message)
				else
					cur_artifact.anchored = 1
					cur_artifact.being_used = 1
					src.working = 1
					src.icon_state = "analyser_processing"
					var/time = rand(30,50) + max(0, 300 - scan_num * 10)
					/*for(var/i = artifact_research.starting_tier, i <= artifact_research.max_tiers, i++)
						for(var/datum/artiresearch/R in artifact_research.researched_items[i])
							if (R.bonustype == "analyser") time -= R.bonusTime*/
					time *= 10
					var/message = "[src] states, \"Commencing analysis.\""
					src.visible_message(message, message)
					use_power(500)
					spawn(time)
						src.working = 0
						icon_state = "analyser"
						cur_artifact.anchored = 0
						cur_artifact.being_used = 0
						if(cur_artifact.loc == pad_turf)
							AA_Analyse()
							scan_num++
							message = "[src] states, \"Analysis complete.\""
							src.visible_message(message, message)
							use_power(500)
			else if (findarti > 1)
				var/message = "[src] states, \"Cannot analyse. Error isolating energy signature.\""
				src.visible_message(message, message)
			else
				var/message = "[src] states, \"Cannot analyse. No noteworthy energy signature isolated.\""
				src.visible_message(message, message)

	if(href_list["upload"] && cur_id != "")
		//add new datum to every DB in the world
		for(var/obj/machinery/computer/artifact_database/DB in machines)
			var/update = 0
			for(var/datum/catalogued_artifact/CA in DB.catalogued_artifacts)
				if(CA.display_id == cur_id)
					//already there, so update it
					update = 1
					CA.origin = aorigin + " ([accuO]%)"
					CA.trigger = atrigger + " ([accuT]%)"
					CA.effecttype = aeffect1 + " ([accuE1]%)"
					CA.effectmode = aeffect2 + " ([accuE2]%)"
			if(!update)
				//not there, so add it
				var/datum/catalogued_artifact/CA = new()
				CA.display_id = cur_id
				CA.origin = aorigin + " ([accuO]%)"
				CA.trigger = atrigger + " ([accuT]%)"
				CA.effecttype = aeffect1 + " ([accuE1]%)"
				CA.effectmode = aeffect2 + " ([accuE2]%)"
				DB.catalogued_artifacts.Add(CA)
			use_power(100)

	if(href_list["print"])
		var/r = "Artifact Analysis Report (Scan #[scan_num])
"
		r += "Artifact ID: [cur_id] (determined from unique energy emission signatures)
"
		r += "Artifact Origin: [aorigin] ([accuO]%)
"
		r += "Activation Trigger: [atrigger] ([accuT]%)
"
		r += "Artifact Function: [aeffect1] ([accuE1]%)
"
		r += "Artifact Range: [aeffect2] ([accuE2]%)

"
		var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(src.loc)
		P.name = "Artifact Analysis Report #[scan_num]"
		P.info = r
		for(var/mob/O in hearers(src, null))
			O.show_message("\icon[src] The [src.name] prints a sheet of paper", 3)
		use_power(10)

	if(href_list["close"])
		usr << browse(null, "window=artanalyser")
		usr.machine = null

	src.updateDialog()

//stick artifacts onto this then switch the analyser on
/obj/machinery/analyser_pad
	name = "artifact analysis pad"
	desc = "Studies the structure of artifacts to discover their uses."
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "tele0"
	anchored = 1
	density = 0

/obj/machinery/analyser_pad/New()
	..()
	/*spawn(10)
		for(var/obj/machinery/artifact_analyser/analyser in orange(1))
			world << "pad found analyser"
			if(!analyser.owned_pad)
				analyser.owned_pad = src
				world << "pad set analyser to self"
				break*/


code:
/datum/catalogued_artifact
	var/trigger = "touch"      // What activates it?
	var/effecttype = "healing" // What does it do?
	var/effectmode = "aura"    // How does it carry out the effect?
	var/display_id = ""        // Artifact ID to display once successfully scanned
	var/origin = ""

/obj/machinery/computer/artifact_database
	name = "Artifact Database"
	icon_state = "rdcomp"
	var/list/catalogued_artifacts

/obj/machinery/computer/artifact_database/New()
	..()
	catalogued_artifacts = new/list

/obj/machinery/computer/artifact_database/Topic(href, href_list)
	if(..()) return 1
	if( href_list["close"] )
		usr << browse(null, "window=artifact_db")
		usr.machine = null
	updateDialog()

/obj/machinery/computer/artifact_database/process()
	..()
	updateDialog()

/obj/machinery/computer/artifact_database/interact(mob/user)
	if ((stat & (BROKEN|NOPOWER)))
		user.machine = null
		user << browse(null, "window=artifact_db")
		return
	if ( (!Adjacent(user)) && !issilicon(user))
		if (!user.mutations && !user.mutations.len && !(M_TK in user.mutations))
			user.machine = null
			user << browse(null, "window=artifact_db")
			return

	var/t = "Artifact Database
"
	t += "
"
	for(var/datum/catalogued_artifact/CA in catalogued_artifacts)
		t += "Artifact ID: [CA.display_id] (determined from unique energy emission signatures)
"
		t += "Artifact Origin: [CA.origin]
"
		t += "Activation Trigger: [CA.trigger]
"
		t += "Artifact Function: [CA.effecttype]
"
		t += "Artifact Range: [CA.effectmode]

"
	t += "
"
	t += "Refresh Close
"
	user << browse(t, "window=artifact_db;size=500x800")
	user.machine = src

/*
/datum/artifact_effect
	var/origin = null          // Used in the randomisation/research of the artifact.
	var/trigger = "touch"      // What activates it?
	var/triggerX = "none"      // Used for more varied triggers
	var/effecttype = "healing" // What does it do?
	var/effectmode = "aura"    // How does it carry out the effect?
	var/aurarange = 4          // How far the artifact will extend an aura effect.
	var/display_id = ""        // Artifact ID to display once successfully scanned
	var/list/created_field
*/


code:
/obj/machinery/artifact_harvester
	name = "Exotic Particle Harvester"
	icon = 'icons/obj/virology.dmi'
	icon_state = "incubator"	//incubator_on
	anchored = 1
	density = 1
	idle_power_usage = 50
	active_power_usage = 750
	use_power = 1
	var/harvesting = 0
	var/obj/item/weapon/anobattery/inserted_battery
	var/obj/machinery/artifact/cur_artifact
	var/obj/machinery/artifact_scanpad/owned_scanner = null
	var/chargerate = 0

/obj/machinery/artifact_harvester/New()
	..()
	//connect to a nearby scanner pad
	owned_scanner = locate(/obj/machinery/artifact_scanpad) in get_step(src, dir)
	if(!owned_scanner)
		owned_scanner = locate(/obj/machinery/artifact_scanpad) in orange(1, src)

/obj/machinery/artifact_harvester/attackby(var/obj/I as obj, var/mob/user as mob)
	if(istype(I,/obj/item/weapon/anobattery))
		if(!inserted_battery)
			user << "You insert [I] into [src]."
			user.drop_item()
			I.loc = src
			src.inserted_battery = I
			updateDialog()
		else
			user << "There is already a battery in [src]."
	else
		return..()

/obj/machinery/artifact_harvester/attack_hand(var/mob/user as mob)
	src.add_fingerprint(user)
	interact(user)

/obj/machinery/artifact_harvester/interact(var/mob/user as mob)
	if(stat & (NOPOWER|BROKEN))
		return
	user.set_machine(src)
	var/dat = "Artifact Power Harvester
"
	dat += "

"
	//
	if(owned_scanner)
		if(harvesting)
			if(harvesting > 0)
				dat += "Please wait. Harvesting in progress ([(inserted_battery.stored_charge/inserted_battery.capacity)*100]%).
"
			else
				dat += "Please wait. Energy dump in progress ([(inserted_battery.stored_charge/inserted_battery.capacity)*100]%).
"
			dat += "Halt early
"
		else
			if(inserted_battery)
				dat += "[inserted_battery.name] inserted, charge level: [inserted_battery.stored_charge]/[inserted_battery.capacity] ([(inserted_battery.stored_charge/inserted_battery.capacity)*100]%)
"
				dat += "Energy signature ID:[inserted_battery.battery_effect.artifact_id == "" ? "???" : "[inserted_battery.battery_effect.artifact_id]"]
"
				dat += "Eject battery
"
				dat += "Drain battery of all charge
"
				dat += "Begin harvesting
"

			else
				dat += "No battery inserted.
"
	else
		dat += "Unable to locate analysis pad.
"
	//
	dat += "
"
	dat += "Refresh Close
"
	user << browse(dat, "window=artharvester;size=450x500")
	onclose(user, "artharvester")

/obj/machinery/artifact_harvester/process()
	if(stat & (NOPOWER|BROKEN))
		return
	if(!cur_artifact)
		return

	if(harvesting > 0)
		//chargerate is chargemaxlevel/effectrange
		//creates variable charging rates, with the minimum being 0.5
		inserted_battery.stored_charge += chargerate
		cur_artifact.being_used = 1

		//check if we've finished
		if(inserted_battery.stored_charge >= inserted_battery.capacity)
			inserted_battery.stored_charge = inserted_battery.capacity //Prevents overcharging
			use_power = 1
			harvesting = 0
			cur_artifact.anchored = 0
			cur_artifact.being_used = 0
			src.visible_message("[name] states, \"Battery is full.\"")
			icon_state = "incubator"

	else if(harvesting < 0)
		//dump some charge
		inserted_battery.stored_charge -= 2
		cur_artifact.being_used = 1

		//do the effect
		if(inserted_battery.battery_effect)
			inserted_battery.battery_effect.process()

			//if the effect works by touch, activate it on anyone viewing the console
			/*if(inserted_battery.battery_effect.effect == 0)
				var/list/nearby = viewers(1, src)
				for(var/mob/M in nearby)
					if(M.machine == src)
						inserted_battery.battery_effect.DoEffectTouch(M) THIS IS RETARDED! - Angelite */

		//if there's no charge left, finish
		if(inserted_battery.stored_charge <= 0)
			use_power = 1
			inserted_battery.stored_charge = 0
			harvesting = 0
			cur_artifact.anchored = 0
			if(inserted_battery.battery_effect && inserted_battery.battery_effect.activated)
				inserted_battery.battery_effect.ToggleActivate()
			src.visible_message("[name] states, \"Battery dump completed.\"")
			icon_state = "incubator"
	if(!harvesting && cur_artifact)
		cur_artifact.anchored = 0
		cur_artifact.being_used = 0

/obj/machinery/artifact_harvester/Topic(href, href_list)

	if(..()) return
	if (href_list["harvest"])
		//locate artifact on analysis pad
		cur_artifact = null
		var/articount = 0
		var/obj/machinery/artifact/analysed
		for(var/obj/machinery/artifact/A in get_turf(owned_scanner))
			analysed = A
			articount++

		var/mundane = 0
		for(var/obj/O in get_turf(owned_scanner))
			if(O.invisibility)
				continue
			if(!istype(O, /obj/machinery/artifact) && !istype(O, /obj/machinery/artifact_scanpad))
				mundane++
				break
		for(var/mob/O in get_turf(owned_scanner))
			if(O.invisibility)
				continue
			mundane++
			break
		if(!analysed)
			var/message = "[src] states, \"Cannot harvest, unable to analyse.\""
			src.visible_message(message)
			return
		if(analysed.being_used)
			var/message = "[src] states, \"Cannot harvest. Too much interference.\""
			src.visible_message(message)
		else if(articount == 1 && !mundane)
			cur_artifact = analysed
			if(!cur_artifact)
				return
			//there should already be a battery inserted, but this is just in case
			if(inserted_battery)
				//see if we can clear out an old effect
				//delete it when the ids match to account for duplicate ids having different effects
				if(inserted_battery.battery_effect && inserted_battery.stored_charge <= 0)
					del(inserted_battery.battery_effect)

				//only charge up
				var/matching_id = 0
				if(inserted_battery.battery_effect)
					matching_id = (inserted_battery.battery_effect.artifact_id == cur_artifact.my_effect.artifact_id)
				var/matching_effecttype = 0
				if(inserted_battery.battery_effect)
					matching_effecttype = (inserted_battery.battery_effect.type == cur_artifact.my_effect.type)
				if(!inserted_battery.battery_effect || (matching_id && matching_effecttype))
					chargerate = cur_artifact.my_effect.chargelevelmax / cur_artifact.my_effect.effectrange
					harvesting = 1
					use_power = 2
					cur_artifact.anchored = 1
					cur_artifact.being_used = 1
					icon_state = "incubator_on"
					var/message = "[src] states, \"Beginning artifact energy harvesting.\""
					src.visible_message(message)

					//duplicate the artifact's effect datum
					if(!inserted_battery.battery_effect)
						var/effecttype = cur_artifact.my_effect.type
						var/datum/artifact_effect/E = new effecttype(inserted_battery)

						//duplicate it's unique settings
						for(var/varname in list("chargelevelmax","artifact_id","effect","effectrange","trigger"))
							E.vars[varname] = cur_artifact.my_effect.vars[varname]

						//copy the new datum into the battery
						inserted_battery.battery_effect = E
						inserted_battery.stored_charge = 0
				else
					var/message = "[src] states, \"Cannot harvest. Incompatible energy signatures detected.\""
					src.visible_message(message)
			else if(cur_artifact)
				var/message = "[src] states, \"Cannot harvest. No battery inserted.\""
				src.visible_message(message)
		else if(articount > 1 || mundane)
			var/message = "[src] states, \"Cannot harvest. Error isolating energy signature.\""
			src.visible_message(message)
		else if(!articount)
			var/message = "[src] states, \"Cannot harvest. No noteworthy energy signature isolated.\""
			src.visible_message(message)

	if (href_list["stopharvest"])
		if(!cur_artifact)
			return
		if(harvesting)
			if(harvesting < 0 && inserted_battery.battery_effect && inserted_battery.battery_effect.activated)
				inserted_battery.battery_effect.ToggleActivate()
			harvesting = 0
			cur_artifact.anchored = 0
			cur_artifact.being_used = 0
			src.visible_message("[name] states, \"Activity interrupted.\"")
			icon_state = "incubator"

	if (href_list["ejectbattery"])
		src.inserted_battery.loc = src.loc
		src.inserted_battery = null
		cur_artifact.anchored = 0

	if (href_list["drainbattery"])
		if(inserted_battery)
			if(!cur_artifact)
				return
			if(inserted_battery.battery_effect && inserted_battery.stored_charge > 0)
				if(alert("This action will dump all charge, safety gear is recommended before proceeding","Warning","Continue","Cancel"))
					if(!inserted_battery.battery_effect.activated)
						inserted_battery.battery_effect.ToggleActivate(0)
					harvesting = -1
					use_power = 2
					cur_artifact.anchored = 0
					icon_state = "incubator_on"
					var/message = "[src] states, \"Warning, battery charge dump commencing.\""
					src.visible_message(message)
			else
				var/message = "[src] states, \"Cannot dump energy. Battery is drained of charge already.\""
				src.visible_message(message)
		else
			var/message = "[src] states, \"Cannot dump energy. No battery inserted.\""
			src.visible_message(message)

	if(href_list["close"])
		usr << browse(null, "window=artharvester")
		usr.unset_machine(src)

	updateDialog()


code:
/obj/machinery/artifact_scanpad
	name = "Anomaly Scanner Pad"
	desc = "Place things here for scanning."
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "tele0"
	anchored = 1
	density = 0


code:
datum/reagent/coolant
	name = "Coolant"
	id = "coolant"
	description = "Industrial cooling substance."
	reagent_state = LIQUID
	color = "#C8A5DC" // rgb: 200, 165, 220

datum/chemical_reaction/coolant
	name = "Coolant"
	id = "coolant"
	result = "coolant"
	required_reagents = list("tungsten" = 1, "oxygen" = 1, "water" = 1)
	result_amount = 3

/obj/structure/reagent_dispensers/coolanttank
	name = "coolant tank"
	desc = "A tank of industrial coolant"
	icon = 'icons/obj/objects.dmi'
	icon_state = "coolanttank"
	amount_per_transfer_from_this = 10
	New()
		..()
		reagents.add_reagent("coolant",1000)

/obj/structure/reagent_dispensers/coolanttank/bullet_act(var/obj/item/projectile/Proj)
	if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
		if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) )
			explode()

/obj/structure/reagent_dispensers/coolanttank/blob_act()
	explode()

/obj/structure/reagent_dispensers/coolanttank/ex_act()
	explode()

/obj/structure/reagent_dispensers/coolanttank/proc/explode()
	var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread
	//S.attach(src)
	S.set_up(5, 0, src.loc)

	playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
	spawn(0)
		S.start()

	var/datum/gas_mixture/env = src.loc.return_air()
	if(env)
		if (reagents.total_volume > 750)
			env.temperature = 0
		else if (reagents.total_volume > 500)
			env.temperature -= 100
		else
			env.temperature -= 50

	sleep(10)
	if(src)
		del(src)