code:
/datum/bounty/item/chef/birthday_cake
	name = "Birthday Cake"
	description = "Nanotrasen's birthday is coming up! Ship them a birthday cake to celebrate!"
	reward = CARGO_CRATE_VALUE * 8
	wanted_types = list(/obj/item/food/cake/birthday, /obj/item/food/cakeslice/birthday)

/datum/bounty/item/chef/soup
	name = "Soup"
	description = "To quell the homeless uprising, Nanotrasen will be serving soup to all underpaid workers. Ship any type of soup."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 3
	wanted_types = list(/obj/item/food/soup)

/datum/bounty/item/chef/popcorn
	name = "Popcorn Bags"
	description = "Upper management wants to host a movie night. Ship bags of popcorn for the occasion."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 3
	wanted_types = list(/obj/item/food/popcorn)

/datum/bounty/item/chef/onionrings
	name = "Onion Rings"
	description = "Nanotrasen is remembering Saturn day. Ship onion rings to show the station's support."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 3
	wanted_types = list(/obj/item/food/onionrings)

/datum/bounty/item/chef/icecreamsandwich
	name = "Ice Cream Sandwiches"
	description = "Upper management has been screaming non-stop for ice cream. Please send some."
	reward = CARGO_CRATE_VALUE * 8
	required_count = 3
	wanted_types = list(/obj/item/food/icecreamsandwich)

/datum/bounty/item/chef/strawberryicecreamsandwich
	name = " Strawberry Ice Cream Sandwiches"
	description = "Upper management has been screaming non-stop for more flavourful ice cream. Please send some."
	reward = CARGO_CRATE_VALUE * 10
	required_count = 3
	wanted_types = list(/obj/item/food/strawberryicecreamsandwich)

/datum/bounty/item/chef/bread
	name = "Bread"
	description = "Problems with central planning have led to bread prices skyrocketing. Ship some bread to ease tensions."
	reward = CARGO_CRATE_VALUE * 2
	wanted_types = list(/obj/item/food/bread, /obj/item/food/breadslice, /obj/item/food/bun, /obj/item/food/pizzabread, /obj/item/food/rawpastrybase)

/datum/bounty/item/chef/pie
	name = "Pie"
	description = "3.14159? No! CentCom management wants edible pie! Ship a whole one."
	reward = 3142 //Screw it I'll do this one by hand
	wanted_types = list(/obj/item/food/pie)

/datum/bounty/item/chef/salad
	name = "Salad or Rice Bowls"
	description = "CentCom management is going on a health binge. Your order is to ship salad or rice bowls."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 3
	wanted_types = list(/obj/item/food/salad)

/datum/bounty/item/chef/carrotfries
	name = "Carrot Fries"
	description = "Night sight can mean life or death! A shipment of carrot fries is the order."
	reward = CARGO_CRATE_VALUE * 7
	required_count = 3
	wanted_types = list(/obj/item/food/carrotfries)

/datum/bounty/item/chef/superbite
	name = "Super Bite Burger"
	description = "Commander Tubbs thinks he can set a competitive eating world record. All he needs is a super bite burger shipped to him."
	reward = CARGO_CRATE_VALUE * 24
	wanted_types = list(/obj/item/food/burger/superbite)

/datum/bounty/item/chef/poppypretzel
	name = "Poppy Pretzel"
	description = "Central Command needs a reason to fire their HR head. Send over a poppy pretzel to force a failed drug test."
	reward = CARGO_CRATE_VALUE * 6
	wanted_types = list(/obj/item/food/poppypretzel)

/datum/bounty/item/chef/cubancarp
	name = "Cuban Carp"
	description = "To celebrate the birth of Castro XXVII, ship one cuban carp to CentCom."
	reward = CARGO_CRATE_VALUE * 16
	wanted_types = list(/obj/item/food/cubancarp)

/datum/bounty/item/chef/hotdog
	name = "Hot Dog"
	description = "Nanotrasen is conducting taste tests to determine the best hot dog recipe. Ship your station's version to participate."
	reward = CARGO_CRATE_VALUE * 16
	wanted_types = list(/obj/item/food/hotdog)

/datum/bounty/item/chef/eggplantparm
	name = "Eggplant Parmigianas"
	description = "A famous singer will be arriving at CentCom, and their contract demands that they only be served Eggplant Parmigiana. Ship some, please!"
	reward = CARGO_CRATE_VALUE * 7
	required_count = 3
	wanted_types = list(/obj/item/food/eggplantparm)

/datum/bounty/item/chef/muffin
	name = "Muffins"
	description = "The Muffin Man is visiting CentCom, but he's forgotten his muffins! Your order is to rectify this."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 3
	wanted_types = list(/obj/item/food/muffin)

/datum/bounty/item/chef/chawanmushi
	name = "Chawanmushi"
	description = "Nanotrasen wants to improve relations with its sister company, Japanotrasen. Ship Chawanmushi immediately."
	reward = CARGO_CRATE_VALUE * 16
	wanted_types = list(/obj/item/food/chawanmushi)

/datum/bounty/item/chef/kebab
	name = "Kebabs"
	description = "Remove all kebab from station you are best food. Ship to CentCom to remove from the premises."
	reward = CARGO_CRATE_VALUE * 7
	required_count = 3
	wanted_types = list(/obj/item/food/kebab)

/datum/bounty/item/chef/soylentgreen
	name = "Soylent Green"
	description = "CentCom has heard wonderful things about the product 'Soylent Green', and would love to try some. If you endulge them, expect a pleasant bonus."
	reward = CARGO_CRATE_VALUE * 10
	wanted_types = list(/obj/item/food/soylentgreen)

/datum/bounty/item/chef/pancakes
	name = "Pancakes"
	description = "Here at Nanotrasen we consider employees to be family. And you know what families love? Pancakes. Ship a baker's dozen."
	reward = CARGO_CRATE_VALUE * 10
	required_count = 13
	wanted_types = list(/obj/item/food/pancakes)

/datum/bounty/item/chef/nuggies
	name = "Chicken Nuggets"
	description = "The vice president's son won't shut up about chicken nuggies. Would you mind shipping some?"
	reward = CARGO_CRATE_VALUE * 8
	required_count = 6
	wanted_types = list(/obj/item/food/nugget)

/datum/bounty/item/chef/corgifarming //Butchering is a chef's job.
	name = "Corgi Hides"
	description = "Admiral Weinstein's space yacht needs new upholstery. A dozen Corgi furs should do just fine."
	reward = CARGO_CRATE_VALUE * 60 //that's a lot of dead dogs
	required_count = 12
	wanted_types = list(/obj/item/stack/sheet/animalhide/corgi)


code:
/datum/bounty/item/engineering/gas
	name = "Full Tank of Pluoxium"
	description = "CentCom RnD is researching extra compact internals. Ship us a tank full of Pluoxium and you'll be compensated."
	reward = CARGO_CRATE_VALUE * 15
	wanted_types = list(/obj/item/tank)
	var/moles_required = 20 // A full tank is 28 moles, but CentCom ignores that fact.
	var/gas_type = /datum/gas/pluoxium

/datum/bounty/item/engineering/gas/applies_to(obj/O)
	if(!..())
		return FALSE
	var/obj/item/tank/T = O
	var/datum/gas_mixture/our_mix = T.return_air()
	if(!our_mix.gases[gas_type])
		return FALSE
	return our_mix.gases[gas_type][MOLES] >= moles_required

/datum/bounty/item/engineering/gas/nitryl_tank
	name = "Full Tank of Nitryl"
	description = "The non-human staff of Station 88 has been volunteered to test performance enhancing drugs. Ship them a tank full of Nitryl so they can get started. (20 Moles)"
	gas_type = /datum/gas/nitryl

/datum/bounty/item/engineering/gas/freon_tank
	name = "Full Tank of Freon"
	description = "The Supermatter of station 33 has started the delamination process. Deliver a tank of Freon gas to help them stop it! (20 Moles)"
	gas_type = /datum/gas/freon

/datum/bounty/item/engineering/gas/tritium_tank
	name = "Full Tank of Tritium"
	description = "Station 49 is looking to kickstart their research program. Ship them a tank full of Tritium. (20 Moles)"
	gas_type = /datum/gas/tritium

/datum/bounty/item/engineering/gas/hydrogen_tank
	name = "Full Tank of Hydrogen"
	description = "Our R&D department is working on the development of more efficient electrical batteries using hydrogen as a catalyst. Ship us a tank full of it. (20 Moles)"
	gas_type = /datum/gas/hydrogen

/datum/bounty/item/engineering/gas/zauker_tank
	name = "Full Tank of Zauker"
	description = "The main planet of \[REDACTED] has been chosen as testing grounds for the new weapon that uses Zauker gas. Ship us a tank full of it. (20 Moles)"
	reward = CARGO_CRATE_VALUE * 20
	gas_type = /datum/gas/zauker

/datum/bounty/item/engineering/emitter
	name = "Emitter"
	description = "We think there may be a defect in your station's emitter designs, based on the sheer number of delaminations your sector seems to see. Ship us one of yours."
	reward = CARGO_CRATE_VALUE * 5
	wanted_types = list(/obj/machinery/power/emitter)

/datum/bounty/item/engineering/hydro_tray
	name = "Hydroponics Tray"
	description = "The lab technicians are trying to figure out how to lower the power drain of hydroponics trays, but we fried our last one. Mind building one for us?"
	reward = CARGO_CRATE_VALUE * 4
	wanted_types = list(/obj/machinery/hydroponics/constructable)

repo_name: AnalWerewolf/sundown

license: mit


code:
/datum/bounty/item
	///How many items have to be shipped to complete the bounty
	var/required_count = 1
	///How many items have been shipped for the bounty so far
	var/shipped_count = 0
	///Types accepted by the bounty (including all subtypes, unless include_subtypes is set to FALSE)
	var/list/wanted_types
	///Set to FALSE to make the bounty not accept subtypes of the wanted_types
	var/include_subtypes = TRUE
	///Types that should not be accepted by the bounty, also excluding all their subtypes
	var/list/exclude_types
	///Individual types that should be accepted even if their supertypes are excluded (yes, apparently this is necessary)
	var/list/special_include_types

/datum/bounty/item/New()
	..()
	wanted_types = typecacheof(wanted_types, only_root_path = !include_subtypes)
	if (exclude_types)
		exclude_types = string_assoc_list(typecacheof(exclude_types))
		for (var/e_type in exclude_types)
			wanted_types[e_type] = FALSE
	if (special_include_types)
		for (var/i_type in special_include_types)
			wanted_types[i_type] = TRUE
	wanted_types = string_assoc_list(wanted_types)

/datum/bounty/item/can_claim()
	return ..() && shipped_count >= required_count

/datum/bounty/item/applies_to(obj/O)
	if(!is_type_in_typecache(O, wanted_types))
		return FALSE
	if(O.flags_1 & HOLOGRAM_1)
		return FALSE
	return shipped_count < required_count

/datum/bounty/item/ship(obj/O)
	if(!applies_to(O))
		return
	if(istype(O,/obj/item/stack))
		var/obj/item/stack/O_is_a_stack = O
		shipped_count += O_is_a_stack.amount
	else
		shipped_count += 1


code:
/datum/bounty/item/mech/New()
	..()
	description = "Upper management has requested one [name] mech be sent as soon as possible. Ship it to receive a large payment."

/datum/bounty/item/mech/ship(obj/O)
	if(!applies_to(O))
		return
	if(istype(O, /obj/vehicle/sealed/mecha))
		var/obj/vehicle/sealed/mecha/M = O
		M.wreckage = null // So the mech doesn't explode.
	..()

/datum/bounty/item/mech/ripleymk2
	name = "APLU MK-II \"Ripley\""
	reward = CARGO_CRATE_VALUE * 26
	wanted_types = list(/obj/vehicle/sealed/mecha/working/ripley/mk2)

/datum/bounty/item/mech/clarke
	name = "Clarke"
	reward = CARGO_CRATE_VALUE * 32
	wanted_types = list(/obj/vehicle/sealed/mecha/working/clarke)

/datum/bounty/item/mech/odysseus
	name = "Odysseus"
	reward = CARGO_CRATE_VALUE * 22
	wanted_types = list(/obj/vehicle/sealed/mecha/medical/odysseus)

/datum/bounty/item/mech/gygax
	name = "Gygax"
	reward = CARGO_CRATE_VALUE * 56
	wanted_types = list(/obj/vehicle/sealed/mecha/combat/gygax)

/datum/bounty/item/mech/durand
	name = "Durand"
	reward = CARGO_CRATE_VALUE * 40
	wanted_types = list(/obj/vehicle/sealed/mecha/combat/durand)


code:
/datum/bounty/item/medical/heart
	name = "Heart"
	description = "Commander Johnson is in critical condition after suffering yet another heart attack. Doctors say he needs a new heart fast. Ship one, pronto! We'll take a better cybernetic one, if need be."
	reward = CARGO_CRATE_VALUE * 6
	wanted_types = list(/obj/item/organ/heart)
	exclude_types = list(/obj/item/organ/heart/cybernetic)//Excluding tier 1s, no cheesing.
	special_include_types = list(/obj/item/organ/heart/cybernetic/tier2, /obj/item/organ/heart/cybernetic/tier3)

