code:
/datum/buildmode_mode/throwing
	key = "throw"

	var/atom/movable/throw_atom = null

/datum/buildmode_mode/throwing/Destroy()
	throw_atom = null
	return ..()

/datum/buildmode_mode/throwing/show_help(client/c)
	to_chat(c, span_notice("***********************************************************"))
	to_chat(c, span_notice("Left Mouse Button on turf/obj/mob      = Select"))
	to_chat(c, span_notice("Right Mouse Button on turf/obj/mob     = Throw"))
	to_chat(c, span_notice("***********************************************************"))

/datum/buildmode_mode/throwing/handle_click(client/c, params, obj/object)
	var/list/modifiers = params2list(params)

	if(LAZYACCESS(modifiers, LEFT_CLICK))
		if(isturf(object))
			return
		throw_atom = object
		to_chat(c, "Selected object '[throw_atom]'")
	if(LAZYACCESS(modifiers, RIGHT_CLICK))
		if(throw_atom)
			throw_atom.throw_at(object, 10, 1, c.mob)
			log_admin("Build Mode: [key_name(c)] threw [throw_atom] at [object] ([AREACOORD(object)])")


code:
/datum/buildmode_mode/varedit
	key = "edit"
	// Varedit mode
	var/varholder = null
	var/valueholder = null

/datum/buildmode_mode/varedit/Destroy()
	varholder = null
	valueholder = null
	return ..()

/datum/buildmode_mode/varedit/show_help(client/c)
	to_chat(c, span_notice("***********************************************************"))
	to_chat(c, span_notice("Right Mouse Button on buildmode button = Select var(type) & value"))
	to_chat(c, span_notice("Left Mouse Button on turf/obj/mob      = Set var(type) & value"))
	to_chat(c, span_notice("Right Mouse Button on turf/obj/mob     = Reset var's value"))
	to_chat(c, span_notice("***********************************************************"))

/datum/buildmode_mode/varedit/Reset()
	. = ..()
	varholder = null
	valueholder = null

/datum/buildmode_mode/varedit/change_settings(client/c)
	varholder = input(c, "Enter variable name:" ,"Name", "name")

	if(!vv_varname_lockcheck(varholder))
		return

	var/temp_value = c.vv_get_value()
	if(isnull(temp_value["class"]))
		Reset()
		to_chat(c, span_notice("Variable unset."))
		return
	valueholder = temp_value["value"]

/datum/buildmode_mode/varedit/handle_click(client/c, params, obj/object)
	var/list/modifiers = params2list(params)

	if(isnull(varholder))
		to_chat(c, span_warning("Choose a variable to modify first."))
		return
	if(LAZYACCESS(modifiers, LEFT_CLICK))
		if(object.vars.Find(varholder))
			if(object.vv_edit_var(varholder, valueholder) == FALSE)
				to_chat(c, span_warning("Your edit was rejected by the object."))
				return
			log_admin("Build Mode: [key_name(c)] modified [object.name]'s [varholder] to [valueholder]")
		else
			to_chat(c, span_warning("[initial(object.name)] does not have a var called '[varholder]'"))
	if(LAZYACCESS(modifiers, RIGHT_CLICK))
		if(object.vars.Find(varholder))
			var/reset_value = initial(object.vars[varholder])
			if(object.vv_edit_var(varholder, reset_value) == FALSE)
				to_chat(c, span_warning("Your edit was rejected by the object."))
				return
			log_admin("Build Mode: [key_name(c)] modified [object.name]'s [varholder] to [reset_value]")
		else
			to_chat(c, span_warning("[initial(object.name)] does not have a var called '[varholder]'"))

repo_name: AnalWerewolf/sundown

license: mit


code: #define CTF_REQUIRED_PLAYERS 4


code:
// GENERIC CLASSES

/datum/outfit/ctf
	name = "CTF Rifleman (Solo)"
	ears = /obj/item/radio/headset
	uniform = /obj/item/clothing/under/syndicate
	suit = /obj/item/clothing/suit/armor/vest/ctf
	toggle_helmet = FALSE // see the whites of their eyes
	shoes = /obj/item/clothing/shoes/combat
	gloves = /obj/item/clothing/gloves/combat
	id = /obj/item/card/id/away
	belt = /obj/item/gun/ballistic/automatic/pistol/deagle/ctf
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf

	///Description to be shown in the class selection menu
	var/class_description = "General purpose combat class. Armed with a laser rifle and backup pistol."
	///Radio frequency to assign players with this outfit
	var/team_radio_freq = FREQ_COMMON // they won't be able to use this on the centcom z-level, so ffa players cannot use radio
	///Icon file for the class radial menu icons
	var/icon = 'icons/hud/radial_ctf.dmi'
	///Icon state for this class
	var/icon_state = "ctf_rifleman"
	///Do they get a headset?
	var/has_radio = TRUE
	///Do they get an ID?
	var/has_card = TRUE
	///Which slots to apply TRAIT_NODROP to the items in
	var/list/nodrop_slots = list(ITEM_SLOT_OCLOTHING, ITEM_SLOT_GLOVES, ITEM_SLOT_FEET, ITEM_SLOT_ICLOTHING, ITEM_SLOT_EARS)

/datum/outfit/ctf/post_equip(mob/living/carbon/human/human_to_equip, visualsOnly=FALSE)
	if(visualsOnly)
		return
	var/list/no_drops = list()

	if(has_card)
		var/obj/item/card/id/idcard = human_to_equip.wear_id
		no_drops += idcard
		idcard.registered_name = human_to_equip.real_name
		idcard.update_label()
		idcard.update_icon()

	// Make clothing in the specified slots NODROP
	for(var/slot in nodrop_slots)
		no_drops += human_to_equip.get_item_by_slot(slot)
	// Make items in the hands NODROP
	for(var/obj/item/held_item in human_to_equip.held_items)
		no_drops += held_item
	list_clear_nulls(no_drops) // For any slots we didn't have filled
	// Apply TRAIT_NODROP to everything
	for(var/obj/item/item_to_nodrop as anything in no_drops)
		ADD_TRAIT(item_to_nodrop, TRAIT_NODROP, CAPTURE_THE_FLAG_TRAIT)

	if(has_radio)
		var/obj/item/radio/headset = human_to_equip.ears
		headset.set_frequency(team_radio_freq)
		headset.freqlock = TRUE
		headset.independent = TRUE
	human_to_equip.dna.species.stunmod = 0

/datum/outfit/ctf/instagib
	name = "CTF Instagib (Solo)"
	r_hand = /obj/item/gun/energy/laser/instakill/ctf
	shoes = /obj/item/clothing/shoes/jackboots/fast
	icon_state = "ctf_instakill"
	class_description = "General purpose combat class. Armed with a laser rifle and backup pistol."

/datum/outfit/ctf/assault
	name = "CTF Assaulter (Solo)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/light
	r_hand = /obj/item/gun/ballistic/shotgun/ctf
	gloves = /obj/item/clothing/gloves/tackler/rocket
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun
	belt = null
	icon_state = "ctf_assaulter"
	class_description = "Close combat class. Armed with a shotgun and rocket gloves."

/datum/outfit/ctf/marksman
	name = "CTF Marksman (Solo)"
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman
	belt = null
	icon_state = "ctf_marksman"
	class_description = "Long range class. Armed with a hitscan laser rifle."

// RED TEAM CLASSES

/datum/outfit/ctf/red
	name = "CTF Rifleman (Red)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/red
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/red
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/red
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/red
	id = /obj/item/card/id/red //it's red
	team_radio_freq = FREQ_CTF_RED

/datum/outfit/ctf/red/instagib
	name = "CTF Instagib (Red)"
	r_hand = /obj/item/gun/energy/laser/instakill/ctf/red
	shoes = /obj/item/clothing/shoes/jackboots/fast
	team_radio_freq = FREQ_CTF_RED

/datum/outfit/ctf/assault/red
	name = "CTF Assaulter (Red)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/light/red
	r_hand = /obj/item/gun/ballistic/shotgun/ctf/red
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/red
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/red
	id = /obj/item/card/id/red
	team_radio_freq = FREQ_CTF_RED

/datum/outfit/ctf/marksman/red
	name = "CTF Marksman (Red)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/red
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/red
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/red
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/red
	id = /obj/item/card/id/red
	team_radio_freq = FREQ_CTF_RED

// BLUE TEAM CLASSES

/datum/outfit/ctf/blue
	name = "CTF Rifleman (Blue)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/blue
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/blue
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/blue
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/blue
	id = /obj/item/card/id/blue //it's blue
	team_radio_freq = FREQ_CTF_BLUE

/datum/outfit/ctf/blue/instagib
	name = "CTF Instagib (Blue)"
	r_hand = /obj/item/gun/energy/laser/instakill/ctf/blue
	shoes = /obj/item/clothing/shoes/jackboots/fast
	team_radio_freq = FREQ_CTF_BLUE

/datum/outfit/ctf/assault/blue
	name = "CTF Assaulter (Blue)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/light/blue
	r_hand = /obj/item/gun/ballistic/shotgun/ctf/blue
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/blue
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/blue
	id = /obj/item/card/id/blue
	team_radio_freq = FREQ_CTF_BLUE

/datum/outfit/ctf/marksman/blue
	name = "CTF Marksman (Blue)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/blue
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/blue
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/blue
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/blue
	id = /obj/item/card/id/blue
	team_radio_freq = FREQ_CTF_BLUE

// GREEN TEAM CLASSES

/datum/outfit/ctf/green
	name = "CTF Rifleman (Green)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/green
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/green
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/green
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/green
	id = /obj/item/card/id/green //it's green
	team_radio_freq = FREQ_CTF_GREEN

/datum/outfit/ctf/green/instagib
	name = "CTF Instagib (Green)"
	r_hand = /obj/item/gun/energy/laser/instakill/ctf/green
	shoes = /obj/item/clothing/shoes/jackboots/fast
	team_radio_freq = FREQ_CTF_GREEN

/datum/outfit/ctf/assault/green
	name = "CTF Assaulter (Green)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/light/green
	r_hand = /obj/item/gun/ballistic/shotgun/ctf/green
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/green
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/green
	id = /obj/item/card/id/green
	team_radio_freq = FREQ_CTF_GREEN

/datum/outfit/ctf/marksman/green
	name = "CTF Marksman (Green)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/green
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/green
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/green
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/green
	id = /obj/item/card/id/green
	team_radio_freq = FREQ_CTF_GREEN

// YELLOW TEAM CLASSES

/datum/outfit/ctf/yellow
	name = "CTF Rifleman (Yellow)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/yellow
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/yellow
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/yellow
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/yellow
	id = /obj/item/card/id/yellow //it's yellow
	team_radio_freq = FREQ_CTF_YELLOW

/datum/outfit/ctf/yellow/instagib
	name = "CTF Instagib (Yellow)"
	r_hand = /obj/item/gun/energy/laser/instakill/ctf/yellow
	shoes = /obj/item/clothing/shoes/jackboots/fast
	team_radio_freq = FREQ_CTF_YELLOW

/datum/outfit/ctf/assault/yellow
	name = "CTF Assaulter (Yellow)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/light/yellow
	r_hand = /obj/item/gun/ballistic/shotgun/ctf/yellow
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/yellow
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/yellow
	id = /obj/item/card/id/yellow
	team_radio_freq = FREQ_CTF_YELLOW

/datum/outfit/ctf/marksman/yellow
	name = "CTF Marksman (Yellow)"
	suit = /obj/item/clothing/suit/armor/vest/ctf/yellow
	r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/yellow
	l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/yellow
	r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/yellow
	id = /obj/item/card/id/yellow
	team_radio_freq = FREQ_CTF_YELLOW


code:
// GENERIC PROJECTILE

/obj/projectile/beam/ctf
	damage = 0
	icon_state = "omnilaser"

/obj/projectile/beam/ctf/prehit_pierce(atom/target)
	if(!is_ctf_target(target))
		damage = 0
		return PROJECTILE_PIERCE_NONE /// hey uhhh don't hit anyone behind them
	. = ..()

/obj/projectile/beam/ctf/on_hit(atom/target, blocked = FALSE)
	. = ..()
	if(is_ctf_target(target) && blocked == FALSE)
		if(iscarbon(target))
			var/mob/living/carbon/target_mob = target
			target_mob.adjustBruteLoss(150, 0)
		return BULLET_ACT_HIT

/obj/item/ammo_box/magazine/recharge/ctf
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf

/obj/item/ammo_box/magazine/recharge/ctf/Initialize(mapload)
	. = ..()
	AddElement(/datum/element/delete_on_drop)

/obj/item/ammo_casing/caseless/laser/ctf
	projectile_type = /obj/projectile/beam/ctf/

/obj/item/ammo_casing/caseless/laser/ctf/Initialize(mapload)
	. = ..()
	AddElement(/datum/element/delete_on_drop)

// LASER RIFLE

/obj/item/gun/ballistic/automatic/laser/ctf
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/rifle
	desc = "This looks like it could really hurt in melee."
	force = 50
	weapon_weight = WEAPON_HEAVY
	slot_flags = null

/obj/item/gun/ballistic/automatic/laser/ctf/Initialize(mapload)
	. = ..()
	AddElement(/datum/element/delete_on_drop)

/obj/item/ammo_box/magazine/recharge/ctf/rifle
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/rifle

/obj/item/ammo_casing/caseless/laser/ctf/rifle
	projectile_type = /obj/projectile/beam/ctf/rifle

/obj/projectile/beam/ctf/rifle
	damage = 45
	light_color = LIGHT_COLOR_BLUE
	impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser

// LASER SHOTGUN