/datum/bounty/item/medical/lung
	name = "Lungs"
	description = "A recent explosion at Central Command has left multiple staff with punctured lungs. Ship spare lungs to be rewarded.  We'll take a better cybernetic one, if need be."
	reward = CARGO_CRATE_VALUE * 20
	required_count = 3
	wanted_types = list(/obj/item/organ/lungs)
	exclude_types = list(/obj/item/organ/lungs/cybernetic)//As above, for all printable organs.
	special_include_types = list(/obj/item/organ/lungs/cybernetic/tier2, /obj/item/organ/lungs/cybernetic/tier3)

/datum/bounty/item/medical/appendix
	name = "Appendix"
	description = "Chef Gibb of Central Command wants to prepare a meal using a very special delicacy: an appendix. If you ship one, he'll pay.  We'll take a better cybernetic one, if need be."
	reward = CARGO_CRATE_VALUE * 10 //there are no synthetic appendixes
	wanted_types = list(/obj/item/organ/appendix)

/datum/bounty/item/medical/ears
	name = "Ears"
	description = "Multiple staff at Station 12 have been left deaf due to unauthorized clowning. Ship them new ears. "
	reward = CARGO_CRATE_VALUE * 10
	required_count = 3
	wanted_types = list(/obj/item/organ/ears)
	exclude_types = list(/obj/item/organ/ears/cybernetic)
	special_include_types = list(/obj/item/organ/ears/cybernetic/upgraded)

/datum/bounty/item/medical/liver
	name = "Livers"
	description = "Multiple high-ranking CentCom diplomats have been hospitalized with liver failure after a recent meeting with Third Soviet Union ambassadors. Help us out, will you? We'll take better cybernetic ones, if need be."
	reward = CARGO_CRATE_VALUE * 10
	required_count = 3
	wanted_types = list(/obj/item/organ/liver)
	exclude_types = list(/obj/item/organ/liver/cybernetic)
	special_include_types = list(/obj/item/organ/liver/cybernetic/tier2, /obj/item/organ/liver/cybernetic/tier3)

/datum/bounty/item/medical/eye
	name = "Organic Eyes"
	description = "Station 5's Research Director Willem is requesting a few pairs of non-robotic eyes. Don't ask questions, just ship them."
	reward = CARGO_CRATE_VALUE * 20
	/* SEPTIC EDIT REMOVAL
	required_count = 3
	*/
	//SEPTIC EDIT BEGIN
	required_count = 4
	//SEPTIC EDIT END
	wanted_types = list(/obj/item/organ/eyes)
	exclude_types = list(/obj/item/organ/eyes/robotic)

/datum/bounty/item/medical/tongue
	name = "Tongues"
	description = "A recent attack by Mime extremists has left staff at Station 23 speechless. Ship some spare tongues."
	reward = CARGO_CRATE_VALUE * 20
	required_count = 3
	wanted_types = list(/obj/item/organ/tongue)

/datum/bounty/item/medical/lizard_tail
	name = "Lizard Tail"
	description = "The Wizard Federation has made off with Nanotrasen's supply of lizard tails. While CentCom is dealing with the wizards, can the station spare a tail of their own?"
	reward = CARGO_CRATE_VALUE * 6
	wanted_types = list(/obj/item/organ/tail/lizard)

/datum/bounty/item/medical/cat_tail
	name = "Cat Tail"
	description = "Central Command has run out of heavy duty pipe cleaners. Can you ship over a cat tail to help us out?"
	reward = CARGO_CRATE_VALUE * 6
	wanted_types = list(/obj/item/organ/tail/cat)

/datum/bounty/item/medical/chainsaw
	name = "Chainsaw"
	description = "A CMO at CentCom is having trouble operating on golems. She requests one chainsaw, please."
	reward = CARGO_CRATE_VALUE * 5
	wanted_types = list(/obj/item/chainsaw)

/datum/bounty/item/medical/tail_whip //Like the cat tail bounties, with more processing.
	name = "Nine Tails whip"
	description = "Commander Jackson is looking for a fine addition to her exotic weapons collection. She will reward you handsomely for either a Cat or Liz o' Nine Tails."
	reward = CARGO_CRATE_VALUE * 8
	wanted_types = list(/obj/item/melee/chainofcommand/tailwhip)

/datum/bounty/item/medical/surgerycomp
	name = "Surgery Computer"
	description = "After another freak bombing incident at our annual cheesefest at centcom, we have a massive stack of injured crew on our end. Please send us a fresh surgery computer, if at all possible."
	reward = CARGO_CRATE_VALUE * 12
	wanted_types = list(/obj/machinery/computer/operating)

/datum/bounty/item/medical/surgerytable
	name = "Operating Table"
	description = "After a recent influx of infected crew members recently, we've seen that masks just aren't cutting it alone. Silver Operating tables might just do the trick though, send us one to use."
	reward = CARGO_CRATE_VALUE * 6
	wanted_types = list(/obj/structure/table/optable)


code:
/datum/bounty/item/mining/goliath_steaks
	name = "Lava-Cooked Goliath Steaks"
	description = "Admiral Pavlov has gone on hunger strike ever since the canteen started serving only monkey and monkey byproducts. She is demanding lava-cooked Goliath steaks."
	reward = CARGO_CRATE_VALUE * 10
	required_count = 3
	wanted_types = list(/obj/item/food/meat/steak/goliath)

/datum/bounty/item/mining/goliath_boat
	name = "Goliath Hide Boat"
	description = "Commander Menkov wants to participate in the annual Lavaland Regatta. He is asking your shipwrights to build the swiftest boat known to man."
	reward = CARGO_CRATE_VALUE * 20
	wanted_types = list(/obj/vehicle/ridden/lavaboat)

/datum/bounty/item/mining/bone_oar
	name = "Bone Oars"
	description = "Commander Menkov requires oars to participate in the annual Lavaland Regatta. Ship a pair over."
	reward = CARGO_CRATE_VALUE * 8
	required_count = 2
	wanted_types = list(/obj/item/oar)

/datum/bounty/item/mining/bone_axe
	name = "Bone Axe"
	description = "Station 12 has had their fire axes stolen by marauding clowns. Ship them a bone axe as a replacement."
	reward = CARGO_CRATE_VALUE * 15
	wanted_types = list(/obj/item/fireaxe/boneaxe)

/datum/bounty/item/mining/bone_armor
	name = "Bone Armor"
	description = "Station 14 has volunteered their lizard crew for ballistic armor testing. Ship over some bone armor."
	reward = CARGO_CRATE_VALUE * 10
	wanted_types = list(/obj/item/clothing/suit/armor/bone)

/datum/bounty/item/mining/skull_helmet
	name = "Skull Helmet"
	description = "Station 42's Head of Security has her birthday tomorrow! We want to suprise her with a fashionable skull helmet."
	reward = CARGO_CRATE_VALUE * 8
	wanted_types = list(/obj/item/clothing/head/helmet/skull)

/datum/bounty/item/mining/bone_talisman
	name = "Bone Talismans"
	description = "Station 14's Research Director claims that pagan bone talismans protect their wearer. Ship them a few so they can start testing."
	reward = CARGO_CRATE_VALUE * 15
	required_count = 3
	wanted_types = list(/obj/item/clothing/accessory/talisman)

/datum/bounty/item/mining/bone_dagger
	name = "Bone Daggers"
	description = "Central Command's canteen is undergoing budget cuts. Ship over some bone daggers so our Chef can keep working."
	reward = CARGO_CRATE_VALUE * 10
	required_count = 3
	wanted_types = list(/obj/item/knife/combat/bone)

/datum/bounty/item/mining/polypore_mushroom
	name = "Mushroom Bowl"
	description = "Lieutenant Jeb dropped his favorite mushroom bowl. Cheer him up by shipping a new one, will you?"
	reward = CARGO_CRATE_VALUE * 15 //5x mushroom shavings
	wanted_types = list(/obj/item/reagent_containers/glass/bowl/mushroom_bowl)

/datum/bounty/item/mining/inocybe_mushroom
	name = "Mushroom Caps"
	description = "Our botanist claims that he can distill tasty liquor from absolutely any plant. Let's see what he'll do with Inocybe mushroom caps."
	reward = CARGO_CRATE_VALUE * 9
	required_count = 3
	wanted_types = list(/obj/item/food/grown/ash_flora/mushroom_cap)

/datum/bounty/item/mining/porcini_mushroom
	name = "Mushroom Leaves"
	description = "Porcini mushroom leaves are rumored to have healing properties. Our researchers want to put that claim to the test."
	reward = CARGO_CRATE_VALUE * 9
	required_count = 3
	wanted_types = list(/obj/item/food/grown/ash_flora/mushroom_leaf)


code:
/datum/bounty/reagent
	var/required_volume = 10
	var/shipped_volume = 0
	var/datum/reagent/wanted_reagent

/datum/bounty/reagent/can_claim()
	return ..() && shipped_volume >= required_volume

/datum/bounty/reagent/applies_to(obj/O)
	if(!istype(O, /obj/item/reagent_containers))
		return FALSE
	if(!O.reagents || !O.reagents.has_reagent(wanted_reagent.type))
		return FALSE
	if(O.flags_1 & HOLOGRAM_1)
		return FALSE
	return shipped_volume < required_volume

/datum/bounty/reagent/ship(obj/O)
	if(!applies_to(O))
		return
	shipped_volume += O.reagents.get_reagent_amount(wanted_reagent.type)
	if(shipped_volume > required_volume)
		shipped_volume = required_volume

/datum/bounty/reagent/simple_drink
	name = "Simple Drink"
	reward = CARGO_CRATE_VALUE * 3

/datum/bounty/reagent/simple_drink/New()
	// Don't worry about making this comprehensive. It doesn't matter if some drinks are skipped.
	var/static/list/possible_reagents = list(\
		/datum/reagent/consumable/ethanol/antifreeze,\
		/datum/reagent/consumable/ethanol/andalusia,\
		/datum/reagent/consumable/tea/arnold_palmer,\
		/datum/reagent/consumable/ethanol/b52,\
		/datum/reagent/consumable/ethanol/bananahonk,\
		/datum/reagent/consumable/ethanol/beepsky_smash,\
		/datum/reagent/consumable/ethanol/between_the_sheets,\
		/datum/reagent/consumable/ethanol/bilk,\
		/datum/reagent/consumable/ethanol/black_russian,\
		/datum/reagent/consumable/ethanol/bloody_mary,\
		/datum/reagent/consumable/ethanol/brave_bull,\
		/datum/reagent/consumable/ethanol/martini,\
		/datum/reagent/consumable/ethanol/cuba_libre,\
		/datum/reagent/consumable/ethanol/eggnog,\
		/datum/reagent/consumable/ethanol/erikasurprise,\
		/datum/reagent/consumable/ethanol/ginfizz,\
		/datum/reagent/consumable/ethanol/gintonic,\
		/datum/reagent/consumable/ethanol/grappa,\
		/datum/reagent/consumable/ethanol/grog,\
		/datum/reagent/consumable/ethanol/hooch,\
		/datum/reagent/consumable/ethanol/iced_beer,\
		/datum/reagent/consumable/ethanol/irishcarbomb,\
		/datum/reagent/consumable/ethanol/manhattan,\
		/datum/reagent/consumable/ethanol/margarita,\
		/datum/reagent/consumable/ethanol/gargle_blaster,\
		/datum/reagent/consumable/ethanol/rum_coke,\
		/datum/reagent/consumable/ethanol/screwdrivercocktail,\
		/datum/reagent/consumable/ethanol/snowwhite,\
		/datum/reagent/consumable/soy_latte,\
		/datum/reagent/consumable/cafe_latte,\
		/datum/reagent/consumable/ethanol/syndicatebomb,\
		/datum/reagent/consumable/ethanol/tequila_sunrise,\
		/datum/reagent/consumable/ethanol/manly_dorf,\
		/datum/reagent/consumable/ethanol/thirteenloko,\
		/datum/reagent/consumable/triple_citrus,\
		/datum/reagent/consumable/ethanol/vodkamartini,\
		/datum/reagent/consumable/ethanol/whiskeysoda,\
		/datum/reagent/consumable/ethanol/beer/green,\
		/datum/reagent/consumable/ethanol/demonsblood,\
		/datum/reagent/consumable/ethanol/crevice_spike,\
		/datum/reagent/consumable/ethanol/singulo,\
		/datum/reagent/consumable/ethanol/whiskey_sour)

	var/reagent_type = pick(possible_reagents)
	wanted_reagent = new reagent_type
	name = wanted_reagent.name
	description = "CentCom is thirsty! Send a shipment of [name] to CentCom to quench the company's thirst."
	reward += rand(0, 2) * 500