/obj/item/gun/ballistic/shotgun/ctf
	name = "laser shotgun"
	desc = "This looks like it could really hurt in melee."
	icon_state = "ctfshotgun"
	inhand_icon_state = "shotgun_combat"
	worn_icon_state = "gun"
	slot_flags = null
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/shotgun
	empty_indicator = TRUE
	fire_sound = 'sound/weapons/gun/shotgun/shot_alt.ogg'
	semi_auto = TRUE
	internal_magazine = FALSE
	tac_reloads = TRUE

/obj/item/gun/ballistic/shotgun/ctf/Initialize(mapload)
	. = ..()
	AddElement(/datum/element/delete_on_drop)

/obj/item/ammo_box/magazine/recharge/ctf/shotgun
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/shotgun
	max_ammo = 6

/obj/item/ammo_casing/caseless/laser/ctf/shotgun
	projectile_type = /obj/projectile/beam/ctf/shotgun
	pellets = 6
	variance = 25

/obj/projectile/beam/ctf/shotgun
	damage = 15
	light_color = LIGHT_COLOR_BLUE
	impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser

// MARKSMAN RIFLE

/obj/item/gun/ballistic/automatic/laser/ctf/marksman
	name = "designated marksman rifle"
	icon_state = "ctfmarksman"
	inhand_icon_state = "ctfmarksman"
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/marksman
	fire_delay = 1 SECONDS

/obj/item/ammo_box/magazine/recharge/ctf/marksman
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/marksman
	max_ammo = 10

/obj/item/ammo_casing/caseless/laser/ctf/marksman
	projectile_type = /obj/projectile/beam/ctf/marksman

/obj/projectile/beam/ctf/marksman
	damage = 30
	hitscan = TRUE
	tracer_type = /obj/effect/projectile/tracer/laser/blue
	muzzle_type = /obj/effect/projectile/muzzle/laser/blue
	impact_type = /obj/effect/projectile/impact/laser/blue

// DESERT EAGLE

/obj/item/gun/ballistic/automatic/pistol/deagle/ctf
	desc = "This looks like it could really hurt in melee."
	force = 75
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/deagle

/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/Initialize(mapload)
	. = ..()
	AddElement(/datum/element/delete_on_drop)

/obj/item/ammo_box/magazine/recharge/ctf/deagle
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/deagle
	max_ammo = 7

/obj/item/ammo_casing/caseless/laser/ctf/deagle
	projectile_type = /obj/projectile/beam/ctf/deagle

/obj/projectile/beam/ctf/deagle
	icon_state = "bullet"
	damage = 60
	light_color = COLOR_WHITE
	impact_effect_type = /obj/effect/temp_visual/impact_effect

// INSTAKILL RIFLE

/obj/item/gun/energy/laser/instakill
	name = "instakill rifle"
	icon_state = "instagib"
	inhand_icon_state = "instagib"
	desc = "A specialized ASMD laser-rifle, capable of flat-out disintegrating most targets in a single hit."
	w_class = WEIGHT_CLASS_BULKY
	ammo_type = list(/obj/item/ammo_casing/energy/instakill)
	force = 60
	slot_flags = null
	charge_sections = 5
	ammo_x_offset = 2
	shaded_charge = FALSE

/obj/item/gun/energy/laser/instakill/emp_act() //implying you could stop the instagib
	return

/obj/item/gun/energy/laser/instakill/ctf/Initialize(mapload)
	. = ..()
	AddElement(/datum/element/delete_on_drop)

/obj/item/ammo_casing/energy/instakill
	projectile_type = /obj/projectile/beam/instakill
	e_cost = 0
	select_name = "DESTROY"

/obj/projectile/beam/instakill
	name = "instagib laser"
	icon_state = "purple_laser"
	damage = 200
	damage_type = BURN
	impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
	light_color = LIGHT_COLOR_PURPLE

/obj/projectile/beam/instakill/on_hit(atom/target)
	. = ..()
	if(iscarbon(target))
		var/mob/living/carbon/target_mob = target
		target_mob.visible_message(span_danger("[target_mob] explodes into a shower of gibs!"))
		target_mob.gib()

// SHIELDED VEST

/obj/item/clothing/suit/armor/vest/ctf
	name = "white shielded vest"
	desc = "Standard issue vest for playing capture the flag."
	icon = 'icons/mob/clothing/suits/ctf.dmi'
	worn_icon = 'icons/mob/clothing/suits/ctf.dmi'
	icon_state = "standard"
	// Adding TRAIT_NODROP is done when the CTF spawner equips people
	armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0) // CTF gear gives no protection outside of the shield
	allowed = null
	greyscale_config = /datum/greyscale_config/ctf_standard
	greyscale_config_worn = /datum/greyscale_config/ctf_standard_worn
	greyscale_colors = "#ffffff"

	///Icon state to be fed into the shielded component
	var/team_shield_icon = "shield-old"

/obj/item/clothing/suit/armor/vest/ctf/setup_shielding()
	AddComponent(/datum/component/shielded, max_charges = 150, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 30, lose_multiple_charges = TRUE, shield_icon = team_shield_icon)

// LIGHT SHIELDED VEST

/obj/item/clothing/suit/armor/vest/ctf/light
	name = "light white shielded vest"
	desc = "Lightweight vest for playing capture the flag."
	icon_state = "light"
	greyscale_config = /datum/greyscale_config/ctf_light
	greyscale_config_worn = /datum/greyscale_config/ctf_light_worn
	slowdown = -0.25

/obj/item/clothing/suit/armor/vest/ctf/light/setup_shielding()
	AddComponent(/datum/component/shielded, max_charges = 30, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 30, lose_multiple_charges = TRUE, shield_icon = team_shield_icon)

// RED TEAM GUNS

// Rifle
/obj/item/gun/ballistic/automatic/laser/ctf/red
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/rifle/red

/obj/item/ammo_box/magazine/recharge/ctf/rifle/red
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/rifle/red

/obj/item/ammo_casing/caseless/laser/ctf/rifle/red
	projectile_type = /obj/projectile/beam/ctf/rifle/red

/obj/projectile/beam/ctf/rifle/red
	icon_state = "laser"
	light_color = COLOR_SOFT_RED
	impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser

// Shotgun
/obj/item/gun/ballistic/shotgun/ctf/red
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/red

/obj/item/ammo_box/magazine/recharge/ctf/shotgun/red
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/shotgun/red

/obj/item/ammo_casing/caseless/laser/ctf/shotgun/red
	projectile_type = /obj/projectile/beam/ctf/shotgun/red

/obj/projectile/beam/ctf/shotgun/red
	icon_state = "laser"
	light_color = COLOR_SOFT_RED
	impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser

// DMR
/obj/item/gun/ballistic/automatic/laser/ctf/marksman/red
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/marksman/red

/obj/item/ammo_box/magazine/recharge/ctf/marksman/red
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/marksman/red

/obj/item/ammo_casing/caseless/laser/ctf/marksman/red
	projectile_type = /obj/projectile/beam/ctf/marksman/red

/obj/projectile/beam/ctf/marksman/red
	icon_state = "laser"
	tracer_type = /obj/effect/projectile/tracer/laser
	muzzle_type = /obj/effect/projectile/muzzle/laser
	impact_type = /obj/effect/projectile/impact/laser

// Instakill
/obj/item/gun/energy/laser/instakill/ctf/red
	desc = "A specialized ASMD laser-rifle, capable of flat-out disintegrating most targets in a single hit. This one has a red design."
	icon_state = "instagibred"
	inhand_icon_state = "instagibred"
	ammo_type = list(/obj/item/ammo_casing/energy/instakill/red)

/obj/item/ammo_casing/energy/instakill/red
	projectile_type = /obj/projectile/beam/instakill/red

/obj/projectile/beam/instakill/red
	icon_state = "red_laser"
	impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser
	light_color = COLOR_SOFT_RED

// BLUE TEAM GUNS

// Rifle
/obj/item/gun/ballistic/automatic/laser/ctf/blue
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/rifle/blue

/obj/item/ammo_box/magazine/recharge/ctf/rifle/blue
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/rifle/blue

/obj/item/ammo_casing/caseless/laser/ctf/rifle/blue
	projectile_type = /obj/projectile/beam/ctf/rifle/blue

/obj/projectile/beam/ctf/rifle/blue
	icon_state = "bluelaser"
	impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser

// Shotgun
/obj/item/gun/ballistic/shotgun/ctf/blue
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/blue

/obj/item/ammo_box/magazine/recharge/ctf/shotgun/blue
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/shotgun/blue

/obj/item/ammo_casing/caseless/laser/ctf/shotgun/blue
	projectile_type = /obj/projectile/beam/ctf/shotgun/blue

/obj/projectile/beam/ctf/shotgun/blue
	icon_state = "bluelaser"
	impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser

// DMR
/obj/item/gun/ballistic/automatic/laser/ctf/marksman/blue
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/marksman/blue

/obj/item/ammo_box/magazine/recharge/ctf/marksman/blue
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/marksman/blue

/obj/item/ammo_casing/caseless/laser/ctf/marksman/blue
	projectile_type = /obj/projectile/beam/ctf/marksman/blue

/obj/projectile/beam/ctf/marksman/blue

// Instakill
/obj/item/gun/energy/laser/instakill/ctf/blue
	desc = "A specialized ASMD laser-rifle, capable of flat-out disintegrating most targets in a single hit. This one has a blue design."
	icon_state = "instagibblue"
	inhand_icon_state = "instagibblue"
	ammo_type = list(/obj/item/ammo_casing/energy/instakill/blue)

/obj/item/ammo_casing/energy/instakill/blue
	projectile_type = /obj/projectile/beam/instakill/blue

/obj/projectile/beam/instakill/blue
	icon_state = "blue_laser"
	impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
	light_color = LIGHT_COLOR_BLUE

// GREEN TEAM GUNS

// Rifle
/obj/item/gun/ballistic/automatic/laser/ctf/green
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/rifle/green

/obj/item/ammo_box/magazine/recharge/ctf/rifle/green
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/rifle/green

/obj/item/ammo_casing/caseless/laser/ctf/rifle/green
	projectile_type = /obj/projectile/beam/ctf/rifle/green

/obj/projectile/beam/ctf/rifle/green
	icon_state = "xray"
	light_color = COLOR_VERY_PALE_LIME_GREEN
	impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser

// Shotgun
/obj/item/gun/ballistic/shotgun/ctf/green
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/green

/obj/item/ammo_box/magazine/recharge/ctf/shotgun/green
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/shotgun/green

/obj/item/ammo_casing/caseless/laser/ctf/shotgun/green
	projectile_type = /obj/projectile/beam/ctf/shotgun/green

/obj/projectile/beam/ctf/shotgun/green
	icon_state = "xray"
	light_color = COLOR_VERY_PALE_LIME_GREEN
	impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser

// DMR
/obj/item/gun/ballistic/automatic/laser/ctf/marksman/green
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/marksman/green

/obj/item/ammo_box/magazine/recharge/ctf/marksman/green
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/marksman/green

/obj/item/ammo_casing/caseless/laser/ctf/marksman/green
	projectile_type = /obj/projectile/beam/ctf/marksman/green

/obj/projectile/beam/ctf/marksman/green
	icon_state = "xray"
	tracer_type = /obj/effect/projectile/tracer/xray
	muzzle_type = /obj/effect/projectile/muzzle/xray
	impact_type = /obj/effect/projectile/impact/xray

// Instakill
/obj/item/gun/energy/laser/instakill/ctf/green
	desc = "A specialized ASMD laser-rifle, capable of flat-out disintegrating most targets in a single hit. This one has a green design."
	icon_state = "instagibgreen"
	inhand_icon_state = "instagibgreen"
	ammo_type = list(/obj/item/ammo_casing/energy/instakill/green)

/obj/item/ammo_casing/energy/instakill/green
	projectile_type = /obj/projectile/beam/instakill/green

/obj/projectile/beam/instakill/green
	icon_state = "green_laser"
	impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
	light_color = COLOR_VERY_PALE_LIME_GREEN

// YELLOW TEAM GUNS

// Rifle
/obj/item/gun/ballistic/automatic/laser/ctf/yellow
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/rifle/yellow

/obj/item/ammo_box/magazine/recharge/ctf/rifle/yellow
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/rifle/yellow

/obj/item/ammo_casing/caseless/laser/ctf/rifle/yellow
	projectile_type = /obj/projectile/beam/ctf/rifle/yellow

/obj/projectile/beam/ctf/rifle/yellow
	icon_state = "gaussstrong"
	light_color = COLOR_VERY_SOFT_YELLOW
	impact_effect_type = /obj/effect/temp_visual/impact_effect/yellow_laser

// Shotgun
/obj/item/gun/ballistic/shotgun/ctf/yellow
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/yellow

/obj/item/ammo_box/magazine/recharge/ctf/shotgun/yellow
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/shotgun/yellow

/obj/item/ammo_casing/caseless/laser/ctf/shotgun/yellow
	projectile_type = /obj/projectile/beam/ctf/shotgun/yellow

/obj/projectile/beam/ctf/shotgun/yellow
	icon_state = "gaussstrong"
	light_color = COLOR_VERY_SOFT_YELLOW
	impact_effect_type = /obj/effect/temp_visual/impact_effect/yellow_laser

// DMR
/obj/item/gun/ballistic/automatic/laser/ctf/marksman/yellow
	mag_type = /obj/item/ammo_box/magazine/recharge/ctf/marksman/yellow

/obj/item/ammo_box/magazine/recharge/ctf/marksman/yellow
	ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/marksman/yellow

/obj/item/ammo_casing/caseless/laser/ctf/marksman/yellow
	projectile_type = /obj/projectile/beam/ctf/marksman/yellow

/obj/projectile/beam/ctf/marksman/yellow
	icon_state = "gaussstrong"
	tracer_type = /obj/effect/projectile/tracer/solar
	muzzle_type = /obj/effect/projectile/muzzle/solar
	impact_type = /obj/effect/projectile/impact/solar

// Instakill
/obj/item/gun/energy/laser/instakill/ctf/yellow
	desc = "A specialized ASMD laser-rifle, capable of flat-out disintegrating most targets in a single hit. This one has a yellow design."
	icon_state = "instagibyellow"
	inhand_icon_state = "instagibyellow"
	ammo_type = list(/obj/item/ammo_casing/energy/instakill/yellow)

/obj/item/ammo_casing/energy/instakill/yellow
	projectile_type = /obj/projectile/beam/instakill/yellow

/obj/projectile/beam/instakill/yellow
	icon_state = "yellow_laser"
	impact_effect_type = /obj/effect/temp_visual/impact_effect/yellow_laser
	light_color = COLOR_VERY_SOFT_YELLOW

// RED TEAM SUITS

// Regular
/obj/item/clothing/suit/armor/vest/ctf/red
	name = "red shielded vest"
	inhand_icon_state = "ert_security"
	team_shield_icon = "shield-red"
	greyscale_colors = COLOR_VIVID_RED

// Light
/obj/item/clothing/suit/armor/vest/ctf/light/red
	name = "light red shielded vest"
	inhand_icon_state = "ert_security"
	team_shield_icon = "shield-red"
	greyscale_colors = COLOR_VIVID_RED

// BLUE TEAM SUITS

// Regular
/obj/item/clothing/suit/armor/vest/ctf/blue
	name = "blue shielded vest"
	inhand_icon_state = "ert_command"
	team_shield_icon = "shield-old"
	greyscale_colors = COLOR_DARK_CYAN

// Light
/obj/item/clothing/suit/armor/vest/ctf/light/blue
	name = "light blue shielded vest"
	inhand_icon_state = "ert_command"
	team_shield_icon = "shield-old"
	greyscale_colors = COLOR_DARK_CYAN

// GREEN TEAM SUITS

// Regular
/obj/item/clothing/suit/armor/vest/ctf/green
	name = "green shielded vest"
	inhand_icon_state = "ert_green"
	team_shield_icon = "shield-green"
	greyscale_colors = COLOR_LIME

// Light
/obj/item/clothing/suit/armor/vest/ctf/light/green
	name = "light green shielded vest"
	inhand_icon_state = "ert_green"
	team_shield_icon = "shield-green"
	greyscale_colors = COLOR_LIME

// YELLOW TEAM SUITS

// Regular
/obj/item/clothing/suit/armor/vest/ctf/yellow
	name = "yellow shielded vest"
	inhand_icon_state = "ert_engineer"
	team_shield_icon = "shield-yellow"
	greyscale_colors = COLOR_VIVID_YELLOW

// Light
/obj/item/clothing/suit/armor/vest/ctf/light/yellow
	name = "light yellow shielded vest"
	inhand_icon_state = "ert_engineer"
	team_shield_icon = "shield-yellow"
	greyscale_colors = COLOR_VIVID_YELLOW


code:
#define WHITE_TEAM "White"
#define RED_TEAM "Red"
#define BLUE_TEAM "Blue"
#define GREEN_TEAM "Green"
#define YELLOW_TEAM "Yellow"
#define FLAG_RETURN_TIME 200 // 20 seconds
#define INSTAGIB_RESPAWN 50 //5 seconds
#define DEFAULT_RESPAWN 150 //15 seconds

/obj/item/ctf
	name = "banner"
	icon = 'icons/obj/banner.dmi'
	icon_state = "banner"
	inhand_icon_state = "banner"
	lefthand_file = 'icons/mob/inhands/equipment/banners_lefthand.dmi'
	righthand_file = 'icons/mob/inhands/equipment/banners_righthand.dmi'
	desc = "A banner with Nanotrasen's logo on it."
	slowdown = 2
	throw_speed = 0
	throw_range = 1
	force = 200
	armour_penetration = 1000
	resistance_flags = INDESTRUCTIBLE
	anchored = TRUE
	item_flags = SLOWS_WHILE_IN_HAND
	var/team = WHITE_TEAM
	var/reset_cooldown = 0
	var/anyonecanpickup = TRUE
	var/obj/effect/ctf/flag_reset/reset
	var/reset_path = /obj/effect/ctf/flag_reset
	/// Which area we announce updates on the flag to. Should just generally be the area of the arena.
	var/game_area = /area/ctf

/obj/item/ctf/Destroy()
	QDEL_NULL(reset)
	return ..()

/obj/item/ctf/Initialize(mapload)
	. = ..()
	if(!reset)
		reset = new reset_path(get_turf(src))
		reset.flag = src
	RegisterSignal(src, COMSIG_PARENT_PREQDELETED, .proc/reset_flag) //just in case CTF has some map hazards (read: chasms).

/obj/item/ctf/process()
	if(is_ctf_target(loc)) //pickup code calls temporary drops to test things out, we need to make sure the flag doesn't reset from
		return PROCESS_KILL
	if(world.time > reset_cooldown)
		reset_flag()

/obj/item/ctf/proc/reset_flag(capture = FALSE)
	SIGNAL_HANDLER
	STOP_PROCESSING(SSobj, src)

	var/turf/our_turf = get_turf(src.reset)
	if(!our_turf)
		return TRUE
	forceMove(our_turf)
	for(var/mob/M in GLOB.player_list)
		var/area/mob_area = get_area(M)
		if(istype(mob_area, game_area))
			if(!capture)
				to_chat(M, span_userdanger("[src] has been returned to the base!"))
	return TRUE //so if called by a signal, it doesn't delete

//working with attack hand feels like taking my brain and putting it through an industrial pill press so i'm gonna be a bit liberal with the comments
/obj/item/ctf/attack_hand(mob/living/user, list/modifiers)
	//pre normal check item stuff, this is for our special flag checks
	if(!is_ctf_target(user) && !anyonecanpickup)
		to_chat(user, span_warning("Non-players shouldn't be moving the flag!"))
		return
	if(team in user.faction)
		to_chat(user, span_warning("You can't move your own flag!"))
		return
	if(loc == user)
		if(!user.dropItemToGround(src))
			return
	for(var/mob/M in GLOB.player_list)
		var/area/mob_area = get_area(M)
		if(istype(mob_area, game_area))
			to_chat(M, span_userdanger("\The [initial(src.name)] has been taken!"))
	STOP_PROCESSING(SSobj, src)
	anchored = FALSE // Hacky usage that bypasses set_anchored(), because normal checks need this to be FALSE to pass
	. = ..() //this is the actual normal item checks
	if(.) //only apply these flag passives
		anchored = TRUE // Avoid directly assigning to anchored and prefer to use set_anchored() on normal circumstances.
		return
	//passing means the user picked up the flag so we can now apply this
	user.set_anchored(TRUE)
	user.status_flags &= ~CANPUSH

/obj/item/ctf/dropped(mob/user)
	..()
	user.anchored = FALSE // Hacky usage that bypasses set_anchored()
	user.status_flags |= CANPUSH
	reset_cooldown = world.time + 20 SECONDS
	START_PROCESSING(SSobj, src)
	for(var/mob/M in GLOB.player_list)
		var/area/mob_area = get_area(M)
		if(istype(mob_area, game_area))
			to_chat(M, span_userdanger("\The [initial(name)] has been dropped!"))
	anchored = TRUE // Avoid directly assigning to anchored and prefer to use set_anchored() on normal circumstances.

/obj/item/ctf/red
	name = "red flag"
	icon_state = "banner-red"
	inhand_icon_state = "banner-red"
	desc = "A red banner used to play capture the flag."
	team = RED_TEAM
	reset_path = /obj/effect/ctf/flag_reset/red

/obj/item/ctf/blue
	name = "blue flag"
	icon_state = "banner-blue"
	inhand_icon_state = "banner-blue"
	desc = "A blue banner used to play capture the flag."
	team = BLUE_TEAM
	reset_path = /obj/effect/ctf/flag_reset/blue

/obj/item/ctf/green
	name = "green flag"
	icon_state = "banner-green"
	inhand_icon_state = "banner-green"
	desc = "A green banner used to play capture the flag."
	team = GREEN_TEAM
	reset_path = /obj/effect/ctf/flag_reset/green

/obj/item/ctf/yellow
	name = "yellow flag"
	icon_state = "banner-yellow"
	inhand_icon_state = "banner-yellow"
	desc = "A yellow banner used to play capture the flag."
	team = YELLOW_TEAM
	reset_path = /obj/effect/ctf/flag_reset/yellow

/obj/effect/ctf/flag_reset
	name = "banner landmark"
	icon = 'icons/obj/items_and_weapons.dmi'
	icon_state = "banner"
	desc = "This is where a banner with Nanotrasen's logo on it would go."
	layer = LOW_ITEM_LAYER
	var/obj/item/ctf/flag

/obj/effect/ctf/flag_reset/Destroy()
	if(flag)
		flag.reset = null
		flag = null
	return ..()

/obj/effect/ctf/flag_reset/red
	name = "red flag landmark"
	icon_state = "banner-red"
	desc = "This is where a red banner used to play capture the flag \
		would go."

/obj/effect/ctf/flag_reset/blue
	name = "blue flag landmark"
	icon_state = "banner-blue"
	desc = "This is where a blue banner used to play capture the flag \
		would go."

/obj/effect/ctf/flag_reset/green
	name = "green flag landmark"
	icon_state = "banner"
	desc = "This is where a green banner used to play capture the flag \
		would go."

/obj/effect/ctf/flag_reset/yellow
	name = "yellow flag landmark"
	icon_state = "banner"
	desc = "This is where a yellow banner used to play capture the flag \
		would go."

/proc/toggle_id_ctf(user, activated_id, automated = FALSE)
	var/ctf_enabled = FALSE
	var/area/A
	for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
		if(activated_id != CTF.game_id)
			continue
		ctf_enabled = CTF.toggle_ctf()
		A = get_area(CTF)
	for(var/obj/machinery/power/emitter/E in A)
		E.active = ctf_enabled
	if(user)
		message_admins("[key_name_admin(user)] has [ctf_enabled ? "enabled" : "disabled"] CTF!")
	else if(automated)
		message_admins("CTF has finished a round and automatically restarted.")
		notify_ghosts("CTF has automatically restarted after a round finished in [A]!",'sound/effects/ghost2.ogg')
	else
		message_admins("The players have spoken! Voting has enabled CTF!")
	if(!automated)
		notify_ghosts("CTF has been [ctf_enabled? "enabled" : "disabled"] in [A]!",'sound/effects/ghost2.ogg')

/obj/machinery/capture_the_flag
	name = "CTF Controller"
	desc = "Used for running friendly games of capture the flag."
	icon = 'icons/obj/device.dmi'
	icon_state = "syndbeacon"
	resistance_flags = INDESTRUCTIBLE
	var/game_id = "centcom"

	var/victory_rejoin_text = "Teams have been cleared. Click on the machines to vote to begin another round."
	var/team = WHITE_TEAM
	var/team_span = ""
	//Capture the Flag scoring
	var/points = 0
	var/points_to_win = 3
	var/respawn_cooldown = DEFAULT_RESPAWN
	//Capture Point/King of the Hill scoring
	var/control_points = 0
	var/control_points_to_win = 180
	var/list/team_members = list()
	///assoc list: mob = outfit datum (class)
	var/list/spawned_mobs = list()
	var/list/recently_dead_ckeys = list()
	var/ctf_enabled = FALSE
	///assoc list for classes. If there's only one, it'll just equip. Otherwise, it lets you pick which outfit!
	var/list/ctf_gear = list("Rifleman" = /datum/outfit/ctf, "Assaulter" = /datum/outfit/ctf/assault, "Marksman" = /datum/outfit/ctf/marksman)
	var/instagib_gear = /datum/outfit/ctf/instagib
	var/ammo_type = /obj/effect/powerup/ammo/ctf
	// Fast paced gameplay, no real time for burn infections.
	var/player_traits = list(TRAIT_NEVER_WOUNDED)

	var/list/dead_barricades = list()

	var/static/arena_reset = FALSE
	var/static/list/people_who_want_to_play = list()
	var/game_area = /area/ctf

	/// This variable is needed because of ctf shitcode + we need to make sure we're deleting the current ctf landmark that spawned us in and not a new one.
	var/obj/effect/landmark/ctf/ctf_landmark

/obj/machinery/capture_the_flag/Initialize(mapload)
	. = ..()
	SSpoints_of_interest.make_point_of_interest(src)
	ctf_landmark = GLOB.ctf_spawner

/obj/machinery/capture_the_flag/Destroy()
	ctf_landmark = null
	return ..()

/obj/machinery/capture_the_flag/process(delta_time)
	for(var/i in spawned_mobs)
		if(!i)
			spawned_mobs -= i
			continue
		// Anyone in crit, automatically reap
		var/mob/living/living_participant = i
		if(HAS_TRAIT(living_participant, TRAIT_CRITICAL_CONDITION) || living_participant.stat == DEAD || !living_participant.client) // If they're critted, dead or no longer in their body, dust them
			ctf_dust_old(living_participant)
		else
			// The changes that you've been hit with no shield but not
			// instantly critted are low, but have some healing.
			living_participant.adjustBruteLoss(-2.5 * delta_time)
			living_participant.adjustFireLoss(-2.5 * delta_time)

/obj/machinery/capture_the_flag/red
	name = "Red CTF Controller"
	icon_state = "syndbeacon"
	team = RED_TEAM
	team_span = "redteamradio"
	ctf_gear = list("Rifleman" = /datum/outfit/ctf/red, "Assaulter" = /datum/outfit/ctf/assault/red, "Marksman" = /datum/outfit/ctf/marksman/red)
	instagib_gear = /datum/outfit/ctf/red/instagib