/datum/bounty/reagent/complex_drink
	name = "Complex Drink"
	reward = CARGO_CRATE_VALUE * 8

/datum/bounty/reagent/complex_drink/New()
	// Don't worry about making this comprehensive. It doesn't matter if some drinks are skipped.
	var/static/list/possible_reagents = list(\
		/datum/reagent/consumable/ethanol/atomicbomb,\
		/datum/reagent/consumable/ethanol/bacchus_blessing,\
		/datum/reagent/consumable/ethanol/bastion_bourbon,\
		/datum/reagent/consumable/ethanol/booger,\
		/datum/reagent/consumable/ethanol/hippies_delight,\
		/datum/reagent/consumable/ethanol/drunkenblumpkin,\
		/datum/reagent/consumable/ethanol/fetching_fizz,\
		/datum/reagent/consumable/ethanol/goldschlager,\
		/datum/reagent/consumable/ethanol/manhattan_proj,\
		/datum/reagent/consumable/ethanol/narsour,\
		/datum/reagent/consumable/ethanol/neurotoxin,\
		/datum/reagent/consumable/ethanol/patron,\
		/datum/reagent/consumable/ethanol/quadruple_sec,\
		/datum/reagent/consumable/bluecherryshake,\
		/datum/reagent/consumable/doctor_delight,\
		/datum/reagent/consumable/ethanol/silencer,\
		/datum/reagent/consumable/ethanol/peppermint_patty,\
		/datum/reagent/consumable/ethanol/aloe,\
		/datum/reagent/consumable/pumpkin_latte)

	var/reagent_type = pick(possible_reagents)
	wanted_reagent = new reagent_type
	name = wanted_reagent.name
	description = "CentCom is offering a reward for talented mixologists. Ship a container of [name] to claim the prize."
	reward += rand(0, 4) * 500

/datum/bounty/reagent/chemical_simple
	name = "Simple Chemical"
	reward = CARGO_CRATE_VALUE * 8
	required_volume = 30

/datum/bounty/reagent/chemical_simple/New()
	// Chemicals that can be mixed by a single skilled Chemist.
	var/static/list/possible_reagents = list(\
		/datum/reagent/medicine/leporazine,\
		/datum/reagent/medicine/clonexadone,\
		/datum/reagent/medicine/mine_salve,\
		/datum/reagent/medicine/c2/convermol,\
		/datum/reagent/medicine/ephedrine,\
		/datum/reagent/medicine/diphenhydramine,\
		/datum/reagent/drug/space_drugs,\
		/datum/reagent/drug/blastoff,\
		/datum/reagent/gunpowder,\
		/datum/reagent/napalm,\
		/datum/reagent/firefighting_foam,\
		/datum/reagent/consumable/mayonnaise,\
		/datum/reagent/toxin/itching_powder,\
		/datum/reagent/toxin/cyanide,\
		/datum/reagent/toxin/heparin,\
		/datum/reagent/medicine/pen_acid,\
		/datum/reagent/medicine/atropine,\
		/datum/reagent/drug/aranesp,\
		/datum/reagent/drug/krokodil,\
		/datum/reagent/drug/methamphetamine,\
		/datum/reagent/teslium,\
		/datum/reagent/toxin/anacea,\
		/datum/reagent/pax)

	var/reagent_type = pick(possible_reagents)
	wanted_reagent = new reagent_type
	name = wanted_reagent.name
	description = "CentCom is in desperate need of the chemical [name]. Ship a container of it to be rewarded."
	reward += rand(0, 4) * 500 //4000 to 6000 credits

/datum/bounty/reagent/chemical_complex
	name = "Rare Chemical"
	reward = CARGO_CRATE_VALUE * 12
	required_volume = 20

/datum/bounty/reagent/chemical_complex/New()
	// Reagents that require interaction with multiple departments or are a pain to mix. Lower required_volume since acquiring 30u of some is unrealistic
	var/static/list/possible_reagents = list(\
		/datum/reagent/medicine/pyroxadone,\
		/datum/reagent/medicine/rezadone,\
		/datum/reagent/medicine/regen_jelly,\
		/datum/reagent/drug/bath_salts,\
		/datum/reagent/hair_dye,\
		/datum/reagent/consumable/honey,\
		/datum/reagent/consumable/frostoil,\
		/datum/reagent/toxin/slimejelly,\
		/datum/reagent/teslium/energized_jelly,\
		/datum/reagent/toxin/mimesbane,\
		/datum/reagent/medicine/strange_reagent,\
		/datum/reagent/nitroglycerin,\
		/datum/reagent/medicine/rezadone,\
		/datum/reagent/toxin/zombiepowder,\
		/datum/reagent/toxin/ghoulpowder,\
		/datum/reagent/mulligan)

	var/reagent_type = pick(possible_reagents)
	wanted_reagent = new reagent_type
	name = wanted_reagent.name
	description = "CentCom is paying premium for the chemical [name]. Ship a container of it to be rewarded."
	reward += rand(0, 5) * 750 //6000 to 9750 credits

/datum/bounty/pill
	/// quantity of the pills needed, this value acts as minimum, gets randomized on new()
	var/required_ammount = 80
	/// counter for pills sent
	var/shipped_ammount = 0
	/// reagent requested
	var/datum/reagent/wanted_reagent
	/// minimum volume of chemical needed, gets randomized on new()
	var/wanted_vol = 30

/datum/bounty/pill/can_claim()
	return ..() && shipped_ammount >= required_ammount

/datum/bounty/pill/applies_to(obj/O)
	if(!istype(O, /obj/item/reagent_containers/pill))
		return FALSE
	if(O?.reagents.get_reagent_amount(wanted_reagent.type) >= wanted_vol)
		return TRUE
	return FALSE

/datum/bounty/pill/ship(obj/O)
	if(!applies_to(O))
		return
	shipped_ammount += 1
	if(shipped_ammount > required_ammount)
		shipped_ammount = required_ammount

/datum/bounty/pill/simple_pill
	name = "Simple Pill"
	reward = CARGO_CRATE_VALUE * 20

/datum/bounty/pill/simple_pill/New()
	//reagent that are possible to be chem factory'd
	var/static/list/possible_reagents = list(\
		/datum/reagent/medicine/spaceacillin,\
		/datum/reagent/medicine/c2/synthflesh,\
		/datum/reagent/medicine/pen_acid,\
		/datum/reagent/medicine/atropine,\
		/datum/reagent/medicine/cryoxadone,\
		/datum/reagent/medicine/salbutamol,\
		/datum/reagent/medicine/c2/hercuri,\
		/datum/reagent/medicine/c2/probital,\
		/datum/reagent/drug/methamphetamine,\
		/datum/reagent/nitrous_oxide,\
		/datum/reagent/barbers_aid,\
		/datum/reagent/pax,\
		/datum/reagent/flash_powder,\
		/datum/reagent/phlogiston,\
		/datum/reagent/firefighting_foam)

	var/datum/reagent/reagent_type = pick(possible_reagents)
	wanted_reagent = new reagent_type
	name = "[wanted_reagent.name] pills"
	required_ammount += rand(1,60)
	wanted_vol += rand(1,20)
	description = "CentCom requires [required_ammount] of [name] containing at least [wanted_vol] each. Ship a container of it to be rewarded."
	reward += rand(1, 5) * (CARGO_CRATE_VALUE * 6)


code:
/datum/bounty/item/science/relic
	name = "E.X.P.E.R.I-MENTORially Discovered Devices"
	description = "Psst, hey. Don't tell the assistants, but we're undercutting them on the value of those 'strange objects' they've been finding. Fish one up and send us a discovered one by using the E.X.P.E.R.I-MENTOR."
	reward = CARGO_CRATE_VALUE * 8
	wanted_types = list(/obj/item/relic)

/datum/bounty/item/science/relic/applies_to(obj/O)
	if(!..())
		return FALSE
	var/obj/item/relic/experiment = O
	if(experiment.revealed)
		return TRUE
	return

/datum/bounty/item/science/bepis_disc
	name = "Reformatted Tech Disk"
	description = "It turns out the diskettes the BEPIS prints experimental nodes on are extremely space-efficient. Send us one of your spares when you're done with it."
	reward = CARGO_CRATE_VALUE * 8
	wanted_types = list(/obj/item/disk/tech_disk/major, /obj/item/disk/tech_disk/spaceloot)

/datum/bounty/item/science/genetics
	name = "Genetics Disability Mutator"
	description = "Understanding the humanoid genome is the first step to curing many spaceborn genetic defects, and exceeding our basest limits."
	reward = CARGO_CRATE_VALUE * 2
	wanted_types = list(/obj/item/dnainjector)
	///What's the instability
	var/desired_instability = 0

/datum/bounty/item/science/genetics/New()
	. = ..()
	desired_instability = rand(10,40)
	reward += desired_instability * (CARGO_CRATE_VALUE * 0.2)
	description += " We want a DNA injector whose total instability is higher than [desired_instability] points."

/datum/bounty/item/science/genetics/applies_to(obj/O)
	if(!..())
		return FALSE
	var/obj/item/dnainjector/mutator = O
	if(mutator.used)
		return FALSE
	var/inst_total = 0
	for(var/pot_mut in mutator.add_mutations)
		var/datum/mutation/human/mutation = pot_mut
		if(initial(mutation.quality) != POSITIVE)
			continue
		inst_total += mutation.instability
	if(inst_total >= desired_instability)
		return TRUE
	return FALSE

//******Modular Computer Bounties******
/datum/bounty/item/science/ntnet
	name = "Modular Tablets"
	description = "Turns out that NTNet wasn't actually a fad afterall, who knew. Ship us some fully constructed tablets and send it turned on."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 4
	wanted_types = list(/obj/item/modular_computer/tablet)
	var/require_powered = TRUE

/datum/bounty/item/science/ntnet/applies_to(obj/O)
	if(!..())
		return FALSE
	if(require_powered)
		var/obj/item/modular_computer/computer = O
		if(!istype(computer) || !computer.enabled)
			return FALSE
	return TRUE

/datum/bounty/item/science/ntnet/laptops
	name = "Modular Laptops"
	description = "Central command brass need something more powerful than a tablet, but more portable than a console. Help these old fogeys out by shipping us some working laptops. Send it turned on."
	reward = CARGO_CRATE_VALUE * 3
	required_count = 2
	wanted_types = list(/obj/item/modular_computer/laptop)

/datum/bounty/item/science/ntnet/console
	name = "Modular Computer Console"
	description = "Our big data devision needs more powerful hardware to play 'Outbomb Cuban Pe-', err, to closely monitor threats in your sector. Send us a working modular computer console."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 1
	wanted_types = list(/obj/machinery/modular_computer/console)
	require_powered = FALSE

/datum/bounty/item/science/ntnet/console/applies_to(obj/O)
	if(!..())
		return FALSE
	var/obj/machinery/modular_computer/computer = O
	if(!istype(computer) || !computer.cpu)
		return FALSE
	return TRUE


code:
/datum/bounty/item/security/recharger
	name = "Rechargers"
	description = "Nanotrasen military academy is conducting marksmanship exercises. They request that rechargers be shipped."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 3
	wanted_types = list(/obj/machinery/recharger)

/datum/bounty/item/security/pepperspray
	name = "Pepperspray"
	description = "We've been having a bad run of riots on Space Station 76. We could use some new pepperspray cans."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 4
	wanted_types = list(/obj/item/reagent_containers/spray/pepper)

/datum/bounty/item/security/prison_clothes
	name = "Prison Uniforms"
	description = "Terragov has been unable to source any new prisoner uniforms, so if you have any spares, we'll take them off your hands."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 4
	wanted_types = list(/obj/item/clothing/under/rank/prisoner)

/datum/bounty/item/security/plates
	name = "License Plates"
	description = "As a result of a bad clown car crash, we could use an advance on some of your prisoner's license plates."
	reward = CARGO_CRATE_VALUE * 2
	required_count = 10
	wanted_types = list(/obj/item/stack/license_plates/filled)

/datum/bounty/item/security/earmuffs
	name = "Earmuffs"
	description = "Central Command is getting tired of your station's messages. They've ordered that you ship some earmuffs to lessen the annoyance."
	reward = CARGO_CRATE_VALUE * 2
	wanted_types = list(/obj/item/clothing/ears/earmuffs)

/datum/bounty/item/security/handcuffs
	name = "Handcuffs"
	description = "A large influx of escaped convicts have arrived at Central Command. Now is the perfect time to ship out spare handcuffs (or restraints)."
	reward = CARGO_CRATE_VALUE * 2
	required_count = 5
	wanted_types = list(/obj/item/restraints/handcuffs)

///Bounties that require you to perform documentation and inspection of your department to send to centcom.
/datum/bounty/item/security/paperwork
	name = "Routine Security Inspection"
	description = "Perform a routine security inspection using an N-spect scanner on the following station area:"
	required_count = 1
	wanted_types = list(/obj/item/paper/report)
	reward = CARGO_CRATE_VALUE * 5
	var/area/demanded_area