/obj/machinery/capture_the_flag/blue
	name = "Blue CTF Controller"
	icon_state = "bluebeacon"
	team = BLUE_TEAM
	team_span = "blueteamradio"
	ctf_gear = list("Rifleman" = /datum/outfit/ctf/blue, "Assaulter" = /datum/outfit/ctf/assault/blue, "Marksman" = /datum/outfit/ctf/marksman/blue)
	instagib_gear = /datum/outfit/ctf/blue/instagib

/obj/machinery/capture_the_flag/green
	name = "Green CTF Controller"
	icon_state = "greenbeacon"
	team = GREEN_TEAM
	team_span = "greenteamradio"
	ctf_gear = list("Rifleman" = /datum/outfit/ctf/green, "Assaulter" = /datum/outfit/ctf/assault/green, "Marksman" = /datum/outfit/ctf/marksman/green)
	instagib_gear = /datum/outfit/ctf/green/instagib

/obj/machinery/capture_the_flag/yellow
	name = "Yellow CTF Controller"
	icon_state = "yellowbeacon"
	team = YELLOW_TEAM
	team_span = "yellowteamradio"
	ctf_gear = list("Rifleman" = /datum/outfit/ctf/yellow, "Assaulter" = /datum/outfit/ctf/assault/yellow, "Marksman" = /datum/outfit/ctf/marksman/yellow)
	instagib_gear = /datum/outfit/ctf/yellow/instagib

//ATTACK GHOST IGNORING PARENT RETURN VALUE
/obj/machinery/capture_the_flag/attack_ghost(mob/user)
	if(ctf_enabled == FALSE)
		if(user.client && user.client.holder)
			var/response = tgui_alert(usr,"Enable this CTF game?", "CTF", list("Yes", "No"))
			if(response == "Yes")
				toggle_id_ctf(user, game_id)
			return

		if(!(GLOB.ghost_role_flags & GHOSTROLE_MINIGAME))
			to_chat(user, span_warning("CTF has been temporarily disabled by admins."))
			return
		for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
			if(CTF.game_id != game_id && CTF.ctf_enabled)
				to_chat(user, span_warning("There is already an ongoing game in the [get_area(CTF)]!"))
				return
		people_who_want_to_play |= user.ckey
		var/num = people_who_want_to_play.len
		var/remaining = CTF_REQUIRED_PLAYERS - num
		if(remaining <= 0)
			people_who_want_to_play.Cut()
			toggle_id_ctf(null, game_id)
		else
			to_chat(user, span_notice("CTF has been requested. [num]/[CTF_REQUIRED_PLAYERS] have readied up."))

		return

	if(!SSticker.HasRoundStarted())
		return
	if(user.ckey in team_members)
		if(user.ckey in recently_dead_ckeys)
			to_chat(user, span_warning("It must be more than [DisplayTimeText(respawn_cooldown)] from your last death to respawn!"))
			return
		var/client/new_team_member = user.client
		if(user.mind && user.mind.current)
			ctf_dust_old(user.mind.current)
		spawn_team_member(new_team_member)
		return

	for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
		if(CTF.game_id != game_id || CTF == src || CTF.ctf_enabled == FALSE)
			continue
		if(user.ckey in CTF.team_members)
			to_chat(user, span_warning("No switching teams while the round is going!"))
			return
		if(CTF.team_members.len < src.team_members.len)
			to_chat(user, span_warning("[src.team] has more team members than [CTF.team]! Try joining [CTF.team] team to even things up."))
			return

	var/client/new_team_member = user.client
	team_members |= new_team_member.ckey
	to_chat(user, "You are now a member of [src.team]. Get the enemy flag and bring it back to your team's controller!")
	spawn_team_member(new_team_member)

//does not add to recently dead, because it dusts and that triggers ctf_qdelled_player
/obj/machinery/capture_the_flag/proc/ctf_dust_old(mob/living/body)
	if(isliving(body) && (team in body.faction))
		var/turf/T = get_turf(body)
		if(ammo_type)
			new ammo_type(T)
		body.dust()

/obj/machinery/capture_the_flag/proc/ctf_qdelled_player(mob/living/body)
	SIGNAL_HANDLER

	recently_dead_ckeys += body.ckey
	spawned_mobs -= body
	addtimer(CALLBACK(src, .proc/clear_cooldown, body.ckey), respawn_cooldown, TIMER_UNIQUE)

/obj/machinery/capture_the_flag/proc/clear_cooldown(ckey)
	recently_dead_ckeys -= ckey

/obj/machinery/capture_the_flag/proc/spawn_team_member(client/new_team_member)
	var/datum/outfit/chosen_class

	if(ctf_gear.len == 1) //no choices to make
		for(var/key in ctf_gear)
			chosen_class = ctf_gear[key]

	else //there's a choice to make, present a radial menu
		var/list/display_classes = list()

		for(var/key in ctf_gear)
			var/datum/outfit/ctf/class = ctf_gear[key]
			var/datum/radial_menu_choice/option = new
			option.image  = image(icon = initial(class.icon), icon_state = initial(class.icon_state))
			option.info = "[initial(class.class_description)]"
			display_classes[key] = option

		sort_list(display_classes)
		var/choice = show_radial_menu(new_team_member.mob, src, display_classes, radius = 38)
		if(!choice || !(GLOB.ghost_role_flags & GHOSTROLE_MINIGAME) || (new_team_member.ckey in recently_dead_ckeys) || !isobserver(new_team_member.mob) || src.ctf_enabled == FALSE || !(new_team_member.ckey in src.team_members))
			return //picked nothing, admin disabled it, cheating to respawn faster, cheating to respawn... while in game?,
				   //there isn't a game going on any more, you are no longer a member of this team (perhaps a new match already started?)
		chosen_class = ctf_gear[choice]

	var/mob/living/carbon/human/M = new /mob/living/carbon/human(get_turf(src))
	new_team_member.prefs.safe_transfer_prefs_to(M, is_antag = TRUE)
	M.set_species(/datum/species/synth)
	M.key = new_team_member.key
	M.faction += team
	M.equipOutfit(chosen_class)
	RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/ctf_qdelled_player) //just in case CTF has some map hazards (read: chasms). bit shorter than dust
	for(var/trait in player_traits)
		ADD_TRAIT(M, trait, CAPTURE_THE_FLAG_TRAIT)
	spawned_mobs[M] = chosen_class
	return M //used in medisim.dm

/obj/machinery/capture_the_flag/Topic(href, href_list)
	if(href_list["join"])
		var/mob/dead/observer/ghost = usr
		if(istype(ghost))
			attack_ghost(ghost)

/obj/machinery/capture_the_flag/attackby(obj/item/I, mob/user, params)
	if(istype(I, /obj/item/ctf))
		var/obj/item/ctf/flag = I
		if(flag.team != src.team)
			points++
			flag.reset_flag(capture = TRUE)
			for(var/mob/ctf_player in GLOB.player_list)
				var/area/mob_area = get_area(ctf_player)
				if(istype(mob_area, game_area))
					to_chat(ctf_player, "[user.real_name] has captured \the [flag], scoring a point for [team] team! They now have [points]/[points_to_win] points!")
			if(points >= points_to_win)
				victory()

/obj/machinery/capture_the_flag/proc/victory()
	for(var/mob/_competitor in GLOB.mob_living_list)
		var/mob/living/competitor = _competitor
		var/area/mob_area = get_area(competitor)
		if(istype(mob_area, game_area))
			to_chat(competitor, "[team] team wins!")
			to_chat(competitor, victory_rejoin_text)
			for(var/obj/item/ctf/W in competitor)
				competitor.dropItemToGround(W)
			competitor.dust()
	for(var/obj/machinery/control_point/control in GLOB.machines)
		control.icon_state = "dominator"
		control.controlling = null
	for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
		if(CTF.game_id != game_id)
			continue
		if(CTF.ctf_enabled == TRUE)
			CTF.points = 0
			CTF.control_points = 0
			CTF.ctf_enabled = FALSE
			CTF.team_members = list()
			CTF.arena_reset = FALSE

/obj/machinery/capture_the_flag/proc/toggle_ctf()
	if(!ctf_enabled)
		start_ctf()
		. = TRUE
	else
		stop_ctf()
		. = FALSE

/obj/machinery/capture_the_flag/proc/start_ctf()
	ctf_enabled = TRUE
	for(var/d in dead_barricades)
		var/obj/effect/ctf/dead_barricade/D = d
		D.respawn()

	dead_barricades.Cut()

	notify_ghosts("[name] has been activated!", source = src, action=NOTIFY_ORBIT, header = "CTF has been activated")

/obj/machinery/capture_the_flag/proc/reset_the_arena()
	if(!ctf_landmark)
		return

	if(ctf_landmark == GLOB.ctf_spawner)
		new /obj/effect/landmark/ctf(get_turf(GLOB.ctf_spawner))

/obj/machinery/capture_the_flag/proc/stop_ctf()
	ctf_enabled = FALSE
	arena_reset = FALSE
	var/area/A = get_area(src)
	for(var/_competitor in GLOB.mob_living_list)
		var/mob/living/competitor = _competitor
		if((get_area(A) == A) && (competitor.ckey in team_members))
			competitor.dust()
	team_members.Cut()
	spawned_mobs.Cut()
	recently_dead_ckeys.Cut()
	reset_the_arena()

/obj/machinery/capture_the_flag/proc/instagib_mode()
	for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
		if(CTF.game_id != game_id)
			continue
		if(CTF.ctf_enabled == TRUE)
			CTF.ctf_gear = CTF.instagib_gear
			CTF.respawn_cooldown = INSTAGIB_RESPAWN

/obj/machinery/capture_the_flag/proc/normal_mode()
	for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
		if(CTF.game_id != game_id)
			continue
		if(CTF.ctf_enabled == TRUE)
			CTF.ctf_gear = initial(ctf_gear)
			CTF.respawn_cooldown = DEFAULT_RESPAWN

/obj/structure/trap/ctf
	name = "Spawn protection"
	desc = "Stay outta the enemy spawn!"
	icon_state = "trap"
	resistance_flags = INDESTRUCTIBLE
	var/team = WHITE_TEAM
	time_between_triggers = 1
	anchored = TRUE
	alpha = 255

/obj/structure/trap/ctf/examine(mob/user)
	return

/obj/structure/trap/ctf/trap_effect(mob/living/L)
	if(!is_ctf_target(L))
		return
	if(!(src.team in L.faction))
		to_chat(L, span_danger("Stay out of the enemy spawn!"))
		L.death()

/obj/structure/trap/ctf/red
	team = RED_TEAM
	icon_state = "trap-fire"

/obj/structure/trap/ctf/blue
	team = BLUE_TEAM
	icon_state = "trap-frost"

/obj/structure/trap/ctf/green
	team = GREEN_TEAM
	icon_state = "trap-earth"

/obj/structure/trap/ctf/yellow
	team = YELLOW_TEAM
	icon_state = "trap-shock"

/obj/structure/barricade/security/ctf
	name = "barrier"
	desc = "A barrier. Provides cover in fire fights."
	deploy_time = 0
	deploy_message = 0

/obj/structure/barricade/security/ctf/make_debris()
	new /obj/effect/ctf/dead_barricade(get_turf(src))

/obj/structure/table/reinforced/ctf
	resistance_flags = INDESTRUCTIBLE
	flags_1 = NODECONSTRUCT_1

/obj/effect/ctf
	density = FALSE
	anchored = TRUE
	invisibility = INVISIBILITY_OBSERVER
	alpha = 100
	resistance_flags = INDESTRUCTIBLE

/obj/effect/ctf/dead_barricade
	name = "dead barrier"
	desc = "It provided cover in fire fights. And now it's gone."
	icon = 'icons/obj/objects.dmi'
	icon_state = "barrier0"
	var/game_id = "centcom"

/obj/effect/ctf/dead_barricade/Initialize(mapload)
	. = ..()
	for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
		if(CTF.game_id != game_id)
			continue
		CTF.dead_barricades += src

/obj/effect/ctf/dead_barricade/Destroy()
	for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
		if(CTF.game_id != game_id)
			continue
		CTF.dead_barricades -= src
	return ..()

/obj/effect/ctf/dead_barricade/proc/respawn()
	if(!QDELETED(src))
		new /obj/structure/barricade/security/ctf(get_turf(src))
		qdel(src)

//Control Point

/obj/machinery/control_point
	name = "control point"
	desc = "You should capture this."
	icon = 'icons/obj/machines/dominator.dmi'
	icon_state = "dominator"
	resistance_flags = INDESTRUCTIBLE
	var/obj/machinery/capture_the_flag/controlling
	var/team = "none"
	var/point_rate = 0.5
	var/game_area = /area/ctf

/obj/machinery/control_point/process(delta_time)
	if(controlling)
		controlling.control_points += point_rate * delta_time
		if(controlling.control_points >= controlling.control_points_to_win)
			controlling.victory()

/obj/machinery/control_point/attackby(mob/user, params)
	capture(user)

/obj/machinery/control_point/attack_hand(mob/user, list/modifiers)
	. = ..()
	if(.)
		return
	capture(user)

/obj/machinery/control_point/proc/capture(mob/user)
	if(do_after(user, 30, target = src))
		for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
			if(CTF.ctf_enabled && (user.ckey in CTF.team_members))
				controlling = CTF
				icon_state = "dominator-[CTF.team]"
				for(var/mob/M in GLOB.player_list)
					var/area/mob_area = get_area(M)
					if(istype(mob_area, game_area))
						to_chat(M, span_userdanger("[user.real_name] has captured \the [src], claiming it for [CTF.team]! Go take it back!"))
				break

/proc/is_ctf_target(atom/target)
	. = FALSE
	if(istype(target, /obj/structure/barricade/security/ctf))
		. = TRUE
	if(ishuman(target))
		var/mob/living/carbon/human/H = target
		for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
			if(H in CTF.spawned_mobs)
				. = TRUE
				break

#undef WHITE_TEAM
#undef RED_TEAM
#undef BLUE_TEAM
#undef GREEN_TEAM
#undef YELLOW_TEAM
#undef FLAG_RETURN_TIME
#undef INSTAGIB_RESPAWN
#undef DEFAULT_RESPAWN


code:
GLOBAL_DATUM(ctf_spawner, /obj/effect/landmark/ctf)

/obj/effect/landmark/ctf
	name = "CTF Map Spawner"
	var/list/map_bounds

/obj/effect/landmark/ctf/Initialize(mapload)
	. = ..()
	if(GLOB.ctf_spawner)
		qdel(GLOB.ctf_spawner)
	GLOB.ctf_spawner = src
	INVOKE_ASYNC(src, .proc/load_map)

/obj/effect/landmark/ctf/Destroy()
	if(map_bounds)
		for(var/turf/ctf_turf in block(
			locate(
				map_bounds[MAP_MINX],
				map_bounds[MAP_MINY],
				map_bounds[MAP_MINZ],
			),
			locate(
				map_bounds[MAP_MAXX],
				map_bounds[MAP_MAXY],
				map_bounds[MAP_MAXZ],
			)
		))
			ctf_turf.empty()
	GLOB.ctf_spawner = null
	return ..()

/obj/effect/landmark/ctf/proc/load_map()

	var/list/map_options = subtypesof(/datum/map_template/ctf)
	var/turf/spawn_area = get_turf(src)
	var/datum/map_template/ctf/current_map

	current_map = pick(map_options)
	current_map = new current_map()

	if(!spawn_area)
		CRASH("No spawn area detected for CTF!")
	else if(!current_map)
		CRASH("No map prepared")
	map_bounds = current_map.load(spawn_area, TRUE)
	if(!map_bounds)
		CRASH("Loading CTF map failed!")

/datum/map_template/ctf
	var/description = ""

/datum/map_template/ctf/classic
	name = "Classic"
	description = "The original CTF map."
	mappath = "_maps/map_files/CTF/classic.dmm"

/datum/map_template/ctf/four_side
	name = "Four Side"
	description = "A CTF map created to demonstrate 4 team CTF, features a single centred flag rather than one per team."
	mappath = "_maps/map_files/CTF/fourSide.dmm"

/datum/map_template/ctf/downtown
	name = "Downtown"
	description = "A CTF map that takes place in a terrestrial city."
	mappath = "_maps/map_files/CTF/downtown.dmm"

/datum/map_template/ctf/limbo
	name = "Limbo"
	description = "A KOTH map that takes place in a wizard den with looping hallways"
	mappath = "_maps/map_files/CTF/limbo.dmm"

/datum/map_template/ctf/cruiser
	name = "Crusier"
	description = "A CTF map that takes place across multiple space ships, one carring a powerful device that can accelerate those who obtain it"
	mappath = "_maps/map_files/CTF/cruiser.dmm"


code:
GLOBAL_DATUM_INIT(ctf_panel, /datum/ctf_panel, new())

/datum/ctf_panel

/datum/ctf_panel/ui_state(mob/user)
	return GLOB.observer_state

/datum/ctf_panel/ui_interact(mob/user, datum/tgui/ui)
	ui = SStgui.try_update_ui(user, src, ui)
	if(!ui)
		ui = new(user, src, "CTFPanel")
		ui.open()

/datum/ctf_panel/ui_data(mob/user)
	var/list/data = list()
	data["teams"] = list()
	data["enabled"] = ""
	for(var/obj/machinery/capture_the_flag/team in GLOB.machines)
		var/list/this = list()
		this["name"] = team
		this["color"] = team.team
		this["score"] = team.points + team.control_points
		this["team_size"] = team.team_members.len
		this["refs"] += "[REF(team)]"
		data["teams"] += list(this)
		if(!data["enabled"])
			if(team.ctf_enabled)
				data["enabled"] = "CTF is currently running!"
			else
				data["enabled"] = "CTF needs [CTF_REQUIRED_PLAYERS] players to start, currently [team.people_who_want_to_play.len]/[CTF_REQUIRED_PLAYERS] have signed up!"
	return data

/datum/ctf_panel/ui_act(action, params, datum/tgui/ui)
	.= ..()
	if(.)
		return
	var/mob/user = ui.user

	switch(action)
		if("jump")
			var/obj/machinery/capture_the_flag/ctf_spawner = locate(params["refs"])
			if(istype(ctf_spawner))
				user.forceMove(get_turf(ctf_spawner))
				return TRUE
		if("join")
			var/obj/machinery/capture_the_flag/ctf_spawner = locate(params["refs"])
			if(istype(ctf_spawner))
				if(ctf_spawner.ctf_enabled)
					user.forceMove(get_turf(ctf_spawner))
				ctf_spawner.attack_ghost(user)
				return TRUE


code:
/datum/outfit/ctf/medisim
	name = "Redfield Castle Knight"
	icon_state = "medisim_knight"

	uniform = /obj/item/clothing/under/color/red
	shoes = /obj/item/clothing/shoes/plate/red
	suit = /obj/item/clothing/suit/armor/riot/knight/red
	gloves = /obj/item/clothing/gloves/plate/red
	head = /obj/item/clothing/head/helmet/knight/red
	r_hand = /obj/item/claymore

	ears = null
	id = null
	belt = null
	l_pocket = null
	r_pocket = null

	has_radio = FALSE
	has_card = FALSE

	nodrop_slots = list(ITEM_SLOT_OCLOTHING, ITEM_SLOT_GLOVES, ITEM_SLOT_FEET, ITEM_SLOT_ICLOTHING, ITEM_SLOT_EARS, ITEM_SLOT_BELT, ITEM_SLOT_HEAD)

	class_description = "Melee class. Armed with a claymore."

/datum/outfit/ctf/medisim/archer
	name = "Redfield Castle Archer"
	icon_state = "medisim_archer"

	belt = /obj/item/storage/bag/quiver
	suit = /obj/item/clothing/suit/armor/vest/cuirass
	r_hand = /obj/item/gun/ballistic/bow

	class_description = "Ranged class. Armed with a bow and arrows."

/datum/outfit/ctf/medisim/blue
	name = "Bluesworth Hold Knight"

	uniform = /obj/item/clothing/under/color/blue
	shoes = /obj/item/clothing/shoes/plate/blue
	suit = /obj/item/clothing/suit/armor/riot/knight/blue
	gloves = /obj/item/clothing/gloves/plate/blue
	head = /obj/item/clothing/head/helmet/knight/blue

/datum/outfit/ctf/medisim/archer/blue
	name = "Bluesworth Hold Archer"

	uniform = /obj/item/clothing/under/color/blue
	shoes = /obj/item/clothing/shoes/plate/blue
	gloves = /obj/item/clothing/gloves/plate/blue
	head = /obj/item/clothing/head/helmet/knight/blue


code:
///These are for the medisim shuttle

#define REDFIELD_TEAM "Red"
#define BLUESWORTH_TEAM "Blue"

/obj/machinery/capture_the_flag/medisim
	game_id = "medieval"
	game_area = /area/shuttle/escape/simulation
	ammo_type = null //no guns, no need
	victory_rejoin_text = "Teams have been cleared. The next game is starting automatically. Rejoin a team if you wish!"
	player_traits = list()

/obj/machinery/capture_the_flag/medisim/Initialize(mapload)
	. = ..()
	start_ctf() //both machines initialize, so both will call start_ctf instead of toggle_id_ctf calling it for both, twice.

/obj/machinery/capture_the_flag/medisim/victory()
	. = ..()
	toggle_id_ctf(null, game_id, automated = TRUE)//only one machine runs the victory proc, start_ctf proc would break the other machine

// We don't clean up for the medisim.
/obj/machinery/capture_the_flag/medisim/reset_the_arena()
	return

/obj/machinery/capture_the_flag/medisim/spawn_team_member(client/new_team_member)
	. = ..()
	if(!.)
		return
	var/mob/living/carbon/human/human_knight = .
	randomize_human(human_knight)
	human_knight.dna.update_dna_identity()
	human_knight.dna.add_mutation(MEDIEVAL, MUT_OTHER)
	var/oldname = human_knight.name
	var/title = "error"
	switch (human_knight.gender)
		if (MALE)
			title = pick(list("Sir", "Lord"))
		if (FEMALE)
			title = pick(list("Dame", "Lady"))
		else
			title = "Noble"
	human_knight.real_name = "[title] [oldname]"
	human_knight.name = human_knight.real_name

/obj/machinery/capture_the_flag/medisim/red
	name = "\improper Redfield Data Realizer"
	icon_state = "syndbeacon"
	team = REDFIELD_TEAM
	team_span = "redteamradio"
	ctf_gear = list("knight" = /datum/outfit/ctf/medisim, "archer" = /datum/outfit/ctf/medisim/archer)

/obj/machinery/capture_the_flag/medisim/blue
	name = "\improper Bluesworth Data Realizer"
	icon_state = "bluebeacon"
	team = BLUESWORTH_TEAM
	team_span = "blueteamradio"
	ctf_gear = list("knight" = /datum/outfit/ctf/medisim/blue, "archer" = /datum/outfit/ctf/medisim/archer/blue)

/obj/item/ctf/red/medisim
	name = "\improper Redfield Castle Fair Maiden"
	desc = "Protect your maiden, and capture theirs!"
	icon = 'icons/obj/plushes.dmi'
	icon_state = "plushie_nuke"
	force = 0
	game_area = /area/shuttle/escape
	movement_type = FLOATING //there are chasms, and resetting when they fall in is really lame so lets minimize that

/obj/item/ctf/blue/medisim
	name = "\improper Bluesworth Hold Fair Maiden"
	desc = "Protect your maiden, and capture theirs!"
	icon = 'icons/obj/plushes.dmi'
	icon_state = "plushie_slime"
	force = 0
	game_area = /area/shuttle/escape
	movement_type = FLOATING //there are chasms, and resetting when they fall in is really lame so lets minimize that

#undef REDFIELD_TEAM
#undef BLUESWORTH_TEAM


code:
/datum/blackmarket_item
	/// Name for the item entry used in the uplink.
	var/name
	/// Description for the item entry used in the uplink.
	var/desc
	/// The category this item belongs to, should be already declared in the market that this item is accessible in.
	var/category
	/// "/datum/blackmarket_market"s that this item should be in, used by SSblackmarket on init.
	var/list/markets = list(/datum/blackmarket_market/blackmarket)

	/// Price for the item, if not set creates a price according to the *_min and *_max vars.
	var/price
	/// How many of this type of item is available, if not set creates a price according to the *_min and *_max vars.
	var/stock

	/// Path to or the item itself what this entry is for, this should be set even if you override spawn_item to spawn your item.
	var/item

	/// Minimum price for the item if generated randomly.
	var/price_min = 0
	/// Maximum price for the item if generated randomly.
	var/price_max = 0
	/// Minimum amount that there should be of this item in the market if generated randomly. This defaults to 1 as most items will have it as 1.
	var/stock_min = 1
	/// Maximum amount that there should be of this item in the market if generated randomly.
	var/stock_max = 0
	/// Probability for this item to be available. Used by SSblackmarket on init.
	var/availability_prob = 0

/datum/blackmarket_item/New()
	if(isnull(price))
		price = rand(price_min, price_max)
	if(isnull(stock))
		stock = rand(stock_min, stock_max)

/// Used for spawning the wanted item, override if you need to do something special with the item.
/datum/blackmarket_item/proc/spawn_item(loc)
	return new item(loc)

/// Buys the item and makes SSblackmarket handle it.
/datum/blackmarket_item/proc/buy(obj/item/blackmarket_uplink/uplink, mob/buyer, shipping_method)
	// Sanity
	if(!istype(uplink) || !istype(buyer))
		return FALSE

	// This shouldn't be able to happen unless there was some manipulation or admin fuckery.
	if(!item || stock <= 0)
		return FALSE

	// Alright, the item has been purchased.
	var/datum/blackmarket_purchase/purchase = new(src, uplink, shipping_method)

	// SSblackmarket takes care of the shipping.
	if(SSblackmarket.queue_item(purchase))
		stock--
		log_game("[key_name(buyer)] has succesfully purchased [name] using [shipping_method] for shipping.")
		return TRUE
	return FALSE

// This exists because it is easier to keep track of all the vars this way.
/datum/blackmarket_purchase
	/// The entry being purchased.
	var/datum/blackmarket_item/entry
	/// Instance of the item being sent.
	var/item
	/// The uplink where this purchase was done from.
	var/obj/item/blackmarket_uplink/uplink
	/// Shipping method used to buy this item.
	var/method

/datum/blackmarket_purchase/New(_entry, _uplink, _method)
	entry = _entry
	if(!ispath(entry.item))
		item = entry.item
	uplink = _uplink
	method = _method


code:
/datum/blackmarket_item/clothing
	category = "Clothing"

/datum/blackmarket_item/clothing/ninja_mask
	name = "Space Ninja Mask"
	desc = "Apart from being acid, lava, fireproof and being hard to take off someone it does nothing special on it's own."
	item = /obj/item/clothing/mask/gas/space_ninja

	price_min = 200
	price_max = 500
	stock_max = 3
	availability_prob = 40