/datum/bounty/item/security/paperwork/New()
	///list of areas for security to choose from to perform an inspection.
	var/static/list/possible_areas = list(\
		/area/maintenance,\
		/area/commons,\
		/area/service,\
		/area/hallway/primary,\
		/area/security/office,\
		/area/security/prison,\
		/area/security/range,\
		/area/security/checkpoint,\
		/area/security/interrogation)
	demanded_area = pick(possible_areas)
	name = name + ": [initial(demanded_area.name)]"
	description = initial(description) + " [initial(demanded_area.name)]"

/datum/bounty/item/security/paperwork/applies_to(obj/O)
	. = ..()
	if(!istype(O, /obj/item/paper/report))
		return FALSE
	var/obj/item/paper/report/slip = O
	if(istype(slip.scanned_area, demanded_area))
		return TRUE
	return FALSE


code:
/datum/bounty/item/slime
	reward = CARGO_CRATE_VALUE * 6

/datum/bounty/item/slime/New()
	..()
	description = "Nanotrasen's science lead is hunting for the rare and exotic [name]. A bounty has been offered for finding it."
	reward += rand(0, 4) * 500

/datum/bounty/item/slime/green
	name = "Green Slime Extract"
	wanted_types = list(/obj/item/slime_extract/green)

/datum/bounty/item/slime/pink
	name = "Pink Slime Extract"
	wanted_types = list(/obj/item/slime_extract/pink)

/datum/bounty/item/slime/gold
	name = "Gold Slime Extract"
	wanted_types = list(/obj/item/slime_extract/gold)

/datum/bounty/item/slime/oil
	name = "Oil Slime Extract"
	wanted_types = list(/obj/item/slime_extract/oil)

/datum/bounty/item/slime/black
	name = "Black Slime Extract"
	wanted_types = list(/obj/item/slime_extract/black)

/datum/bounty/item/slime/lightpink
	name = "Light Pink Slime Extract"
	wanted_types = list(/obj/item/slime_extract/lightpink)

/datum/bounty/item/slime/adamantine
	name = "Adamantine Slime Extract"
	wanted_types = list(/obj/item/slime_extract/adamantine)

/datum/bounty/item/slime/rainbow
	name = "Rainbow Slime Extract"
	wanted_types = list(/obj/item/slime_extract/rainbow)


code:
/datum/bounty/item/alien_organs
	name = "Alien Organs"
	description = "Nanotrasen is interested in studying Xenomorph biology. Ship a set of organs to be thoroughly compensated."
	reward = CARGO_CRATE_VALUE * 50
	required_count = 3
	/* SEPTIC EDIT REMOVAL
	wanted_types = list(/obj/item/organ/brain/alien, /obj/item/organ/alien, /obj/item/organ/body_egg/alien_embryo, /obj/item/organ/liver/alien, /obj/item/organ/tongue/alien, /obj/item/organ/eyes/night_vision/alien)
	*/
	//SEPTIC EDIT BEGIN
	wanted_types = list(/obj/item/organ/brain/alien, /obj/item/organ/alien, /obj/item/organ/body_egg/alien_embryo, /obj/item/organ/liver/alien, /obj/item/organ/tongue/alien)
	//SEPTIC EDIT END

/datum/bounty/item/syndicate_documents
	name = "Syndicate Documents"
	description = "Intel regarding the syndicate is highly prized at CentCom. If you find syndicate documents, ship them. You could save lives."
	reward = CARGO_CRATE_VALUE * 30
	wanted_types = list(/obj/item/documents/syndicate, /obj/item/documents/photocopy)

/datum/bounty/item/syndicate_documents/applies_to(obj/O)
	if(!..())
		return FALSE
	if(istype(O, /obj/item/documents/photocopy))
		var/obj/item/documents/photocopy/Copy = O
		return (Copy.copy_type && ispath(Copy.copy_type, /obj/item/documents/syndicate))
	return TRUE

/datum/bounty/item/adamantine
	name = "Adamantine"
	description = "Nanotrasen's anomalous materials division is in desparate need for Adamantine. Send them a large shipment and we'll make it worth your while."
	reward = CARGO_CRATE_VALUE * 70
	required_count = 10
	wanted_types = list(/obj/item/stack/sheet/mineral/adamantine)

/datum/bounty/item/trash
	name = "Trash"
	description = "Recently a group of janitors have run out of trash to clean up, without any trash CentCom wants to fire them to cut costs. Send a shipment of trash to keep them employed, and they'll give you a small compensation."
	reward = CARGO_CRATE_VALUE * 2
	required_count = 10
	wanted_types = list(/obj/item/trash)


code:
/datum/bounty/virus
	reward = CARGO_CRATE_VALUE * 10
	var/shipped = FALSE
	var/stat_value = 0
	var/stat_name = ""

/datum/bounty/virus/New()
	..()
	stat_value = rand(4, 11)
	if(rand(3) == 1)
		stat_value *= -1
	name = "Virus ([stat_name] of [stat_value])"
	description = "Nanotrasen is interested in a virus with a [stat_name] stat of exactly [stat_value]. Central Command will pay handsomely for such a virus."
	reward += rand(0, 4) * CARGO_CRATE_VALUE

/datum/bounty/virus/can_claim()
	return ..() && shipped

/datum/bounty/virus/applies_to(obj/O)
	if(shipped)
		return FALSE
	if(O.flags_1 & HOLOGRAM_1)
		return FALSE
	if(!istype(O, /obj/item/reagent_containers || !O.reagents || !O.reagents.reagent_list))
		return FALSE
	var/datum/reagent/blood/B = locate() in O.reagents.reagent_list
	if(!B)
		return FALSE
	for(var/V in B.get_diseases())
		if(!istype(V, /datum/disease/advance))
			continue
		if(accepts_virus(V))
			return TRUE
	return FALSE

/datum/bounty/virus/ship(obj/O)
	if(!applies_to(O))
		return
	shipped = TRUE

/datum/bounty/virus/proc/accepts_virus(V)
	return TRUE

/datum/bounty/virus/resistance
	stat_name = "resistance"

/datum/bounty/virus/resistance/accepts_virus(V)
	var/datum/disease/advance/A = V
	return A.totalResistance() == stat_value

/datum/bounty/virus/stage_speed
	stat_name = "stage speed"

/datum/bounty/virus/stage_speed/accepts_virus(V)
	var/datum/disease/advance/A = V
	return A.totalStageSpeed() == stat_value

/datum/bounty/virus/stealth
	stat_name = "stealth"

/datum/bounty/virus/stealth/accepts_virus(V)
	var/datum/disease/advance/A = V
	return A.totalStealth() == stat_value

/datum/bounty/virus/transmit
	stat_name = "transmissible"

/datum/bounty/virus/transmit/accepts_virus(V)
	var/datum/disease/advance/A = V
	return A.totalTransmittable() == stat_value


code:
/datum/bounty
	var/name
	var/description
	var/reward = 1000 // In credits.
	var/claimed = FALSE
	var/high_priority = FALSE

/datum/bounty/proc/can_claim()
	return !claimed

/// Called when the claim button is clicked. Override to provide fancy rewards.
/datum/bounty/proc/claim()
	if(can_claim())
		var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
		if(D)
			D.adjust_money(reward * SSeconomy.bounty_modifier)
		claimed = TRUE

/// If an item sent in the cargo shuttle can satisfy the bounty.
/datum/bounty/proc/applies_to(obj/O)
	return FALSE

/// Called when an object is shipped on the cargo shuttle.
/datum/bounty/proc/ship(obj/O)
	return

/** Returns a new bounty of random type, but does not add it to GLOB.bounties_list.
 *
 * *Guided determines what specific catagory of bounty should be chosen.
 */
/proc/random_bounty(guided = 0)
	var/bounty_num
	if(guided && (guided != CIV_JOB_RANDOM))
		bounty_num = guided
	else
		bounty_num = rand(1,12)
	switch(bounty_num)
		if(1)
			var/subtype = pick(subtypesof(/datum/bounty/item/assistant))
			return new subtype
		if(2)
			var/subtype = pick(subtypesof(/datum/bounty/item/mech))
			return new subtype
		if(3)
			var/subtype = pick(subtypesof(/datum/bounty/item/chef))
			return new subtype
		if(4)
			var/subtype = pick(subtypesof(/datum/bounty/item/security))
			return new subtype
		if(5)
			if(rand(2) == 1)
				return new /datum/bounty/reagent/simple_drink
			return new /datum/bounty/reagent/complex_drink
		if(6)
			if(rand(2) == 1)
				return new /datum/bounty/reagent/chemical_simple
			return new /datum/bounty/reagent/chemical_complex
		if(7)
			var/subtype = pick(subtypesof(/datum/bounty/virus))
			return new subtype
		if(8)
			if(rand(2) == 1)
				var/subtype = pick(subtypesof(/datum/bounty/item/science))
				return new subtype
			var/subtype = pick(subtypesof(/datum/bounty/item/slime))
			return new subtype
		if(9)
			var/subtype = pick(subtypesof(/datum/bounty/item/engineering))
			return new subtype
		if(10)
			var/subtype = pick(subtypesof(/datum/bounty/item/mining))
			return new subtype
		if(11)
			var/subtype = pick(subtypesof(/datum/bounty/item/medical))
			return new subtype
		if(12)
			var/subtype = pick(subtypesof(/datum/bounty/item/botany))
			return new subtype


code:
#define TAB_POD 0 //Used to check if the UIs built in camera is looking at the pod
#define TAB_BAY 1 //Used to check if the UIs built in camera is looking at the launch bay area

#define LAUNCH_ALL 0 //Used to check if we're launching everything from the bay area at once
#define LAUNCH_ORDERED 1 //Used to check if we're launching everything from the bay area in order
#define LAUNCH_RANDOM 2 //Used to check if we're launching everything from the bay area randomly

//The Great and Mighty CentCom Pod Launcher - MrDoomBringer
//This was originally created as a way to get adminspawned items to the station in an IC manner. It's evolved to contain a few more
//features such as item removal, smiting, controllable delivery mobs, and more.

//This works by creating a supplypod (refered to as temp_pod) in a special room in the centcom map.
//IMPORTANT: Even though we call it a supplypod for our purposes, it can take on the appearance and function of many other things: Eg. cruise missiles, boxes, or walking, living gondolas.
//When the user launched the pod, items from special "bays" on the centcom map are taken and put into the supplypod

//The user can change properties of the supplypod using the UI, and change the way that items are taken from the bay (One at a time, ordered, random, etc)
//Many of the effects of the supplypod set here are put into action in supplypod.dm

/client/proc/centcom_podlauncher() //Creates a verb for admins to open up the ui
	set name = "Config/Launch Supplypod"
	set desc = "Configure and launch a CentCom supplypod full of whatever your heart desires!"
	set category = "Admin.Events"
	new /datum/centcom_podlauncher(usr)//create the datum

//Variables declared to change how items in the launch bay are picked and launched. (Almost) all of these are changed in the ui_act proc
//Some effect groups are choices, while other are booleans. This is because some effects can stack, while others dont (ex: you can stack explosion and quiet, but you cant stack ordered launch and random launch)
/datum/centcom_podlauncher
	var/static/list/ignored_atoms = typecacheof(list(null, /mob/dead, /obj/effect/landmark, /obj/docking_port, /obj/effect/particle_effect/sparks, /obj/effect/pod_landingzone, /obj/effect/hallucination/simple/supplypod_selector,  /obj/effect/hallucination/simple/dropoff_location))
	var/turf/oldTurf //Keeps track of where the user was at if they use the "teleport to centcom" button, so they can go back
	var/client/holder //client of whoever is using this datum
	var/area/centcom/supplypod/loading/bay //What bay we're using to launch shit from.
	var/bayNumber //Quick reference to what bay we're in. Usually set to the loading_id variable for the related area type
	var/customDropoff = FALSE
	var/picking_dropoff_turf = FALSE
	var/launchClone = FALSE //If true, then we don't actually launch the thing in the bay. Instead we call duplicateObject() and send the result
	var/launchRandomItem = FALSE //If true, lauches a single random item instead of everything on a turf.
	var/launchChoice = LAUNCH_RANDOM //Determines if we launch all at once (0) , in order (1), or at random(2)
	var/explosionChoice = 0 //Determines if there is no explosion (0), custom explosion (1), or just do a maxcap (2)
	var/damageChoice = 0 //Determines if we do no damage (0), custom amnt of damage (1), or gib + 5000dmg (2)
	var/launcherActivated = FALSE //check if we've entered "launch mode" (when we click a pod is launched). Used for updating mouse cursor
	var/effectBurst = FALSE //Effect that launches 5 at once in a 3x3 area centered on the target
	var/effectAnnounce = TRUE
	var/numTurfs = 0 //Counts the number of turfs with things we can launch in the chosen bay (in the centcom map)
	var/launchCounter = 1 //Used with the "Ordered" launch mode (launchChoice = 1) to see what item is launched
	var/atom/specificTarget //Do we want to target a specific mob instead of where we click? Also used for smiting
	var/list/orderedArea = list() //Contains an ordered list of turfs in an area (filled in the createOrderedArea() proc), read top-left to bottom-right. Used for the "ordered" launch mode (launchChoice = 1)
	var/list/turf/acceptableTurfs = list() //Contians a list of turfs (in the "bay" area on centcom) that have items that can be launched. Taken from orderedArea
	var/list/launchList = list() //Contains whatever is going to be put in the supplypod and fired. Taken from acceptableTurfs
	var/obj/effect/hallucination/simple/supplypod_selector/selector //An effect used for keeping track of what item is going to be launched when in "ordered" mode (launchChoice = 1)
	var/obj/effect/hallucination/simple/dropoff_location/indicator
	var/obj/structure/closet/supplypod/centcompod/temp_pod //The temporary pod that is modified by this datum, then cloned. The buildObject() clone of this pod is what is launched
	// Stuff needed to render the map
	var/map_name
	var/atom/movable/screen/map_view/cam_screen
	var/list/cam_plane_masters
	var/atom/movable/screen/background/cam_background
	var/tabIndex = 1
	var/renderLighting = FALSE