/datum/blackmarket_item/clothing/durathread_vest
	name = "Durathread Vest"
	desc = "Don't let them tell you this stuff is \"Like asbestos\" or \"Pulled from the market for safety concerns\". It could be the difference between a robusting and a retaliation."
	item = /obj/item/clothing/suit/armor/vest/durathread

	price_min = 200
	price_max = 400
	stock_max = 4
	availability_prob = 50

/datum/blackmarket_item/clothing/durathread_helmet
	name = "Durathread Helmet"
	desc = "Customers ask why it's called a helmet when it's just made from armoured fabric and I always say the same thing: No refunds."
	item = /obj/item/clothing/head/helmet/durathread

	price_min = 100
	price_max = 200
	stock_max = 4
	availability_prob = 50

/datum/blackmarket_item/clothing/full_spacesuit_set
	name = "\improper Nanotrasen Branded Spacesuit Box"
	desc = "A few boxes of \"Old Style\" space suits fell off the back of a space truck."
	item = /obj/item/storage/box

	price_min = 1500
	price_max = 4000
	stock_max = 3
	availability_prob = 30

/datum/blackmarket_item/clothing/full_spacesuit_set/spawn_item(loc)
	var/obj/item/storage/box/B = ..()
	B.name = "Spacesuit Box"
	B.desc = "It has an NT logo on it."
	new /obj/item/clothing/suit/space(B)
	new /obj/item/clothing/head/helmet/space(B)
	return B

/datum/blackmarket_item/clothing/chameleon_hat
	name = "Chameleon Hat"
	desc = "Pick any hat you want with this Handy device. Not Quality Tested."
	item = /obj/item/clothing/head/chameleon/broken

	price_min = 100
	price_max = 200
	stock_max = 2
	availability_prob = 70

/datum/blackmarket_item/clothing/combatmedic_suit
	name = "Combat Medic hardsuit"
	desc = "A discarded combat medic hardsuit, found in the ruins of a carpet bombed xeno hive. Definately used, but as sturdy as an anchor."
	item = /obj/item/clothing/suit/space/hardsuit/combatmedic

	price_min = 5500
	price_max = 7000
	stock_max = 1
	availability_prob = 10

/datum/blackmarket_item/clothing/rocket_boots
	name = "Rocket Boots"
	desc = "We found a pair of jump boots and overclocked the hell out of them. No liability for grevious harm to or with a body."
	item = /obj/item/clothing/shoes/bhop/rocket

	price_min = 1000
	price_max = 3000
	stock_max = 1
	availability_prob = 40


code:
/datum/blackmarket_item/consumable
	category = "Consumables"

/datum/blackmarket_item/consumable/clown_tears
	name = "Bowl of Clown's Tears"
	desc = "Guaranteed fresh from Weepy Boggins Tragic Kitchen"
	item = /obj/item/food/soup/clownstears
	stock = 1

	price_min = 520
	price_max = 600
	availability_prob = 10

/datum/blackmarket_item/consumable/donk_pocket_box
	name = "Box of Donk Pockets"
	desc = "A well packaged box containing the favourite snack of every spacefarer."
	item = /obj/item/storage/box/donkpockets

	stock_min = 2
	stock_max = 5
	price_min = 325
	price_max = 400
	availability_prob = 80

/datum/blackmarket_item/consumable/suspicious_pills
	name = "Bottle of Suspicious Pills"
	desc = "A random cocktail of luxury drugs that are sure to put a smile on your face!"
	item = /obj/item/storage/pill_bottle

	stock_min = 2
	stock_max = 3
	price_min = 400
	price_max = 700
	availability_prob = 50

/datum/blackmarket_item/consumable/suspicious_pills/spawn_item(loc)
	var/pillbottle = pick(list(/obj/item/storage/pill_bottle/zoom,
				/obj/item/storage/pill_bottle/happy,
				/obj/item/storage/pill_bottle/lsd,
				/obj/item/storage/pill_bottle/aranesp,
				/obj/item/storage/pill_bottle/stimulant))
	return new pillbottle(loc)

/datum/blackmarket_item/consumable/floor_pill
	name = "Strange Pill"
	desc = "The Russian Roulette of the Maintenance Tunnels."
	item = /obj/item/reagent_containers/pill/maintenance

	stock_min = 5
	stock_max = 35
	price_min = 10
	price_max = 60
	availability_prob = 50

/datum/blackmarket_item/consumable/pumpup
	name = "Maintenance Pump-Up"
	desc = "Resist any Baton stun with this handy device!"
	item = /obj/item/reagent_containers/hypospray/medipen/pumpup

	stock_max = 3
	price_min = 50
	price_max = 150
	availability_prob = 90


code:
/datum/blackmarket_item/misc
	category = "Miscellaneous"

/datum/blackmarket_item/misc/Clear_PDA
	name = "Clear PDA"
	desc = "Show off your style with this limited edition clear PDA!."
	item = /obj/item/pda/clear

	price_min = 250
	price_max = 600
	stock_max = 2
	availability_prob = 50

/datum/blackmarket_item/misc/jade_Lantern
	name = "Jade Lantern"
	desc = "Found in a box labeled 'Danger: Radioactive'. Probably safe."
	item = /obj/item/flashlight/lantern/jade

	price_min = 150
	price_max = 500
	stock_max = 2
	availability_prob = 45

/datum/blackmarket_item/misc/cap_gun
	name = "Cap Gun"
	desc = "Prank your friends with this harmless gun! Harmlessness guranteed."
	item = /obj/item/toy/gun

	price_min = 50
	price_max = 200
	stock_max = 6
	availability_prob = 80

/datum/blackmarket_item/misc/shoulder_holster
	name = "Shoulder holster"
	desc = "Yeehaw, hardboiled friends! This holster is the first step in your dream of becoming a detective and being allowed to shoot real guns!"
	item = /obj/item/storage/belt/holster

	price_min = 400
	price_max = 800
	stock_max = 8
	availability_prob = 60

/datum/blackmarket_item/misc/holywater
	name = "Flask of holy water"
	desc = "Father Lootius' own brand of ready-made holy water."
	item = /obj/item/reagent_containers/food/drinks/bottle/holywater

	price_min = 400
	price_max = 600
	stock_max = 3
	availability_prob = 40

/datum/blackmarket_item/misc/holywater/spawn_item(loc)
	if (prob(6.66))
		return new /obj/item/reagent_containers/glass/beaker/unholywater(loc)
	return ..()

/datum/blackmarket_item/misc/strange_seed
	name = "Strange Seeds"
	desc = "An Exotic Variety of seed that can contain anything from glow to acid."
	item = /obj/item/seeds/random

	price_min = 320
	price_max = 360
	stock_min = 2
	stock_max = 5
	availability_prob = 50

/datum/blackmarket_item/misc/smugglers_satchel
	name = "Smuggler's Satchel"
	desc = "This easily hidden satchel can become a versatile tool to anybody with the desire to keep certain items out of sight and out of mind."
	item = /obj/item/storage/backpack/satchel/flat/empty

	price_min = 750
	price_max = 1000
	stock_max = 2
	availability_prob = 30


code:
/datum/blackmarket_item/tool
	category = "Tools"

/datum/blackmarket_item/tool/caravan_wrench
	name = "Experimental Wrench"
	desc = "The extra fast and handy wrench you always wanted!"
	item = /obj/item/wrench/caravan
	stock = 1

	price_min = 400
	price_max = 800
	availability_prob = 20

/datum/blackmarket_item/tool/caravan_wirecutters
	name = "Experimental Wirecutters"
	desc = "The extra fast and handy wirecutters you always wanted!"
	item = /obj/item/wirecutters/caravan
	stock = 1

	price_min = 400
	price_max = 800
	availability_prob = 20

/datum/blackmarket_item/tool/caravan_screwdriver
	name = "Experimental Screwdriver"
	desc = "The extra fast and handy screwdriver you always wanted!"
	item = /obj/item/screwdriver/caravan
	stock = 1

	price_min = 400
	price_max = 800
	availability_prob = 20

/datum/blackmarket_item/tool/caravan_crowbar
	name = "Experimental Crowbar"
	desc = "The extra fast and handy crowbar you always wanted!"
	item = /obj/item/crowbar/red/caravan
	stock = 1

	price_min = 400
	price_max = 800
	availability_prob = 20

/datum/blackmarket_item/tool/binoculars
	name = "Binoculars"
	desc = "Increase your sight by 150% with this handy Tool!"
	item = /obj/item/binoculars
	stock = 1

	price_min = 400
	price_max = 960
	availability_prob = 30

/datum/blackmarket_item/tool/riot_shield
	name = "Riot Shield"
	desc = "Protect yourself from an unexpected Riot at your local Police department!"
	item = /obj/item/shield/riot

	price_min = 450
	price_max = 650
	stock_max = 2
	availability_prob = 50

/datum/blackmarket_item/tool/thermite_bottle
	name = "Thermite Bottle"
	desc = "30u of Thermite to assist in creating a quick access point or get away!"
	item = /obj/item/reagent_containers/glass/bottle/thermite

	price_min = 500
	price_max = 1500
	stock_max = 3
	availability_prob = 30

/datum/blackmarket_item/tool/science_goggles
	name = "Science Goggles"
	desc = "These glasses scan the contents of containers and projects their contents to the user in an easy to read format."
	item = /obj/item/clothing/glasses/science

	price_min = 150
	price_max = 200
	stock_max = 3
	availability_prob = 50

/**
 * # Fake N-spect scanner black market entry
 */
/datum/blackmarket_item/tool/fake_scanner
	name = "Clowny N-spect scanner"
	desc = "This UPGRADED N-spect scanner can play FIVE HIGH-QUALITY SOUNDS (fork required for sound adjustment not included) and print reports \
	LIGHTNING FAST (screwdriver necessary to activate maximum speed not included). We make no claims as to the usefulness of the reports printed by this. \
	Any and all implied warranties are void if the device is touched, moved, kicked, thrown or modified with bananium sheets. Batteries included. \
	Crowbar necessary to change batteries and adjust settings not included."
	item = /obj/item/inspector/clown

	price_min = 230
	price_max = 323
	stock_max = 2
	availability_prob = 50


code:
/datum/blackmarket_item/weapon
	category = "Weapons"

/datum/blackmarket_item/weapon/bear_trap
	name = "Bear Trap"
	desc = "Get the janitor back at his own game with this affordable prank kit."
	item = /obj/item/restraints/legcuffs/beartrap

	price_min = 300
	price_max = 550
	stock_max = 3
	availability_prob = 40

/datum/blackmarket_item/weapon/shotgun_dart
	name = "Shotgun Dart"
	desc = "These handy darts can be filled up with any chemical and be shot with a shotgun! \
	Prank your friends by shooting them with laughter! \
	Not recommended for comercial use."
	item = /obj/item/ammo_casing/shotgun/dart

	price_min = 10
	price_max = 50
	stock_min = 10
	stock_max = 60
	availability_prob = 40

/datum/blackmarket_item/weapon/bone_spear
	name = "Bone Spear"
	desc = "Authentic tribal spear, made from real bones! A steal at any price, especially if you're a caveman."
	item = /obj/item/spear/bonespear

	price_min = 200
	price_max = 300
	stock_max = 3
	availability_prob = 60

/datum/blackmarket_item/weapon/chainsaw
	name = "Chainsaw"
	desc = "A lumberjack's best friend, perfect for cutting trees or limbs efficiently."
	item = /obj/item/chainsaw

	price_min = 350
	price_max = 600
	stock_max = 1
	availability_prob = 35

/datum/blackmarket_item/weapon/switchblade
	name = "Switchblade"
	desc = "Tunnel Snakes rule!"
	item = /obj/item/switchblade

	price_min = 250
	price_max = 350
	stock_max = 3
	availability_prob = 45

/datum/blackmarket_item/weapon/emp_grenade
	name = "EMP Grenade"
	desc = "Use this grenade for SHOCKING results!"
	item = /obj/item/grenade/empgrenade

	price_min = 100
	price_max = 400
	stock_max = 2
	availability_prob = 50


code:
/datum/blackmarket_market
	/// Name for the market.
	var/name = "huh?"

	/// Available shipping methods and prices, just leave the shipping method out that you don't want to have.
	var/list/shipping

	// Automatic vars, do not touch these.
	/// Items available from this market, populated by SSblackmarket on initialization.
	var/list/available_items = list()
	/// Item categories available from this market, only items which are in these categories can be gotten from this market.
	var/list/categories = list()

/// Adds item to the available items and add it's category if it is not in categories yet.
/datum/blackmarket_market/proc/add_item(datum/blackmarket_item/item)
	if(!prob(initial(item.availability_prob)))
		return FALSE

	if(ispath(item))
		item = new item()

	if(!(item.category in categories))
		categories += item.category
		available_items[item.category] = list()

	available_items[item.category] += item
	return TRUE

/// Handles buying the item, this is mainly for future use and moving the code away from the uplink.
/datum/blackmarket_market/proc/purchase(item, category, method, obj/item/blackmarket_uplink/uplink, user)
	if(!istype(uplink) || !(method in shipping))
		return FALSE

	for(var/datum/blackmarket_item/I in available_items[category])
		if(I.type != item)
			continue
		var/price = I.price + shipping[method]
		// I can't get the price of the item and shipping in a clean way to the UI, so I have to do this.
		if(uplink.money < price)
			to_chat(user, span_warning("You don't have enough credits in [uplink] for [I] with [method] shipping."))
			return FALSE

		if(I.buy(uplink, user, method))
			uplink.money -= price
			return TRUE
		return FALSE

/datum/blackmarket_market/blackmarket
	name = "Black Market"
	shipping = list(SHIPPING_METHOD_LTSRBT =50,
					SHIPPING_METHOD_LAUNCH =10,
					SHIPPING_METHOD_TELEPORT=75)


code:
/obj/item/circuitboard/machine/ltsrbt
	name = "LTSRBT (Machine Board)"
	icon_state = "bluespacearray"
	build_path = /obj/machinery/ltsrbt
	req_components = list(
		/obj/item/stack/ore/bluespace_crystal = 2,
		/obj/item/stock_parts/subspace/ansible = 1,
		/obj/item/stock_parts/micro_laser = 1,
		/obj/item/stock_parts/scanning_module = 2)
	def_components = list(/obj/item/stack/ore/bluespace_crystal = /obj/item/stack/ore/bluespace_crystal/artificial)

/obj/machinery/ltsrbt
	name = "Long-To-Short-Range-Bluespace-Transceiver"
	desc = "The LTSRBT is a compact teleportation machine for receiving and sending items outside the station and inside the station.\nUsing teleportation frequencies stolen from NT it is near undetectable.\nEssential for any illegal market operations on NT stations.\n"
	icon_state = "exonet_node"
	circuit = /obj/item/circuitboard/machine/ltsrbt
	density = TRUE

	idle_power_usage = 200

	/// Divider for power_usage_per_teleport.
	var/power_efficiency = 1
	/// Power used per teleported which gets divided by power_efficiency.
	var/power_usage_per_teleport = 10000
	/// The time it takes for the machine to recharge before being able to send or receive items.
	var/recharge_time = 0
	/// Current recharge progress.
	var/recharge_cooldown = 0
	/// Base recharge time in seconds which is used to get recharge_time.
	var/base_recharge_time = 100
	/// Current /datum/blackmarket_purchase being received.
	var/receiving
	/// Current /datum/blackmarket_purchase being sent to the target uplink.
	var/transmitting
	/// Queue for purchases that the machine should receive and send.
	var/list/datum/blackmarket_purchase/queue = list()

/obj/machinery/ltsrbt/Initialize(mapload)
	. = ..()
	SSblackmarket.telepads += src

/obj/machinery/ltsrbt/Destroy()
	SSblackmarket.telepads -= src
	// Bye bye orders.
	if(SSblackmarket.telepads.len)
		for(var/datum/blackmarket_purchase/P in queue)
			SSblackmarket.queue_item(P)
	. = ..()

/obj/machinery/ltsrbt/RefreshParts()
	recharge_time = base_recharge_time
	// On tier 4 recharge_time should be 20 and by default it is 80 as scanning modules should be tier 1.
	for(var/obj/item/stock_parts/scanning_module/scan in component_parts)
		recharge_time -= scan.rating * 10
	recharge_cooldown = recharge_time

	power_efficiency = 0
	for(var/obj/item/stock_parts/micro_laser/laser in component_parts)
		power_efficiency += laser.rating
	// Shouldn't happen but you never know.
	if(!power_efficiency)
		power_efficiency = 1

/// Adds /datum/blackmarket_purchase to queue unless the machine is free, then it sets the purchase to be instantly received
/obj/machinery/ltsrbt/proc/add_to_queue(datum/blackmarket_purchase/purchase)
	if(!recharge_cooldown && !receiving && !transmitting)
		receiving = purchase
		return
	queue += purchase

/obj/machinery/ltsrbt/process(delta_time)
	if(machine_stat & NOPOWER)
		return

	if(recharge_cooldown > 0)
		recharge_cooldown -= delta_time
		return

	var/turf/T = get_turf(src)
	if(receiving)
		var/datum/blackmarket_purchase/P = receiving

		if(!P.item || ispath(P.item))
			P.item = P.entry.spawn_item(T)
		else
			var/atom/movable/M = P.item
			M.forceMove(T)

		use_power(power_usage_per_teleport / power_efficiency)
		var/datum/effect_system/spark_spread/sparks = new
		sparks.set_up(5, 1, get_turf(src))
		sparks.attach(P.item)
		sparks.start()

		receiving = null
		transmitting = P

		recharge_cooldown = recharge_time
		return
	else if(transmitting)
		var/datum/blackmarket_purchase/P = transmitting
		if(!P.item)
			QDEL_NULL(transmitting)
		if(!(P.item in T.contents))
			QDEL_NULL(transmitting)
			return
		do_teleport(P.item, get_turf(P.uplink))
		use_power(power_usage_per_teleport / power_efficiency)
		QDEL_NULL(transmitting)

		recharge_cooldown = recharge_time
		return

	if(queue.len)
		receiving = pick_n_take(queue)


code:
/obj/item/blackmarket_uplink
	name = "Black Market Uplink"
	icon = 'icons/obj/blackmarket.dmi'
	icon_state = "uplink"

	// UI variables.
	var/viewing_category
	var/viewing_market
	var/selected_item
	var/buying

	/// How much money is inserted into the uplink.
	var/money = 0
	/// List of typepaths for "/datum/blackmarket_market"s that this uplink can access.
	var/list/accessible_markets = list(/datum/blackmarket_market/blackmarket)

/obj/item/blackmarket_uplink/Initialize(mapload)
	. = ..()
	if(accessible_markets.len)
		viewing_market = accessible_markets[1]
		var/list/categories = SSblackmarket.markets[viewing_market].categories
		if(categories?.len)
			viewing_category = categories[1]

/obj/item/blackmarket_uplink/attackby(obj/item/I, mob/user, params)
	if(istype(I, /obj/item/holochip) || istype(I, /obj/item/stack/spacecash) || istype(I, /obj/item/coin))
		var/worth = I.get_item_credit_value()
		if(!worth)
			to_chat(user, span_warning("[I] doesn't seem to be worth anything!"))
		money += worth
		to_chat(user, span_notice("You slot [I] into [src] and it reports a total of [money] credits inserted."))
		qdel(I)
		return
	. = ..()

/obj/item/blackmarket_uplink/AltClick(mob/user)
	if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
		return

	var/amount_to_remove =  FLOOR(input(user, "How much do you want to withdraw? Current Amount: [money]", "Withdraw Funds", 5) as num|null, 1)
	if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
		return

	if(!amount_to_remove || amount_to_remove < 0)
		return
	if(amount_to_remove > money)
		to_chat(user, span_warning("There is only [money] credits in [src]"))
		return

	var/obj/item/holochip/holochip = new (user.drop_location(), amount_to_remove)
	money -= amount_to_remove
	holochip.name = "washed " + holochip.name
	user.put_in_hands(holochip)
	to_chat(user, span_notice("You withdraw [amount_to_remove] credits into a holochip."))

/obj/item/blackmarket_uplink/ui_interact(mob/user, datum/tgui/ui)
	ui = SStgui.try_update_ui(user, src, ui)
	if(!ui)
		ui = new(user, src, "BlackMarketUplink", name)
		ui.open()

/obj/item/blackmarket_uplink/ui_data(mob/user)
	var/list/data = list()
	var/datum/blackmarket_market/market = viewing_market ? SSblackmarket.markets[viewing_market] : null
	data["categories"] = market ? market.categories : null
	data["delivery_methods"] = list()
	if(market)
		for(var/delivery in market.shipping)
			data["delivery_methods"] += list(list("name" = delivery, "price" = market.shipping[delivery]))
	data["money"] = money
	data["buying"] = buying
	data["items"] = list()
	data["viewing_category"] = viewing_category
	data["viewing_market"] = viewing_market
	if(viewing_category && market)
		if(market.available_items[viewing_category])
			for(var/datum/blackmarket_item/I in market.available_items[viewing_category])
				data["items"] += list(list(
					"id" = I.type,
					"name" = I.name,
					"cost" = I.price,
					"amount" = I.stock,
					"desc" = I.desc || I.name
				))
	return data

/obj/item/blackmarket_uplink/ui_static_data(mob/user)
	var/list/data = list()
	data["delivery_method_description"] = SSblackmarket.shipping_method_descriptions
	data["ltsrbt_built"] = SSblackmarket.telepads.len
	data["markets"] = list()
	for(var/M in accessible_markets)
		var/datum/blackmarket_market/BM = SSblackmarket.markets[M]
		data["markets"] += list(list(
			"id" = M,
			"name" = BM.name
		))
	return data

/obj/item/blackmarket_uplink/ui_act(action, params)
	. = ..()
	if(.)
		return
	switch(action)
		if("set_category")
			if(isnull(params["category"]))
				return
			if(isnull(viewing_market))
				return
			if(!(params["category"] in SSblackmarket.markets[viewing_market].categories))
				return
			viewing_category = params["category"]
			. = TRUE
		if("set_market")
			if(isnull(params["market"]))
				return
			var/market = text2path(params["market"])
			if(!(market in accessible_markets))
				return

			viewing_market = market

			var/list/categories = SSblackmarket.markets[viewing_market].categories
			if(categories?.len)
				viewing_category = categories[1]
			else
				viewing_category = null
			. = TRUE
		if("select")
			if(isnull(params["item"]))
				return
			var/item = text2path(params["item"])
			selected_item = item
			buying = TRUE
			. = TRUE
		if("cancel")
			selected_item = null
			buying = FALSE
			. = TRUE
		if("buy")
			if(isnull(params["method"]))
				return
			if(isnull(selected_item))
				buying = FALSE
				return
			var/datum/blackmarket_market/market = SSblackmarket.markets[viewing_market]
			market.purchase(selected_item, viewing_category, params["method"], src, usr)

			buying = FALSE
			selected_item = null

/datum/crafting_recipe/blackmarket_uplink
	name = "Black Market Uplink"
	result = /obj/item/blackmarket_uplink
	time = 30
	tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER, TOOL_MULTITOOL)
	reqs = list(
		/obj/item/stock_parts/subspace/amplifier = 1,
		/obj/item/stack/cable_coil = 15,
		/obj/item/radio = 1,
		/obj/item/analyzer = 1
	)
	category = CAT_MISC

/datum/crafting_recipe/blackmarket_uplink/New()
	..()
	blacklist |= typesof(/obj/item/radio/headset) // because we got shit like /obj/item/radio/off ... WHY!?!
	blacklist |= typesof(/obj/item/radio/intercom)


code:
/datum/bounty/item/assistant/strange_object
	name = "Strange Object"
	description = "Nanotrasen has taken an interest in strange objects. Find one in maint, and ship it off to CentCom right away."
	reward = CARGO_CRATE_VALUE * 2.4
	wanted_types = list(/obj/item/relic)

/datum/bounty/item/assistant/scooter
	name = "Scooter"
	description = "Nanotrasen has determined walking to be wasteful. Ship a scooter to CentCom to speed operations up."
	reward = CARGO_CRATE_VALUE * 2.16 // the mat hoffman
	wanted_types = list(/obj/vehicle/ridden/scooter)
	include_subtypes = FALSE

/datum/bounty/item/assistant/skateboard
	name = "Skateboard"
	description = "Nanotrasen has determined walking to be wasteful. Ship a skateboard to CentCom to speed operations up."
	reward = CARGO_CRATE_VALUE * 1.8 // the tony hawk
	wanted_types = list(/obj/vehicle/ridden/scooter/skateboard, /obj/item/melee/skateboard)

/datum/bounty/item/assistant/stunprod
	name = "Stunprod"
	description = "CentCom demands a stunprod to use against dissidents. Craft one, then ship it."
	reward = CARGO_CRATE_VALUE * 2.6
	wanted_types = list(/obj/item/melee/baton/security/cattleprod)

/datum/bounty/item/assistant/soap
	name = "Soap"
	description = "Soap has gone missing from CentCom's bathrooms and nobody knows who took it. Replace it and be the hero CentCom needs."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 3
	wanted_types = list(/obj/item/soap)

/datum/bounty/item/assistant/spear
	name = "Spears"
	description = "CentCom's security forces are going through budget cuts. You will be paid if you ship a set of spears."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 5
	wanted_types = list(/obj/item/spear)

/datum/bounty/item/assistant/toolbox
	name = "Toolboxes"
	description = "There's an absence of robustness at Central Command. Hurry up and ship some toolboxes as a solution."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 6
	wanted_types = list(/obj/item/storage/toolbox)

/datum/bounty/item/assistant/statue
	name = "Statue"
	description = "Central Command would like to commision an artsy statue for the lobby. Ship one out, when possible."
	reward = CARGO_CRATE_VALUE * 4
	wanted_types = list(/obj/structure/statue)

/datum/bounty/item/assistant/clown_box
	name = "Clown Box"
	description = "The universe needs laughter. Stamp cardboard with a clown stamp and ship it out."
	reward = CARGO_CRATE_VALUE * 3
	wanted_types = list(/obj/item/storage/box/clown)

/datum/bounty/item/assistant/cheesiehonkers
	name = "Cheesie Honkers"
	description = "Apparently the company that makes Cheesie Honkers is going out of business soon. CentCom wants to stock up before it happens!"
	reward = CARGO_CRATE_VALUE * 2.4
	required_count = 3
	wanted_types = list(/obj/item/food/cheesiehonkers)

/datum/bounty/item/assistant/baseball_bat
	name = "Baseball Bat"
	description = "Baseball fever is going on at CentCom! Be a dear and ship them some baseball bats, so that management can live out their childhood dream."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 5
	wanted_types = list(/obj/item/melee/baseball_bat)

/datum/bounty/item/assistant/extendohand
	name = "Extendo-Hand"
	description = "Commander Betsy is getting old, and can't bend over to get the telescreen remote anymore. Management has requested an extendo-hand to help her out."
	reward = CARGO_CRATE_VALUE * 5
	wanted_types = list(/obj/item/extendohand)

/datum/bounty/item/assistant/donut
	name = "Donuts"
	description = "CentCom's security forces are facing heavy losses against the Syndicate. Ship donuts to raise morale."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 10
	wanted_types = list(/obj/item/food/donut)