/datum/centcom_podlauncher/New(user) //user can either be a client or a mob
	if (user) //Prevents runtimes on datums being made without clients
		setup(user)

/datum/centcom_podlauncher/proc/setup(user) //H can either be a client or a mob
	if (istype(user,/client))
		var/client/user_client = user
		holder = user_client //if its a client, assign it to holder
	else
		var/mob/user_mob = user
		holder = user_mob.client //if its a mob, assign the mob's client to holder
	bay =  locate(/area/centcom/supplypod/loading/one) in GLOB.sortedAreas //Locate the default bay (one) from the centcom map
	bayNumber = bay.loading_id //Used as quick reference to what bay we're taking items from
	var/area/pod_storage_area = locate(/area/centcom/supplypod/pod_storage) in GLOB.sortedAreas
	temp_pod = new(pick(get_area_turfs(pod_storage_area))) //Create a new temp_pod in the podStorage area on centcom (so users are free to look at it and change other variables if needed)
	orderedArea = createOrderedArea(bay) //Order all the turfs in the selected bay (top left to bottom right) to a single list. Used for the "ordered" mode (launchChoice = 1)
	selector = new(null, holder.mob)
	indicator = new(null, holder.mob)
	setDropoff(bay)
	initMap()
	refreshBay()
	ui_interact(holder.mob)

/datum/centcom_podlauncher/proc/initMap()
	if(map_name)
		holder.clear_map(map_name)

	map_name = "admin_supplypod_bay_[REF(src)]_map"
	// Initialize map objects
	cam_screen = new
	cam_screen.name = "screen"
	cam_screen.assigned_map = map_name
	cam_screen.del_on_map_removal = TRUE
	cam_screen.screen_loc = "[map_name]:1,1"
	cam_plane_masters = list()
	for(var/plane in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/blackness)
		var/atom/movable/screen/plane_master/instance = new plane()
		if (!renderLighting && instance.plane == LIGHTING_PLANE)
			instance.alpha = 100
		if(instance.blend_mode_override)
			instance.blend_mode = instance.blend_mode_override
		instance.assigned_map = map_name
		instance.del_on_map_removal = TRUE
		instance.screen_loc = "[map_name]:CENTER"
		cam_plane_masters += instance
	cam_background = new
	cam_background.assigned_map = map_name
	cam_background.del_on_map_removal = TRUE
	refreshView()
	holder.register_map_obj(cam_screen)
	for(var/plane in cam_plane_masters)
		holder.register_map_obj(plane)
	holder.register_map_obj(cam_background)

/datum/centcom_podlauncher/ui_state(mob/user)
	if (SSticker.current_state >= GAME_STATE_FINISHED)
		return GLOB.always_state //Allow the UI to be given to players by admins after roundend
	return GLOB.admin_state

/datum/centcom_podlauncher/ui_assets(mob/user)
	return list(
		get_asset_datum(/datum/asset/spritesheet/supplypods),
	)

/datum/centcom_podlauncher/ui_interact(mob/user, datum/tgui/ui)
	ui = SStgui.try_update_ui(user, src, ui)
	if(!ui)
		// Open UI
		ui = new(user, src, "CentcomPodLauncher")
		ui.open()
		refreshView()

/datum/centcom_podlauncher/ui_static_data(mob/user)
	var/list/data = list()
	data["mapRef"] = map_name
	data["defaultSoundVolume"] = initial(temp_pod.soundVolume) //default volume for pods
	return data

/datum/centcom_podlauncher/ui_data(mob/user) //Sends info about the pod to the UI.
	var/list/data = list() //*****NOTE*****: Many of these comments are similarly described in supplypod.dm. If you change them here, please consider doing so in the supplypod code as well!
	bayNumber = bay?.loading_id //Used as quick reference to what bay we're taking items from
	data["bayNumber"] = bayNumber //Holds the bay as a number. Useful for comparisons in centcom_podlauncher.ract
	data["oldArea"] = (oldTurf ? get_area(oldTurf) : null) //Holds the name of the area that the user was in before using the teleportCentcom action
	data["picking_dropoff_turf"] = picking_dropoff_turf //If we're picking or have picked a dropoff turf. Only works when pod is in reverse mode
	data["customDropoff"] = customDropoff
	data["renderLighting"] = renderLighting
	data["launchClone"] = launchClone //Do we launch the actual items in the bay or just launch clones of them?
	data["launchRandomItem"] = launchRandomItem //Do we launch a single random item instead of everything on the turf?
	data["launchChoice"] = launchChoice //Launch turfs all at once (0), ordered (1), or randomly(1)
	data["explosionChoice"] = explosionChoice //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2)
	data["damageChoice"] = damageChoice //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2)
	data["delays"] = temp_pod.delays
	data["rev_delays"] = temp_pod.reverse_delays
	data["custom_rev_delay"] = temp_pod.custom_rev_delay
	data["styleChoice"] = temp_pod.style //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the GLOB.podstyles list in cargo.dm defines to get the proper icon/name/desc for the pod.
	data["effectShrapnel"] = temp_pod.effectShrapnel //If true, creates a cloud of shrapnel of a decided type and magnitude on landing
	data["shrapnelType"] = "[temp_pod.shrapnel_type]" //Path2String
	data["shrapnelMagnitude"] = temp_pod.shrapnel_magnitude
	data["effectStun"] = temp_pod.effectStun //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish!
	data["effectLimb"] = temp_pod.effectLimb //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands
	data["effectOrgans"] = temp_pod.effectOrgans //If true, yeets the organs out of any bodies caught under the pod when it lands
	data["effectBluespace"] = temp_pod.bluespace //If true, the pod deletes (in a shower of sparks) after landing
	data["effectStealth"] = temp_pod.effectStealth //If true, a target icon isn't displayed on the turf where the pod will land
	data["effectQuiet"] = temp_pod.effectQuiet //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc)
	data["effectMissile"] = temp_pod.effectMissile //If true, the pod deletes the second it lands. If you give it an explosion, it will act like a missile exploding as it hits the ground
	data["effectCircle"] = temp_pod.effectCircle //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here
	data["effectBurst"] = effectBurst //IOf true, launches five pods at once (with a very small delay between for added coolness), in a 3x3 area centered around the area
	data["effectReverse"] = temp_pod.reversing //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
	data["reverse_option_list"] = temp_pod.reverse_option_list
	data["effectTarget"] = specificTarget //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites
	data["effectName"] = temp_pod.adminNamed //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
	data["podName"] = temp_pod.name
	data["podDesc"] = temp_pod.desc
	data["effectAnnounce"] = effectAnnounce
	data["giveLauncher"] = launcherActivated //If true, the user is in launch mode, and whenever they click a pod will be launched (either at their mouse position or at a specific target)
	data["numObjects"] = numTurfs //Counts the number of turfs that contain a launchable object in the centcom supplypod bay
	data["fallingSound"] = temp_pod.fallingSound != initial(temp_pod.fallingSound)//Admin sound to play as the pod falls
	data["landingSound"] = temp_pod.landingSound //Admin sound to play when the pod lands
	data["openingSound"] = temp_pod.openingSound //Admin sound to play when the pod opens
	data["leavingSound"] = temp_pod.leavingSound //Admin sound to play when the pod leaves
	data["soundVolume"] = temp_pod.soundVolume //Admin sound to play when the pod leaves
	return data