/datum/bounty/item/assistant/donkpocket
	name = "Donk-Pockets"
	description = "Consumer safety recall: Warning. Donk-Pockets manufactured in the past year contain hazardous lizard biomatter. Return units to CentCom immediately."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 10
	wanted_types = list(/obj/item/food/donkpocket)

/datum/bounty/item/assistant/briefcase
	name = "Briefcase"
	description = "Central Command will be holding a business convention this year. Ship a few briefcases in support."
	reward = CARGO_CRATE_VALUE * 5
	required_count = 5
	wanted_types = list(/obj/item/storage/briefcase, /obj/item/storage/secure/briefcase)

/datum/bounty/item/assistant/sunglasses
	name = "Sunglasses"
	description = "A famous blues duo is passing through the sector, but they've lost their shades and they can't perform. Ship new sunglasses to CentCom to rectify this."
	reward = CARGO_CRATE_VALUE * 6
	required_count = 2
	wanted_types = list(/obj/item/clothing/glasses/sunglasses)

/datum/bounty/item/assistant/monkey_hide
	name = "Monkey Hide"
	description = "One of the scientists at CentCom is interested in testing products on monkey skin. Your mission is to acquire monkey's hide and ship it."
	reward = CARGO_CRATE_VALUE * 3
	wanted_types = list(/obj/item/stack/sheet/animalhide/monkey)

/datum/bounty/item/assistant/comfy_chair
	name = "Comfy Chairs"
	description = "Commander Pat is unhappy with his chair. He claims it hurts his back. Ship some alternatives out to humor him."
	reward = CARGO_CRATE_VALUE * 3
	required_count = 5
	wanted_types = list(/obj/structure/chair/comfy)

/datum/bounty/item/assistant/geranium
	name = "Geraniums"
	description = "Commander Zot has the hots for Commander Zena. Send a shipment of geraniums - her favorite flower - and he'll happily reward you."
	reward = CARGO_CRATE_VALUE * 8
	required_count = 3
	wanted_types = list(/obj/item/food/grown/poppy/geranium)
	include_subtypes = FALSE

/datum/bounty/item/assistant/poppy
	name = "Poppies"
	description = "Commander Zot really wants to sweep Security Officer Olivia off her feet. Send a shipment of Poppies - her favorite flower - and he'll happily reward you."
	reward = CARGO_CRATE_VALUE * 2
	required_count = 3
	wanted_types = list(/obj/item/food/grown/poppy)
	include_subtypes = FALSE

/datum/bounty/item/assistant/shadyjims
	name = "Shady Jim's"
	description = "There's an irate officer at CentCom demanding that he receive a box of Shady Jim's cigarettes. Please ship one. He's starting to make threats."
	reward = CARGO_CRATE_VALUE
	wanted_types = list(/obj/item/storage/fancy/cigarettes/cigpack_shadyjims)

/datum/bounty/item/assistant/potted_plants
	name = "Potted Plants"
	description = "Central Command is looking to commission a new BirdBoat-class station. You've been ordered to supply the potted plants."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 8
	wanted_types = list(/obj/item/kirbyplants)

/datum/bounty/item/assistant/monkey_cubes
	name = "Monkey Cubes"
	description = "Due to a recent genetics accident, Central Command is in serious need of monkeys. Your mission is to ship monkey cubes."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 3
	wanted_types = list(/obj/item/food/monkeycube)

/datum/bounty/item/assistant/ied
	name = "IED"
	description = "Nanotrasen's maximum security prison at CentCom is undergoing personnel training. Ship a handful of IEDs to serve as a training tools."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 3
	wanted_types = list(/obj/item/grenade/iedcasing)

/datum/bounty/item/assistant/corgimeat
	name = "Raw Corgi Meat"
	description = "The Syndicate recently stole all of CentCom's Corgi meat. Ship out a replacement immediately."
	reward = CARGO_CRATE_VALUE * 6
	wanted_types = list(/obj/item/food/meat/slab/corgi)

/datum/bounty/item/assistant/action_figures
	name = "Action Figures"
	description = "The vice president's son saw an ad for action figures on the telescreen and now he won't shut up about them. Ship some to ease his complaints."
	reward = CARGO_CRATE_VALUE * 8
	required_count = 5
	wanted_types = list(/obj/item/toy/figure)

/datum/bounty/item/assistant/dead_mice
	name = "Dead Mice"
	description = "Station 14 ran out of freeze-dried mice. Ship some fresh ones so their janitor doesn't go on strike."
	reward = CARGO_CRATE_VALUE * 10
	required_count = 5
	wanted_types = list(/obj/item/food/deadmouse)

/datum/bounty/item/assistant/paper_bin
	name = "Paper Bins"
	description = "Our accounting division is all out of paper. We need a new shipment immediately."
	reward = CARGO_CRATE_VALUE * 5
	required_count = 5
	wanted_types = list(/obj/item/paper_bin)

/datum/bounty/item/assistant/crayons
	name = "Crayons"
	description = "Dr Jones' kid ate all our crayons again. Please send us yours."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 24
	wanted_types = list(/obj/item/toy/crayon)

/datum/bounty/item/assistant/pens
	name = "Pens"
	description = "We are hosting the intergalactic pen balancing competition. We need you to send us some standardized ball point pens."
	reward = CARGO_CRATE_VALUE * 4
	required_count = 10
	include_subtypes = FALSE
	wanted_types = list(/obj/item/pen)


code:
/datum/bounty/item/botany
	reward = CARGO_CRATE_VALUE * 10
	var/datum/bounty/item/botany/multiplier = 0 //adds bonus reward money; increased for higher tier or rare mutations
	var/datum/bounty/item/botany/bonus_desc //for adding extra flavor text to bounty descriptions
	var/datum/bounty/item/botany/foodtype = "meal" //same here

/datum/bounty/item/botany/New()
	..()
	description = "Central Command's head chef is looking to prepare a fine [foodtype] with [name]. [bonus_desc]"
	reward += multiplier * (CARGO_CRATE_VALUE * 2)
	required_count = rand(5, 10)

/datum/bounty/item/botany/ambrosia_vulgaris
	name = "Ambrosia Vulgaris Leaves"
	wanted_types = list(/obj/item/food/grown/ambrosia/vulgaris)
	foodtype = "stew"

/datum/bounty/item/botany/ambrosia_gaia
	name = "Ambrosia Gaia Leaves"
	wanted_types = list(/obj/item/food/grown/ambrosia/gaia)
	multiplier = 4
	foodtype = "stew"

/datum/bounty/item/botany/apple_golden
	name = "Golden Apples"
	wanted_types = list(/obj/item/food/grown/apple/gold)
	multiplier = 4
	foodtype = "dessert"

/datum/bounty/item/botany/banana
	name = "Bananas"
	wanted_types = list(/obj/item/food/grown/banana)
	exclude_types = list(/obj/item/food/grown/banana/bluespace)
	foodtype = "banana split"

/datum/bounty/item/botany/banana_bluespace
	name = "Bluespace Bananas"
	wanted_types = list(/obj/item/food/grown/banana/bluespace)
	multiplier = 2
	foodtype = "banana split"

/datum/bounty/item/botany/beans_koi
	name = "Koi Beans"
	wanted_types = list(/obj/item/food/grown/koibeans)
	multiplier = 2

/datum/bounty/item/botany/berries_death
	name = "Death Berries"
	wanted_types = list(/obj/item/food/grown/berries/death)
	multiplier = 2
	bonus_desc = "He insists that \"he knows what he's doing\"."
	foodtype = "sorbet"

/datum/bounty/item/botany/berries_glow
	name = "Glow-Berries"
	wanted_types = list(/obj/item/food/grown/berries/glow)
	multiplier = 2
	foodtype = "sorbet"

/datum/bounty/item/botany/cannabis
	name = "Cannabis Leaves"
	wanted_types = list(/obj/item/food/grown/cannabis)
	exclude_types = list(/obj/item/food/grown/cannabis/white, /obj/item/food/grown/cannabis/death, /obj/item/food/grown/cannabis/ultimate)
	multiplier = 4 //hush money
	bonus_desc = "Do not mention this shipment to security."
	foodtype = "batch of \"muffins\""

/datum/bounty/item/botany/cannabis_white
	name = "Lifeweed Leaves"
	wanted_types = list(/obj/item/food/grown/cannabis/white)
	multiplier = 6
	bonus_desc = "Do not mention this shipment to security."
	foodtype = "\"meal\""

/datum/bounty/item/botany/cannabis_death
	name = "Deathweed Leaves"
	wanted_types = list(/obj/item/food/grown/cannabis/death)
	multiplier = 6
	bonus_desc = "Do not mention this shipment to security."
	foodtype = "\"meal\""

/datum/bounty/item/botany/cannabis_ultimate
	name = "Omega Weed Leaves"
	wanted_types = list(/obj/item/food/grown/cannabis/ultimate)
	multiplier = 6
	bonus_desc = "Under no circumstances mention this shipment to security."
	foodtype = "batch of \"brownies\""

/datum/bounty/item/botany/wheat
	name = "Wheat Grains"
	wanted_types = list(/obj/item/food/grown/wheat)

/datum/bounty/item/botany/rice
	name = "Rice Grains"
	wanted_types = list(/obj/item/food/grown/rice)

/datum/bounty/item/botany/chili
	name = "Chili Peppers"
	wanted_types = list(/obj/item/food/grown/chili)

/datum/bounty/item/botany/ice_chili
	name = "Chilly Peppers"
	wanted_types = list(/obj/item/food/grown/icepepper)
	multiplier = 2

/datum/bounty/item/botany/ghost_chili
	name = "Ghost Chili Peppers"
	wanted_types = list(/obj/item/food/grown/ghost_chili)
	multiplier = 2

/datum/bounty/item/botany/citrus_lime
	name = "Limes"
	wanted_types = list(/obj/item/food/grown/citrus/lime)
	foodtype = "sorbet"

/datum/bounty/item/botany/citrus_lemon
	name = "Lemons"
	wanted_types = list(/obj/item/food/grown/citrus/lemon)
	foodtype = "sorbet"

/datum/bounty/item/botany/citrus_oranges
	name = "Oranges"
	wanted_types = list(/obj/item/food/grown/citrus/orange)
	bonus_desc = "Do not ship lemons or limes." //I vanted orahnge!
	foodtype = "sorbet"

/datum/bounty/item/botany/eggplant
	name = "Eggplants"
	wanted_types = list(/obj/item/food/grown/eggplant)
	bonus_desc = "Not to be confused with egg-plants."

/datum/bounty/item/botany/eggplant_eggy
	name = "Egg-plants"
	wanted_types = list(/obj/item/food/grown/shell/eggy)
	bonus_desc = "Not to be confused with eggplants."
	multiplier = 2

/datum/bounty/item/botany/kudzu
	name = "Kudzu Pods"
	wanted_types = list(/obj/item/food/grown/kudzupod)
	bonus_desc = "Store in a dry, dark place."
	multiplier = 4

/datum/bounty/item/botany/watermelon
	name = "Watermelons"
	wanted_types = list(/obj/item/food/grown/watermelon)
	foodtype = "dessert"

/datum/bounty/item/botany/watermelon_holy
	name = "Holy Melons"
	wanted_types = list(/obj/item/food/grown/holymelon)
	multiplier = 2
	foodtype = "dessert"

/datum/bounty/item/botany/glowshroom
	name = "Glowshrooms"
	wanted_types = list(/obj/item/food/grown/mushroom/glowshroom)
	exclude_types = list(/obj/item/food/grown/mushroom/glowshroom/glowcap, /obj/item/food/grown/mushroom/glowshroom/shadowshroom)
	foodtype = "omelet"

/datum/bounty/item/botany/glowshroom_cap
	name = "Glowcaps"
	wanted_types = list(/obj/item/food/grown/mushroom/glowshroom/glowcap)
	multiplier = 2
	foodtype = "omelet"

/datum/bounty/item/botany/glowshroom_shadow
	name = "Shadowshrooms"
	wanted_types = list(/obj/item/food/grown/mushroom/glowshroom/shadowshroom)
	multiplier = 2
	foodtype = "omelet"

/datum/bounty/item/botany/nettles_death
	name = "Death Nettles"
	wanted_types = list(/obj/item/food/grown/nettle/death)
	multiplier = 2
	bonus_desc = "Wear protection when handling them."
	foodtype = "cheese"

/datum/bounty/item/botany/pineapples
	name = "Pineapples"
	wanted_types = list(/obj/item/food/grown/pineapple)
	bonus_desc = "Not for human consumption."
	foodtype = "ashtray"

/datum/bounty/item/botany/tomato
	name = "Tomatoes"
	wanted_types = list(/obj/item/food/grown/tomato)
	exclude_types = list(/obj/item/food/grown/tomato/blue)

/datum/bounty/item/botany/tomato_bluespace
	name = "Bluespace Tomatoes"
	wanted_types = list(/obj/item/food/grown/tomato/blue/bluespace)
	multiplier = 4

/datum/bounty/item/botany/oatz
	name = "Oats"
	wanted_types = list(/obj/item/food/grown/oat)
	multiplier = 2
	foodtype = "batch of oatmeal"
	bonus_desc = "Squats and oats. We're all out of oats."

/datum/bounty/item/botany/bonfire
	name = "Lit Bonfire"
	description = "Space heaters are malfunctioning and the cargo crew of Central Command is starting to feel cold. Grow some logs and Ship a lit bonfire to warm them up."
	wanted_types = list(/obj/structure/bonfire)

/datum/bounty/item/botany/bonfire/applies_to(obj/O)
	if(!..())
		return FALSE
	var/obj/structure/bonfire/B = O
	return !!B.burning