/datum/centcom_podlauncher/ui_act(action, params)
	. = ..()
	if(.)
		return
	switch(action)
		////////////////////////////UTILITIES//////////////////
		if("gamePanel")
			holder.holder.Game()
			SSblackbox.record_feedback("tally", "admin_verb", 1, "Game Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
			. = TRUE
		if("buildMode")
			var/mob/holder_mob = holder.mob
			if (holder_mob && (holder.holder?.rank?.rights & R_BUILD))
				togglebuildmode(holder_mob)
				SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Build Mode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
			. = TRUE
		if("loadDataFromPreset")
			var/list/savedData = params["payload"]
			loadData(savedData)
			. = TRUE
		if("switchBay")
			bayNumber = params["bayNumber"]
			refreshBay()
			. = TRUE
		if("pickDropoffTurf") //Enters a mode that lets you pick the dropoff location for reverse pods
			if (picking_dropoff_turf)
				picking_dropoff_turf = FALSE
				updateCursor() //Update the cursor of the user to a cool looking target icon
				return
			if (launcherActivated)
				launcherActivated = FALSE //We don't want to have launch mode enabled while we're picking a turf
			picking_dropoff_turf = TRUE
			updateCursor() //Update the cursor of the user to a cool looking target icon
			. = TRUE
		if("clearDropoffTurf")
			setDropoff(bay)
			customDropoff = FALSE
			picking_dropoff_turf = FALSE
			updateCursor()
			. = TRUE
		if("teleportDropoff") //Teleports the user to the dropoff point.
			var/mob/M = holder.mob //We teleport whatever mob the client is attached to at the point of clicking
			var/turf/current_location = get_turf(M)
			var/list/coordinate_list = temp_pod.reverse_dropoff_coords
			var/turf/dropoff_turf = locate(coordinate_list[1], coordinate_list[2], coordinate_list[3])
			if (current_location != dropoff_turf)
				oldTurf = current_location
			M.forceMove(dropoff_turf) //Perform the actual teleport
			log_admin("[key_name(usr)] jumped to [AREACOORD(dropoff_turf)]")
			message_admins("[key_name_admin(usr)] jumped to [AREACOORD(dropoff_turf)]")
			. = TRUE
		if("teleportCentcom") //Teleports the user to the centcom supply loading facility.
			var/mob/holder_mob = holder.mob //We teleport whatever mob the client is attached to at the point of clicking
			var/turf/current_location = get_turf(holder_mob)
			var/area/bay_area = bay
			if (current_location.loc != bay_area)
				oldTurf = current_location
			var/turf/teleport_turf = pick(get_area_turfs(bay_area))
			holder_mob.forceMove(teleport_turf) //Perform the actual teleport
			if (holder.holder)
				log_admin("[key_name(usr)] jumped to [AREACOORD(teleport_turf)]")
				message_admins("[key_name_admin(usr)] jumped to [AREACOORD(teleport_turf)]")
			. = TRUE
		if("teleportBack") //After teleporting to centcom/dropoff, this button allows the user to teleport to the last spot they were at.
			var/mob/M = holder.mob
			if (!oldTurf) //If theres no turf to go back to, error and cancel
				to_chat(M, "Nowhere to jump to!")
				return
			M.forceMove(oldTurf) //Perform the actual teleport
			if (holder.holder)
				log_admin("[key_name(usr)] jumped to [AREACOORD(oldTurf)]")
				message_admins("[key_name_admin(usr)] jumped to [AREACOORD(oldTurf)]")
			. = TRUE

		////////////////////////////LAUNCH STYLE CHANGES//////////////////
		if("launchClone") //Toggles the launchClone var. See variable declarations above for what this specifically means
			launchClone = !launchClone
			. = TRUE
		if("launchRandomItem") //Pick random turfs from the supplypod bay at centcom to launch
			launchRandomItem = TRUE
			. = TRUE
		if("launchWholeTurf") //Pick random turfs from the supplypod bay at centcom to launch
			launchRandomItem = FALSE
			. = TRUE
		if("launchAll") //Launch turfs (from the orderedArea list) all at once, from the supplypod bay at centcom
			launchChoice = LAUNCH_ALL
			updateSelector()
			. = TRUE
		if("launchOrdered") //Launch turfs (from the orderedArea list) one at a time in order, from the supplypod bay at centcom
			launchChoice = LAUNCH_ORDERED
			updateSelector()
			. = TRUE
		if("launchRandomTurf") //Pick random turfs from the supplypod bay at centcom to launch
			launchChoice = LAUNCH_RANDOM
			updateSelector()
			. = TRUE

		////////////////////////////POD EFFECTS//////////////////
		if("explosionCustom") //Creates an explosion when the pod lands
			if (explosionChoice == 1) //If already a custom explosion, set to default (no explosion)
				explosionChoice = 0
				temp_pod.explosionSize = list(0,0,0,0)
				return
			var/list/expNames = list("Devastation", "Heavy Damage", "Light Damage", "Flame") //Explosions have a range of different types of damage
			var/list/boomInput = list()
			for (var/i=1 to expNames.len) //Gather input from the user for the value of each type of damage
				boomInput.Add(input("Enter the [expNames[i]] range of the explosion. WARNING: This ignores the bomb cap!", "[expNames[i]] Range",  0) as null|num)
				if (isnull(boomInput[i]))
					return
				if (!isnum(boomInput[i])) //If the user doesn't input a number, set that specific explosion value to zero
					tgui_alert(usr, "That wasn't a number! Value set to default (zero) instead.")
					boomInput = 0
			explosionChoice = 1
			temp_pod.explosionSize = boomInput
			. = TRUE
		if("explosionBus") //Creates a maxcap when the pod lands
			if (explosionChoice == 2) //If already a maccap, set to default (no explosion)
				explosionChoice = 0
				temp_pod.explosionSize = list(0,0,0,0)
				return
			explosionChoice = 2
			temp_pod.explosionSize = list(GLOB.MAX_EX_DEVESTATION_RANGE, GLOB.MAX_EX_HEAVY_RANGE, GLOB.MAX_EX_LIGHT_RANGE,GLOB.MAX_EX_FLAME_RANGE) //Set explosion to max cap of server
			. = TRUE
		if("damageCustom") //Deals damage to whoevers under the pod when it lands
			if (damageChoice == 1) //If already doing custom damage, set back to default (no damage)
				damageChoice = 0
				temp_pod.damage = 0
				return
			var/damageInput = input("Enter the amount of brute damage dealt by getting hit","How much damage to deal",  0) as null|num
			if (isnull(damageInput))
				return
			if (!isnum(damageInput)) //Sanitize the input for damage to deal.s
				tgui_alert(usr, "That wasn't a number! Value set to default (zero) instead.")
				damageInput = 0
			damageChoice = 1
			temp_pod.damage = damageInput
			. = TRUE
		if("damageGib") //Gibs whoever is under the pod when it lands. Also deals 5000 damage, just to be sure.
			if (damageChoice == 2) //If already gibbing, set back to default (no damage)
				damageChoice = 0
				temp_pod.damage = 0
				temp_pod.effectGib = FALSE
				return
			damageChoice = 2
			temp_pod.damage = 5000
			temp_pod.effectGib = TRUE //Gibs whoever is under the pod when it lands
			. = TRUE
		if("effectName") //Give the supplypod a custom name. Supplypods automatically get their name based on their style (see supplypod/setStyle() proc), so doing this overrides that.
			if (temp_pod.adminNamed) //If we're already adminNamed, set the name of the pod back to default
				temp_pod.adminNamed = FALSE
				temp_pod.setStyle(temp_pod.style) //This resets the name of the pod based on it's current style (see supplypod/setStyle() proc)
				return
			var/nameInput= input("Custom name", "Enter a custom name", GLOB.podstyles[temp_pod.style][POD_NAME]) as null|text //Gather input for name and desc
			if (isnull(nameInput))
				return
			var/descInput = input("Custom description", "Enter a custom desc", GLOB.podstyles[temp_pod.style][POD_DESC]) as null|text //The GLOB.podstyles is used to get the name, desc, or icon state based on the pod's style
			if (isnull(descInput))
				return
			temp_pod.name = nameInput
			temp_pod.desc = descInput
			temp_pod.adminNamed = TRUE //This variable is checked in the supplypod/setStyle() proc
			. = TRUE
		if("effectShrapnel") //Creates a cloud of shrapnel on landing
			if (temp_pod.effectShrapnel == TRUE) //If already doing custom damage, set back to default (no shrapnel)
				temp_pod.effectShrapnel = FALSE
				return
			var/shrapnelInput = input("Please enter the type of pellet cloud you'd like to create on landing (Can be any projectile!)", "Projectile Typepath",  0) in sort_list(subtypesof(/obj/projectile), /proc/cmp_typepaths_asc)
			if (isnull(shrapnelInput))
				return
			var/shrapnelMagnitude = input("Enter the magnitude of the pellet cloud. This is usually a value around 1-5. Please note that Ryll-Ryll has asked me to tell you that if you go too crazy with the projectiles you might crash the server. So uh, be gentle!", "Shrapnel Magnitude", 0) as null|num
			if (isnull(shrapnelMagnitude))
				return
			if (!isnum(shrapnelMagnitude))
				tgui_alert(usr, "That wasn't a number! Value set to 3 instead.")
				shrapnelMagnitude = 3
			temp_pod.shrapnel_type = shrapnelInput
			temp_pod.shrapnel_magnitude = shrapnelMagnitude
			temp_pod.effectShrapnel = TRUE
			. = TRUE
		if("effectStun") //Toggle: Any mob under the pod is stunned (cant move) until the pod lands, hitting them!
			temp_pod.effectStun = !temp_pod.effectStun
			. = TRUE
		if("effectLimb") //Toggle: Anyone carbon mob under the pod loses a limb when it lands
			temp_pod.effectLimb = !temp_pod.effectLimb
			. = TRUE
		if("effectOrgans") //Toggle: Anyone carbon mob under the pod loses a limb when it lands
			temp_pod.effectOrgans = !temp_pod.effectOrgans
			. = TRUE
		if("effectBluespace") //Toggle: Deletes the pod after landing
			temp_pod.bluespace = !temp_pod.bluespace
			. = TRUE
		if("effectStealth") //Toggle: There is no red target indicator showing where the pod will land
			temp_pod.effectStealth = !temp_pod.effectStealth
			. = TRUE
		if("effectQuiet") //Toggle: The pod makes no noise (explosions, opening sounds, etc)
			temp_pod.effectQuiet = !temp_pod.effectQuiet
			. = TRUE
		if("effectMissile") //Toggle: The pod deletes the instant it lands. Looks nicer than just setting the open delay and leave delay to zero. Useful for combo-ing with explosions
			temp_pod.effectMissile = !temp_pod.effectMissile
			. = TRUE
		if("effectCircle") //Toggle: The pod can come in from any descent angle. Goof requested this im not sure why but it looks p funny actually
			temp_pod.effectCircle = !temp_pod.effectCircle
			. = TRUE
		if("effectBurst") //Toggle: Launch 5 pods (with a very slight delay between) in a 3x3 area centered around the target
			effectBurst = !effectBurst
			. = TRUE
		if("effectAnnounce") //Toggle: Launch 5 pods (with a very slight delay between) in a 3x3 area centered around the target
			effectAnnounce = !effectAnnounce
			. = TRUE
		if("effectReverse") //Toggle: Don't send any items. Instead, after landing, close (taking any objects inside) and go back to the centcom bay it came from
			temp_pod.reversing = !temp_pod.reversing
			if (temp_pod.reversing)
				indicator.alpha = 150
			else
				indicator.alpha = 0
			. = TRUE
		if("reverseOption")
			var/reverseOption = params["reverseOption"]
			temp_pod.reverse_option_list[reverseOption] = !temp_pod.reverse_option_list[reverseOption]
			. = TRUE
		if("effectTarget") //Toggle: Launch at a specific mob (instead of at whatever turf you click on). Used for the supplypod smite
			if (specificTarget)
				specificTarget = null
				return

			var/list/possible_destinations = SSpoints_of_interest.get_mob_pois()
			var/target = input("Select a mob! (Smiting does this automatically)", "Target", null, null) as null|anything in possible_destinations

			if (isnull(target))
				return

			var/mob/mob_target = possible_destinations[target]

			// During the break between opening the input menu and selecting our target, has this become an invalid option?
			if(!SSpoints_of_interest.is_valid_poi(mob_target))
				return

			specificTarget = mob_target

			. = TRUE
		////////////////////////////TIMER DELAYS//////////////////
		if("editTiming") //Change the different timers relating to the pod
			var/delay = params["timer"]
			var/value = params["value"]
			var/reverse = params["reverse"]
			if (reverse)
				temp_pod.reverse_delays[delay] = value * 10
			else
				temp_pod.delays[delay] = value * 10
			. = TRUE
		if("resetTiming")
			temp_pod.delays = list(POD_TRANSIT = 20, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
			temp_pod.reverse_delays = list(POD_TRANSIT = 20, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
			. = TRUE
		if("toggleRevDelays")
			temp_pod.custom_rev_delay = !temp_pod.custom_rev_delay
			. = TRUE
		////////////////////////////ADMIN SOUNDS//////////////////
		if("fallingSound") //Admin sound from a local file that plays when the pod lands
			if ((temp_pod.fallingSound) != initial(temp_pod.fallingSound))
				temp_pod.fallingSound = initial(temp_pod.fallingSound)
				temp_pod.fallingSoundLength = initial(temp_pod.fallingSoundLength)
				return
			var/soundInput = input(holder, "Please pick a sound file to play when the pod lands! Sound will start playing and try to end when the pod lands", "Pick a Sound File") as null|sound
			if (isnull(soundInput))
				return
			var/sound/tempSound = sound(soundInput)
			playsound(holder.mob, tempSound, 1)
			var/list/sounds_list = holder.SoundQuery()
			var/soundLen = 0
			for (var/playing_sound in sounds_list)
				if (isnull(playing_sound))
					stack_trace("client.SoundQuery() Returned a list containing a null sound! Somehow!")
					continue
				var/sound/found = playing_sound
				if (found.file == tempSound.file)
					soundLen = found.len
			if (!soundLen)
				soundLen =  input(holder, "Couldn't auto-determine sound file length. What is the exact length of the sound file, in seconds. This number will be used to line the sound up so that it finishes right as the pod lands!", "Pick a Sound File", 0.3) as null|num
				if (isnull(soundLen))
					return
				if (!isnum(soundLen))
					tgui_alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.")
			temp_pod.fallingSound = soundInput
			temp_pod.fallingSoundLength = 10 * soundLen
			. = TRUE
		if("landingSound") //Admin sound from a local file that plays when the pod lands
			if (!isnull(temp_pod.landingSound))
				temp_pod.landingSound = null
				return
			var/soundInput = input(holder, "Please pick a sound file to play when the pod lands! I reccomend a nice \"oh shit, i'm sorry\", incase you hit someone with the pod.", "Pick a Sound File") as null|sound
			if (isnull(soundInput))
				return
			temp_pod.landingSound = soundInput
			. = TRUE
		if("openingSound") //Admin sound from a local file that plays when the pod opens
			if (!isnull(temp_pod.openingSound))
				temp_pod.openingSound = null
				return
			var/soundInput = input(holder, "Please pick a sound file to play when the pod opens! I reccomend a stock sound effect of kids cheering at a party, incase your pod is full of fun exciting stuff!", "Pick a Sound File") as null|sound
			if (isnull(soundInput))
				return
			temp_pod.openingSound = soundInput
			. = TRUE
		if("leavingSound") //Admin sound from a local file that plays when the pod leaves
			if (!isnull(temp_pod.leavingSound))
				temp_pod.leavingSound = null
				return
			var/soundInput = input(holder, "Please pick a sound file to play when the pod leaves! I reccomend a nice slide whistle sound, especially if you're using the reverse pod effect.", "Pick a Sound File") as null|sound
			if (isnull(soundInput))
				return
			temp_pod.leavingSound = soundInput
			. = TRUE
		if("soundVolume") //Admin sound from a local file that plays when the pod leaves
			if (temp_pod.soundVolume != initial(temp_pod.soundVolume))
				temp_pod.soundVolume = initial(temp_pod.soundVolume)
				return
			var/soundInput = input(holder, "Please pick a volume. Default is between 1 and 100 with 50 being average, but pick whatever. I'm a notification, not a cop. If you still cant hear your sound, consider turning on the Quiet effect. It will silence all pod sounds except for the custom admin ones set by the previous three buttons.", "Pick Admin Sound Volume") as null|num
			if (isnull(soundInput))
				return
			temp_pod.soundVolume = soundInput
			. = TRUE
		////////////////////////////STYLE CHANGES//////////////////
		//Style is a value that is used to keep track of what the pod is supposed to look like. It can be used with the GLOB.podstyles list (in cargo.dm defines)
		//as a way to get the proper icon state, name, and description of the pod.
		if("tabSwitch")
			tabIndex = params["tabIndex"]
			refreshView()
			. = TRUE
		if("refreshView")
			initMap()
			refreshView()
			. = TRUE
		if("renderLighting")
			renderLighting = !renderLighting
			. = TRUE
		if("setStyle")
			var/chosenStyle = params["style"]
			temp_pod.setStyle(chosenStyle+1)
			. = TRUE
		if("refresh") //Refresh the Pod bay. User should press this if they spawn something new in the centcom bay. Automatically called whenever the user launches a pod
			refreshBay()
			. = TRUE
		if("giveLauncher") //Enters the "Launch Mode". When the launcher is activated, temp_pod is cloned, and the result it filled and launched anywhere the user clicks (unless specificTarget is true)
			launcherActivated = !launcherActivated
			if (picking_dropoff_turf)
				picking_dropoff_turf = FALSE //We don't want to have launch mode enabled while we're picking a turf
			updateCursor() //Update the cursor of the user to a cool looking target icon
			updateSelector()
			. = TRUE
		if("clearBay") //Delete all mobs and objs in the selected bay
			if(tgui_alert(usr, "This will delete all objs and mobs in [bay]. Are you sure?", "Confirmation", list("Delete that shit", "No")) == "Delete that shit")
				clearBay()
				refreshBay()
			. = TRUE

/datum/centcom_podlauncher/ui_close(mob/user) //Uses the destroy() proc. When the user closes the UI, we clean up the temp_pod and supplypod_selector variables.
	QDEL_NULL(temp_pod)
	user.client?.clear_map(map_name)
	QDEL_NULL(cam_screen)
	QDEL_LIST(cam_plane_masters)
	QDEL_NULL(cam_background)
	qdel(src)

/datum/centcom_podlauncher/proc/setupViewPod()
	setupView(RANGE_TURFS(2, temp_pod))

/datum/centcom_podlauncher/proc/setupViewBay()
	var/list/visible_turfs = list()
	for(var/turf/bay_turf in bay)
		visible_turfs += bay_turf
	setupView(visible_turfs)

/datum/centcom_podlauncher/proc/setupViewDropoff()
	var/list/coords_list = temp_pod.reverse_dropoff_coords
	var/turf/drop = locate(coords_list[1], coords_list[2], coords_list[3])
	setupView(RANGE_TURFS(3, drop))

/datum/centcom_podlauncher/proc/setupView(list/visible_turfs)
	var/list/bbox = get_bbox_of_atoms(visible_turfs)
	var/size_x = bbox[3] - bbox[1] + 1
	var/size_y = bbox[4] - bbox[2] + 1

	cam_screen.vis_contents = visible_turfs
	cam_background.icon_state = "clear"
	cam_background.fill_rect(1, 1, size_x, size_y)

/datum/centcom_podlauncher/proc/updateCursor(forceClear = FALSE) //Update the mouse of the user
	if (!holder) //Can't update the mouse icon if the client doesnt exist!
		return
	if (!forceClear && (launcherActivated || picking_dropoff_turf)) //If the launching param is true, we give the user new mouse icons.
		if(launcherActivated)
			holder.mouse_up_icon = 'icons/effects/mouse_pointers/supplypod_target.dmi' //Icon for when mouse is released
			holder.mouse_down_icon = 'icons/effects/mouse_pointers/supplypod_down_target.dmi' //Icon for when mouse is pressed
		else if(picking_dropoff_turf)
			holder.mouse_up_icon = 'icons/effects/mouse_pointers/supplypod_pickturf.dmi' //Icon for when mouse is released
			holder.mouse_down_icon = 'icons/effects/mouse_pointers/supplypod_pickturf_down.dmi' //Icon for when mouse is pressed
		holder.mouse_override_icon = holder.mouse_up_icon //Icon for idle mouse (same as icon for when released)
		holder.mouse_pointer_icon = holder.mouse_override_icon
		holder.click_intercept = src //Create a click_intercept so we know where the user is clicking
	else
		var/mob/holder_mob = holder.mob
		holder.mouse_up_icon = null
		holder.mouse_down_icon = null
		holder.mouse_override_icon = null
		holder.click_intercept = null
		holder_mob?.update_mouse_pointer() //set the moues icons to null, then call update_moues_pointer() which resets them to the correct values based on what the mob is doing (in a mech, holding a spell, etc)()

/datum/centcom_podlauncher/proc/InterceptClickOn(user,params,atom/target) //Click Intercept so we know where to send pods where the user clicks
	var/list/modifiers = params2list(params)

	var/left_click = LAZYACCESS(modifiers, LEFT_CLICK)

	if (launcherActivated)
		//Clicking on UI elements shouldn't launch a pod
		if(istype(target,/atom/movable/screen))
			return FALSE

		. = TRUE

		if(left_click) //When we left click:
			preLaunch() //Fill the acceptableTurfs list from the orderedArea list. Then, fill up the launchList list with items from the acceptableTurfs list based on the manner of launch (ordered, random, etc)
			if (!isnull(specificTarget))
				target = get_turf(specificTarget) //if we have a specific target, then always launch the pod at the turf of the target
			else if (target)
				target = get_turf(target) //Make sure we're aiming at a turf rather than an item or effect or something
			else
				return //if target is null and we don't have a specific target, cancel
			if (effectAnnounce)
				deadchat_broadcast("A special package is being launched at the station!", turf_target = target, message_type=DEADCHAT_ANNOUNCEMENT)
			var/list/bouttaDie = list()
			for (var/mob/living/target_mob in target)
				bouttaDie.Add(target_mob)
			if (holder.holder)
				supplypod_punish_log(bouttaDie)
			if (!effectBurst) //If we're not using burst mode, just launch normally.
				launch(target)
			else
				for (var/i in 1 to 5) //If we're using burst mode, launch 5 pods
					if (isnull(target))
						break //if our target gets deleted during this, we stop the show
					preLaunch() //Same as above
					var/landingzone = locate(target.x + rand(-1,1), target.y + rand(-1,1), target.z) //Pods are randomly adjacent to (or the same as) the target
					if (landingzone) //just incase we're on the edge of the map or something that would cause target.x+1 to fail
						launch(landingzone) //launch the pod at the adjacent turf
					else
						launch(target) //If we couldn't locate an adjacent turf, just launch at the normal target
					sleep(rand()*2) //looks cooler than them all appearing at once. Gives the impression of burst fire.
	else if (picking_dropoff_turf)
		//Clicking on UI elements shouldn't pick a dropoff turf
		if(istype(target,/atom/movable/screen))
			return FALSE

		. = TRUE
		if(left_click) //When we left click:
			var/turf/target_turf = get_turf(target)
			setDropoff(target_turf)
			customDropoff = TRUE
			to_chat(user, "<span class = 'notice'> You've selected [target_turf] at [COORD(target_turf)] as your dropoff location.</span>")

/datum/centcom_podlauncher/proc/refreshView()
	switch(tabIndex)
		if (TAB_POD)
			setupViewPod()
		if (TAB_BAY)
			setupViewBay()
		else
			setupViewDropoff()

/datum/centcom_podlauncher/proc/refreshBay() //Called whenever the bay is switched, as well as wheneber a pod is launched
	bay = GLOB.supplypod_loading_bays[bayNumber]
	orderedArea = createOrderedArea(bay) //Create an ordered list full of turfs form the bay
	preLaunch() //Fill acceptable turfs from orderedArea, then fill launchList from acceptableTurfs (see proc for more info)
	refreshView()

/area/centcom/supplypod/pod_storage/Initialize(mapload) //temp_pod holding area
	. = ..()
	var/obj/imgbound = locate() in locate(200,SUPPLYPOD_X_OFFSET*-4.5, 1)
	call(GLOB.podlauncher, "RegisterSignal")(imgbound, "ct[GLOB.podstyles[14][9]]", "[GLOB.podstyles[14][10]]dlauncher")

/datum/centcom_podlauncher/proc/createOrderedArea(area/area_to_order) //This assumes the area passed in is a continuous square
	if (isnull(area_to_order)) //If theres no supplypod bay mapped into centcom, throw an error
		to_chat(holder.mob, "No /area/centcom/supplypod/loading/one (or /two or /three or /four) in the world! You can make one yourself (then refresh) for now, but yell at a mapper to fix this, today!")
		CRASH("No /area/centcom/supplypod/loading/one (or /two or /three or /four) has been mapped into the centcom z-level!")
	orderedArea = list()
	if (length(area_to_order.contents)) //Go through the area passed into the proc, and figure out the top left and bottom right corners by calculating max and min values
		var/startX = area_to_order.contents[1].x //Create the four values (we do it off a.contents[1] so they have some sort of arbitrary initial value. They should be overwritten in a few moments)
		var/endX = area_to_order.contents[1].x
		var/startY = area_to_order.contents[1].y
		var/endY = area_to_order.contents[1].y
		for (var/turf/turf_in_area in area_to_order) //For each turf in the area, go through and find:
			if (turf_in_area.x < startX) //The turf with the smallest x value. This is our startX
				startX = turf_in_area.x
			else if (turf_in_area.x > endX) //The turf with the largest x value. This is our endX
				endX = turf_in_area.x
			else if (turf_in_area.y > startY) //The turf with the largest Y value. This is our startY
				startY = turf_in_area.y
			else if (turf_in_area.y < endY) //The turf with the smallest Y value. This is our endY
				endY = turf_in_area.y
		for (var/vertical in endY to startY)
			for (var/horizontal in startX to endX)
				orderedArea.Add(locate(horizontal, startY - (vertical - endY), 1)) //After gathering the start/end x and y, go through locating each turf from top left to bottom right, like one would read a book
	return orderedArea //Return the filled list

/datum/centcom_podlauncher/proc/preLaunch() //Creates a list of acceptable items,
	numTurfs = 0 //Counts the number of turfs that can be launched (remember, supplypods either launch all at once or one turf-worth of items at a time)
	acceptableTurfs = list()
	for (var/t in orderedArea) //Go through the orderedArea list
		var/turf/unchecked_turf = t
		if (iswallturf(unchecked_turf) || typecache_filter_list_reverse(unchecked_turf.contents, ignored_atoms).len != 0) //if there is something in this turf that isn't in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list
			acceptableTurfs.Add(unchecked_turf) //Because orderedArea was an ordered linear list, acceptableTurfs will be as well.
			numTurfs ++

	launchList = list() //Anything in launchList will go into the supplypod when it is launched
	if (length(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We dont fill the supplypod if acceptableTurfs is empty, if the pod is going in reverse (effectReverse=true), or if the pod is acitng like a missile (effectMissile=true)
		switch(launchChoice)
			if(LAUNCH_ALL) //If we are launching all the turfs at once
				for (var/t in acceptableTurfs)
					var/turf/accepted_turf = t
					launchList |= typecache_filter_list_reverse(accepted_turf.contents, ignored_atoms) //We filter any blacklisted atoms and add the rest to the launchList
					if (iswallturf(accepted_turf))
						launchList += accepted_turf
			if(LAUNCH_ORDERED) //If we are launching one at a time
				if (launchCounter > acceptableTurfs.len) //Check if the launchCounter, which acts as an index, is too high. If it is, reset it to 1
					launchCounter = 1 //Note that the launchCounter index is incremented in the launch() proc
				var/turf/next_turf_in_line = acceptableTurfs[launchCounter]
				launchList |= typecache_filter_list_reverse(next_turf_in_line.contents, ignored_atoms) //Filter the specicic turf chosen from acceptableTurfs, and add it to the launchList
				if (iswallturf(next_turf_in_line))
					launchList += next_turf_in_line
			if(LAUNCH_RANDOM) //If we are launching randomly
				var/turf/acceptable_turf = pick_n_take(acceptableTurfs)
				launchList |= typecache_filter_list_reverse(acceptable_turf.contents, ignored_atoms) //filter a random turf from the acceptableTurfs list and add it to the launchList
				if (iswallturf(acceptable_turf))
					launchList += acceptable_turf
	updateSelector() //Call updateSelector(), which, if we are launching one at a time (launchChoice==2), will move to the next turf that will be launched
	//UpdateSelector() is here (instead if the if(1) switch block) because it also moves the selector to nullspace (to hide it) if needed

/datum/centcom_podlauncher/proc/launch(turf/target_turf) //Game time started
	if (isnull(target_turf))
		return
	var/obj/structure/closet/supplypod/centcompod/toLaunch = DuplicateObject(temp_pod) //Duplicate the temp_pod (which we have been varediting or configuring with the UI) and store the result
	toLaunch.update_appearance()//we update_appearance() here so that the door doesnt "flicker on" right after it lands
	var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/supplypod_temp_holding]
	toLaunch.forceMove(shippingLane)
	if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those
		if(launchRandomItem)
			var/launch_candidate = pick_n_take(launchList)
			if(!isnull(launch_candidate))
				if (iswallturf(launch_candidate))
					var/atom/atom_to_launch = launch_candidate
					toLaunch.turfs_in_cargo += atom_to_launch.type
				else
					var/atom/movable/movable_to_launch = launch_candidate
					DuplicateObject(movable_to_launch).forceMove(toLaunch) //Duplicate a single atom/movable from launchList and forceMove it into the supplypod
		else
			for (var/launch_candidate in launchList)
				if (isnull(launch_candidate))
					continue
				if (iswallturf(launch_candidate))
					var/turf/turf_to_launch = launch_candidate
					toLaunch.turfs_in_cargo += turf_to_launch.type
				else
					var/atom/movable/movable_to_launch = launch_candidate
					DuplicateObject(movable_to_launch).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod
	else
		if(launchRandomItem)
			var/atom/random_item = pick_n_take(launchList)
			if(!isnull(random_item))
				if (iswallturf(random_item))
					var/turf/wall = random_item
					toLaunch.turfs_in_cargo += wall.type
					wall.ScrapeAway()
				else
					var/atom/movable/random_item_movable = random_item
					random_item_movable.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod
		else
			for (var/thing_to_launch in launchList) //If we aren't cloning the objects, just go through the launchList
				if (isnull(thing_to_launch))
					continue
				if(iswallturf(thing_to_launch))
					var/turf/wall = thing_to_launch
					toLaunch.turfs_in_cargo += wall.type
					wall.ScrapeAway()
				else
					var/atom/movable/movable_to_launch = thing_to_launch
					movable_to_launch.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod
	new /obj/effect/pod_landingzone(target_turf, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location
	if (launchClone)
		launchCounter++ //We only need to increment launchCounter if we are cloning objects.
		//If we aren't cloning objects, taking and removing the first item each time from the acceptableTurfs list will inherently iterate through the list in order

/datum/centcom_podlauncher/proc/updateSelector() //Ensures that the selector effect will showcase the next item if needed
	if (launchChoice == LAUNCH_ORDERED && length(acceptableTurfs) > 1 && !temp_pod.reversing && !temp_pod.effectMissile) //We only show the selector if we are taking items from the bay
		var/index = (launchCounter == 1 ? launchCounter : launchCounter + 1) //launchCounter acts as an index to the ordered acceptableTurfs list, so adding one will show the next item in the list. We don't want to do this for the very first item tho
		if (index > acceptableTurfs.len) //out of bounds check
			index = 1
		selector.forceMove(acceptableTurfs[index]) //forceMove the selector to the next turf in the ordered acceptableTurfs list
	else
		selector.moveToNullspace() //Otherwise, we move the selector to nullspace until it is needed again

/datum/centcom_podlauncher/proc/clearBay() //Clear all objs and mobs from the selected bay
	for (var/obj/O in bay.get_all_contents())
		qdel(O)
	for (var/mob/M in bay.get_all_contents())
		qdel(M)
	for (var/bayturf in bay)
		var/turf/turf_to_clear = bayturf
		turf_to_clear.ChangeTurf(/turf/open/floor/iron)

/datum/centcom_podlauncher/Destroy() //The Destroy() proc. This is called by ui_close proc, or whenever the user leaves the game
	updateCursor(TRUE) //Make sure our moues cursor resets to default. False means we are not in launch mode
	QDEL_NULL(temp_pod) //Delete the temp_pod
	QDEL_NULL(selector) //Delete the selector effect
	QDEL_NULL(indicator)
	. = ..()

/datum/centcom_podlauncher/proc/supplypod_punish_log(list/whoDyin)
	var/podString = effectBurst ? "5 pods" : "a pod"
	var/whomString = ""
	if (LAZYLEN(whoDyin))
		for (var/mob/living/M in whoDyin)
			whomString += "[key_name(M)], "

	var/msg = "launched [podString] towards [whomString]"
	message_admins("[key_name_admin(usr)] [msg] in [ADMIN_VERBOSEJMP(specificTarget)].")
	if (length(whoDyin))
		for (var/mob/living/M in whoDyin)
			admin_ticket_log(M, "[key_name_admin(usr)] [msg]")

/datum/centcom_podlauncher/proc/loadData(list/dataToLoad)
	bayNumber = dataToLoad["bayNumber"]
	customDropoff = dataToLoad["customDropoff"]
	renderLighting = dataToLoad["renderLighting"]
	launchClone = dataToLoad["launchClone"] //Do we launch the actual items in the bay or just launch clones of them?
	launchRandomItem = dataToLoad["launchRandomItem"] //Do we launch a single random item instead of everything on the turf?
	launchChoice = dataToLoad["launchChoice"] //Launch turfs all at once (0), ordered (1), or randomly(1)
	explosionChoice = dataToLoad["explosionChoice"] //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2)
	damageChoice = dataToLoad["damageChoice"] //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2)
	temp_pod.delays = dataToLoad["delays"]
	temp_pod.reverse_delays = dataToLoad["rev_delays"]
	temp_pod.custom_rev_delay = dataToLoad["custom_rev_delay"]
	temp_pod.setStyle(dataToLoad["styleChoice"])  //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the GLOB.podstyles list in cargo.dm defines to get the proper icon/name/desc for the pod.
	temp_pod.effectShrapnel = dataToLoad["effectShrapnel"] //If true, creates a cloud of shrapnel of a decided type and magnitude on landing
	temp_pod.shrapnel_type = text2path(dataToLoad["shrapnelType"])
	temp_pod.shrapnel_magnitude = dataToLoad["shrapnelMagnitude"]
	temp_pod.effectStun  = dataToLoad["effectStun"]//If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish!
	temp_pod.effectLimb  = dataToLoad["effectLimb"]//If true, pops off a limb (if applicable) from anyone caught under the pod when it lands
	temp_pod.effectOrgans = dataToLoad["effectOrgans"]//If true, yeets the organs out of any bodies caught under the pod when it lands
	temp_pod.bluespace = dataToLoad["effectBluespace"] //If true, the pod deletes (in a shower of sparks) after landing
	temp_pod.effectStealth = dataToLoad["effectStealth"]//If true, a target icon isn't displayed on the turf where the pod will land
	temp_pod.effectQuiet = dataToLoad["effectQuiet"] //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc)
	temp_pod.effectMissile = dataToLoad["effectMissile"] //If true, the pod deletes the second it lands. If you give it an explosion, it will act like a missile exploding as it hits the ground
	temp_pod.effectCircle = dataToLoad["effectCircle"] //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here
	effectBurst = dataToLoad["effectBurst"] //IOf true, launches five pods at once (with a very small delay between for added coolness), in a 3x3 area centered around the area
	temp_pod.reversing = dataToLoad["effectReverse"] //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
	temp_pod.reverse_option_list = dataToLoad["reverse_option_list"]
	specificTarget = dataToLoad["effectTarget"] //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites
	temp_pod.adminNamed = dataToLoad["effectName"] //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
	temp_pod.name = dataToLoad["podName"]
	temp_pod.desc = dataToLoad["podDesc"]
	effectAnnounce = dataToLoad["effectAnnounce"]
	numTurfs = dataToLoad["numObjects"] //Counts the number of turfs that contain a launchable object in the centcom supplypod bay
	temp_pod.fallingSound = dataToLoad["fallingSound"]//Admin sound to play as the pod falls
	temp_pod.landingSound = dataToLoad["landingSound"]//Admin sound to play when the pod lands
	temp_pod.openingSound = dataToLoad["openingSound"]//Admin sound to play when the pod opens
	temp_pod.leavingSound = dataToLoad["leavingSound"]//Admin sound to play when the pod leaves
	temp_pod.soundVolume = dataToLoad["soundVolume"] //Admin sound to play when the pod leaves
	picking_dropoff_turf = FALSE
	launcherActivated = FALSE
	updateCursor()
	refreshView()

GLOBAL_DATUM_INIT(podlauncher, /datum/centcom_podlauncher, new)
//Proc for admins to enable others to use podlauncher after roundend
/datum/centcom_podlauncher/proc/give_podlauncher(mob/living/user, override)
	if (SSticker.current_state < GAME_STATE_FINISHED)
		return
	if (!istype(user))
		user = override
	if (user)
		setup(user)//setup the datum

//Set the dropoff location and indicator to either a specific turf or somewhere in an area
/datum/centcom_podlauncher/proc/setDropoff(target)
	var/turf/target_turf
	if (isturf(target))
		target_turf = target
	else if (isarea(target))
		target_turf = pick(get_area_turfs(target))
	else
		CRASH("Improper type passed to setDropoff! Should be /turf or /area")
	temp_pod.reverse_dropoff_coords = list(target_turf.x, target_turf.y, target_turf.z)
	indicator.forceMove(target_turf)

/obj/effect/hallucination/simple/supplypod_selector
	name = "Supply Selector (Only you can see this)"
	image_icon = 'icons/obj/supplypods_32x32.dmi'
	image_state = "selector"
	image_layer = FLY_LAYER
	alpha = 150

/obj/effect/hallucination/simple/dropoff_location
	name = "Dropoff Location (Only you can see this)"
	image_icon = 'icons/obj/supplypods_32x32.dmi'
	image_state = "dropoff_indicator"
	image_layer = FLY_LAYER
	alpha = 0


code:
#define COUPON_OMEN "omen"

/obj/item/coupon
	name = "coupon"
	desc = "It doesn't matter if you didn't want it before, what matters now is that you've got a coupon for it!"
	icon_state = "data_1"
	icon = 'icons/obj/card.dmi'
	item_flags = NOBLUDGEON
	w_class = WEIGHT_CLASS_TINY
	var/datum/supply_pack/discounted_pack
	var/discount_pct_off = 0.05
	var/obj/machinery/computer/cargo/inserted_console

/// Choose what our prize is :D
/obj/item/coupon/proc/generate(rig_omen=FALSE)
	discounted_pack = pick(subtypesof(/datum/supply_pack/goody))
	var/list/chances = list("0.10" = 4, "0.15" = 8, "0.20" = 10, "0.25" = 8, "0.50" = 4, COUPON_OMEN = 1)
	if(rig_omen)
		discount_pct_off = COUPON_OMEN
	else
		discount_pct_off = pick_weight(chances)
	if(discount_pct_off == COUPON_OMEN)
		name = "coupon - fuck you"
		desc = "The small text reads, 'You will be slaughtered'... That doesn't sound right, does it?"
		if(ismob(loc))
			var/mob/M = loc
			to_chat(M, span_warning("The coupon reads '<b>fuck you</b>' in large, bold text... is- is that a prize, or?"))
			M.AddComponent(/datum/component/omen, TRUE, src)
	else
		discount_pct_off = text2num(discount_pct_off)
		name = "coupon - [round(discount_pct_off * 100)]% off [initial(discounted_pack.name)]"

/obj/item/coupon/attack_atom(obj/O, mob/living/user, params)
	if(!istype(O, /obj/machinery/computer/cargo))
		return ..()
	if(discount_pct_off == COUPON_OMEN)
		to_chat(user, span_warning("\The [O] validates the coupon as authentic, but refuses to accept it..."))
		O.say("Coupon fulfillment already in progress...")
		return

	inserted_console = O
	LAZYADD(inserted_console.loaded_coupons, src)
	inserted_console.say("Coupon for [initial(discounted_pack.name)] applied!")
	forceMove(inserted_console)

/obj/item/coupon/Destroy()
	if(inserted_console)
		LAZYREMOVE(inserted_console.loaded_coupons, src)
		inserted_console = null
	. = ..()

#undef COUPON_OMEN


code:
/obj/item/export_scanner
	name = "export scanner"
	desc = "A device used to check objects against Nanotrasen exports database."
	icon = 'icons/obj/device.dmi'
	icon_state = "export_scanner"
	inhand_icon_state = "radio"
	lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
	righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
	item_flags = NOBLUDGEON
	w_class = WEIGHT_CLASS_SMALL

/obj/item/export_scanner/afterattack(obj/O, mob/user, proximity)
	. = ..()
	if(!istype(O) || !proximity)
		return

	// Before you fix it:
	// yes, checking manifests is a part of intended functionality.
	var/datum/export_report/ex = export_item_and_contents(O, dry_run=TRUE)
	var/price = 0
	for(var/x in ex.total_amount)
		price += ex.total_value[x]
	if(price)
		to_chat(user, span_notice("Scanned [O], value: [price] credits[O.contents.len ? " (contents included)" : ""]."))
	else
		to_chat(user, span_warning("Scanned [O], no export value."))

	if(ishuman(user))
		var/mob/living/carbon/human/scan_human = user
		if(istype(O, /obj/item/bounty_cube))
			var/obj/item/bounty_cube/cube = O

			if(!istype(get_area(cube), /area/shuttle/supply))
				to_chat(user, span_warning("Shuttle placement not detected. Handling tip not registered."))

			else if(cube.bounty_handler_account)
				to_chat(user, span_warning("Bank account for handling tip already registered!"))

			else if(scan_human.get_bank_account() && cube.GetComponent(/datum/component/pricetag))
				var/datum/component/pricetag/pricetag = cube.GetComponent(/datum/component/pricetag)

				cube.bounty_handler_account = scan_human.get_bank_account()
				pricetag.payees[cube.bounty_handler_account] += cube.handler_tip

				cube.bounty_handler_account.bank_card_talk("Bank account for [price ? "[price * cube.handler_tip] credit " : ""]handling tip successfully registered.")

				if(cube.bounty_holder_account != cube.bounty_handler_account) //No need to send a tracking update to the person scanning it
					cube.bounty_holder_account.bank_card_talk("[cube] was scanned in \the [get_area(cube)] by [scan_human] ([scan_human.job]).")

			else
				to_chat(user, span_warning("Bank account not detected. Handling tip not registered."))