diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index e1dc71bfa5a..edda907db4c 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -211,6 +211,13 @@
A.point()
return
+/mob/living/carbon/MiddleClickOn(var/atom/A)
+ if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
+ next_click = world.time + 5
+ mind.changeling.chosen_sting.try_to_sting(src, A)
+ else
+ A.point()
+
// In case of use break glass
/*
/atom/proc/MiddleClick(var/mob/M as mob)
@@ -253,6 +260,13 @@
A.AltClick(src)
return
+/mob/living/carbon/AltClickOn(var/atom/A)
+ if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
+ next_click = world.time + 5
+ mind.changeling.chosen_sting.try_to_sting(src, A)
+ else
+ ..()
+
/atom/proc/AltClick(var/mob/user)
var/turf/T = get_turf(src)
if(T && user.TurfAdjacent(T))
@@ -275,16 +289,16 @@
return
/atom/proc/CtrlShiftClick(var/mob/user)
- return
+ return
/mob/proc/AltShiftClickOn(var/atom/A)
A.AltShiftClick(src)
return
/atom/proc/AltShiftClick(var/mob/user)
- return
-
-
+ return
+
+
/*
Misc helpers
diff --git a/code/controllers/_DynamicAreaLighting_TG.dm b/code/controllers/_DynamicAreaLighting_TG.dm
index 8168ef50aad..15e0b2e9c8f 100644
--- a/code/controllers/_DynamicAreaLighting_TG.dm
+++ b/code/controllers/_DynamicAreaLighting_TG.dm
@@ -94,7 +94,7 @@ datum/light_source
if(owner.loc && owner.luminosity > 0)
readrgb(owner.l_color)
effect = list()
- for(var/turf/T in view(owner.get_light_range(),owner))
+ for(var/turf/T in view(owner.get_light_range(),get_turf(owner)))
var/delta_lumen = lum(T)
if(delta_lumen > 0)
effect[T] = delta_lumen
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 7bcb54660e8..35733590f64 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -70,11 +70,6 @@ datum/mind
if(!istype(new_character))
world.log << "## DEBUG: transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn"
if(current) //remove ourself from our old body's mind variable
- if(changeling)
- current.remove_changeling_powers()
- current.verbs -= /datum/changeling/proc/EvolutionMenu
- if(vampire)
- current.remove_vampire_powers()
current.mind = null
if(new_character.mind) //remove any mind currently in our new body's mind variable
@@ -85,10 +80,6 @@ datum/mind
current = new_character //link ourself to our new body
new_character.mind = src //and link our new body to ourself
- if(changeling)
- new_character.make_changeling()
- if(vampire)
- new_character.make_vampire()
if(active)
new_character.key = key //now transfer the key to link the client to our new body
@@ -475,7 +466,7 @@ datum/mind
if(!def_value)//If it's a custom objective, it will be an empty string.
def_value = "custom"
- var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "blood", "debrain", "protect", "prevent", "harm", "speciesist", "brig", "hijack", "escape", "survive", "steal", "download", "nuclear", "capture", "absorb", "destroy", "maroon", "custom")
+ var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "blood", "debrain", "protect", "prevent", "harm", "speciesist", "brig", "hijack", "escape", "survive", "steal", "download", "nuclear", "capture", "absorb", "destroy", "maroon", "identity theft", "custom")
if (!new_obj_type) return
var/datum/objective/new_objective = null
@@ -588,6 +579,11 @@ datum/mind
new_objective.owner = src
new_objective.target_amount = target_number
+ if("identity theft")
+ new_objective = new /datum/objective/escape/escape_with_identity
+ new_objective.owner = src
+ new_objective.find_target()
+
if ("custom")
var/expl = copytext(sanitize(input("Custom objective:", "Objective", objective ? objective.explanation_text : "") as text|null),1,MAX_MESSAGE_LEN)
if (!expl) return
@@ -843,7 +839,6 @@ datum/mind
ticker.mode.changelings -= src
special_role = null
current.remove_changeling_powers()
- current.verbs -= /datum/changeling/proc/EvolutionMenu
if(changeling) del(changeling)
current << "You grow weak and lose your powers! You are no longer a changeling and are stuck in your current form!"
log_admin("[key_name_admin(usr)] has de-changeling'ed [current].")
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index 5c6ef778390..19a01eb7a6e 100755
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -1,1204 +1,1209 @@
-//SUPPLY PACKS
-//NOTE: only secure crate types use the access var (and are lockable)
-//NOTE: hidden packs only show up when the computer has been hacked.
-//ANOTER NOTE: Contraband is obtainable through modified supplycomp circuitboards.
-//BIG NOTE: Don't add living things to crates, that's bad, it will break the shuttle.
-//NEW NOTE: Do NOT set the price of any crates below 7 points. Doing so allows infinite points.
-
-var/list/all_supply_groups = list("Operations","Security","Hospitality","Engineering","Medical / Science","Hydroponics","Organic")
-
-/datum/supply_packs
- var/name = null
- var/list/contains = list()
- var/manifest = ""
- var/amount = null
- var/cost = null
- var/containertype = null
- var/containername = null
- var/access = null
- var/hidden = 0
- var/contraband = 0
- var/group = "Operations"
-
-/datum/supply_packs/New()
- manifest += "
"
- for(var/path in contains)
- if(!path) continue
- var/atom/movable/AM = new path()
- manifest += "- [AM.name]
"
- AM.loc = null //just to make sure they're deleted by the garbage collector
- manifest += "
"
-
-/datum/supply_packs/specialops
- name = "Special Ops supplies"
- contains = list(/obj/item/weapon/storage/box/emps,
- /obj/item/weapon/grenade/smokebomb,
- /obj/item/weapon/grenade/smokebomb,
- /obj/item/weapon/grenade/smokebomb,
- /obj/item/weapon/pen/paralysis,
- /obj/item/weapon/grenade/chem_grenade/incendiary)
- cost = 20
- containertype = /obj/structure/closet/crate
- containername = "Special Ops crate"
- group = "Security"
- hidden = 1
-
-/datum/supply_packs/syndicate
- name = "ERROR_NULL_ENTRY"
- contains = list(/obj/item/weapon/storage/box/syndicate)
- cost = 140
- containertype = /obj/structure/closet/crate
- containername = "crate"
- hidden = 1
-
-/datum/supply_packs/food
- name = "Food crate"
- contains = list(/obj/item/weapon/reagent_containers/food/snacks/flour,
- /obj/item/weapon/reagent_containers/food/snacks/flour,
- /obj/item/weapon/reagent_containers/food/snacks/flour,
- /obj/item/weapon/reagent_containers/food/snacks/flour,
- /obj/item/weapon/reagent_containers/food/drinks/milk,
- /obj/item/weapon/reagent_containers/food/drinks/milk,
- /obj/item/weapon/storage/fancy/egg_box,
- /obj/item/weapon/reagent_containers/food/snacks/grown/banana,
- /obj/item/weapon/reagent_containers/food/snacks/grown/banana)
- cost = 10
- containertype = /obj/structure/closet/crate/freezer
- containername = "Food crate"
- group = "Hospitality"
-
-/datum/supply_packs/monkey
- name = "Monkey crate"
- contains = list (/obj/item/weapon/storage/box/monkeycubes)
- cost = 20
- containertype = /obj/structure/closet/crate/freezer
- containername = "Monkey crate"
- group = "Hydroponics"
-
-/datum/supply_packs/farwa
- name = "Farwa crate"
- contains = list (/obj/item/weapon/storage/box/farwacubes)
- cost = 30
- containertype = /obj/structure/closet/crate/freezer
- containername = "Farwa crate"
- group = "Hydroponics"
-
-/datum/supply_packs/skrell
- name = "Neaera crate"
- contains = list (/obj/item/weapon/storage/box/neaeracubes)
- cost = 30
- containertype = /obj/structure/closet/crate/freezer
- containername = "Neaera crate"
- group = "Hydroponics"
-
-/datum/supply_packs/stok
- name = "Stok crate"
- contains = list (/obj/item/weapon/storage/box/stokcubes)
- cost = 30
- containertype = /obj/structure/closet/crate/freezer
- containername = "Stok crate"
- group = "Hydroponics"
-
-/datum/supply_packs/beanbagammo
- name = "Beanbag shells"
- contains = list(/obj/item/ammo_casing/shotgun/beanbag,
- /obj/item/ammo_casing/shotgun/beanbag,
- /obj/item/ammo_casing/shotgun/beanbag,
- /obj/item/ammo_casing/shotgun/beanbag,
- /obj/item/ammo_casing/shotgun/beanbag,
- /obj/item/ammo_casing/shotgun/beanbag,
- /obj/item/ammo_casing/shotgun/beanbag,
- /obj/item/ammo_casing/shotgun/beanbag,
- /obj/item/ammo_casing/shotgun/beanbag,
- /obj/item/ammo_casing/shotgun/beanbag)
- cost = 10
- containertype = /obj/structure/closet/crate
- containername = "Beanbag shells"
- group = "Security"
-
-/datum/supply_packs/toner
- name = "Toner Cartridges"
- contains = list(/obj/item/device/toner,
- /obj/item/device/toner,
- /obj/item/device/toner,
- /obj/item/device/toner,
- /obj/item/device/toner,
- /obj/item/device/toner)
- cost = 10
- containertype = /obj/structure/closet/crate
- containername = "Toner Cartridges"
- group = "Operations"
-
-/datum/supply_packs/party
- name = "Party equipment"
- contains = list(/obj/item/weapon/storage/box/drinkingglasses,
- /obj/item/weapon/reagent_containers/food/drinks/shaker,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/patron,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager,
- /obj/item/weapon/storage/fancy/cigarettes/dromedaryco,
- /obj/item/weapon/lipstick/random,
- /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
- /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
- /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
- /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
- /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
- /obj/item/weapon/reagent_containers/food/drinks/cans/beer)
- cost = 20
- containertype = /obj/structure/closet/crate
- containername = "Party equipment"
- group = "Hospitality"
-
-/datum/supply_packs/internals
- name = "Internals crate"
- contains = list(/obj/item/clothing/mask/gas,
- /obj/item/clothing/mask/gas,
- /obj/item/clothing/mask/gas,
- /obj/item/weapon/tank/air,
- /obj/item/weapon/tank/air,
- /obj/item/weapon/tank/air)
- cost = 10
- containertype = /obj/structure/closet/crate/internals
- containername = "Internals crate"
- group = "Engineering"
-
-/datum/supply_packs/evacuation
- name = "Emergency equipment"
- contains = list(/obj/item/weapon/storage/toolbox/emergency,
- /obj/item/weapon/storage/toolbox/emergency,
- /obj/item/clothing/suit/storage/hazardvest,
- /obj/item/clothing/suit/storage/hazardvest,
- /obj/item/weapon/tank/emergency_oxygen,
- /obj/item/weapon/tank/emergency_oxygen,
- /obj/item/weapon/tank/emergency_oxygen,
- /obj/item/weapon/tank/emergency_oxygen,
- /obj/item/weapon/tank/emergency_oxygen,
- /obj/item/clothing/mask/gas,
- /obj/item/clothing/mask/gas,
- /obj/item/clothing/mask/gas,
- /obj/item/clothing/mask/gas,
- /obj/item/clothing/mask/gas)
- cost = 35
- containertype = /obj/structure/closet/crate/internals
- containername = "Emergency Crate"
- group = "Engineering"
-
-/datum/supply_packs/inflatable
- name = "Inflatable barriers"
- contains = list(/obj/item/weapon/storage/briefcase/inflatable,
- /obj/item/weapon/storage/briefcase/inflatable,
- /obj/item/weapon/storage/briefcase/inflatable)
- cost = 20
- containertype = /obj/structure/closet/crate
- containername = "Inflatable Barrier Crate"
- group = "Engineering"
-
-/datum/supply_packs/janitor
- name = "Janitorial supplies"
- contains = list(/obj/item/weapon/reagent_containers/glass/bucket,
- /obj/item/weapon/reagent_containers/glass/bucket,
- /obj/item/weapon/reagent_containers/glass/bucket,
- /obj/item/weapon/mop,
- /obj/item/weapon/caution,
- /obj/item/weapon/caution,
- /obj/item/weapon/caution,
- /obj/item/weapon/storage/bag/trash,
- /obj/item/weapon/reagent_containers/spray/cleaner,
- /obj/item/weapon/reagent_containers/glass/rag,
- /obj/item/weapon/grenade/chem_grenade/cleaner,
- /obj/item/weapon/grenade/chem_grenade/cleaner,
- /obj/item/weapon/grenade/chem_grenade/cleaner)
- cost = 10
- containertype = /obj/structure/closet/crate
- containername = "Janitorial supplies"
- group = "Operations"
-
-/datum/supply_packs/janicart
- name = "Janitorial Cart and Galoshes crate"
- contains = list(/obj/structure/janitorialcart,
- /obj/item/clothing/shoes/galoshes)
- cost = 10
- containertype = /obj/structure/largecrate
- containername = "janitorial cart crate"
-
-/datum/supply_packs/lightbulbs
- name = "Replacement lights"
- contains = list(/obj/item/weapon/storage/box/lights/mixed,
- /obj/item/weapon/storage/box/lights/mixed,
- /obj/item/weapon/storage/box/lights/mixed)
- cost = 10
- containertype = /obj/structure/closet/crate
- containername = "Replacement lights"
- group = "Engineering"
-
-/datum/supply_packs/costume
- name = "Standard Costume crate"
- contains = list(/obj/item/weapon/storage/backpack/clown,
- /obj/item/clothing/shoes/clown_shoes,
- /obj/item/clothing/mask/gas/clown_hat,
- /obj/item/clothing/under/rank/clown,
- /obj/item/weapon/bikehorn,
- /obj/item/clothing/under/mime,
- /obj/item/clothing/shoes/black,
- /obj/item/clothing/gloves/color/white,
- /obj/item/clothing/mask/gas/mime,
- /obj/item/clothing/head/beret,
- /obj/item/clothing/suit/suspenders,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing)
- cost = 10
- containertype = /obj/structure/closet/crate/secure
- containername = "Standard Costumes"
- access = access_theatre
- group = "Operations"
-
-/datum/supply_packs/wizard
- name = "Wizard costume"
- contains = list(/obj/item/weapon/staff,
- /obj/item/clothing/suit/wizrobe/fake,
- /obj/item/clothing/shoes/sandal,
- /obj/item/clothing/head/wizard/fake)
- cost = 20
- containertype = /obj/structure/closet/crate
- containername = "Wizard costume crate"
- group = "Operations"
-
-/datum/supply_packs/mule
- name = "MULEbot Crate"
- contains = list(/obj/machinery/bot/mulebot)
- cost = 20
- containertype = /obj/structure/largecrate/mule
- containername = "MULEbot Crate"
- group = "Operations"
-
-/datum/supply_packs/cargotrain
- name = "Cargo Train Tug"
- contains = list(/obj/vehicle/train/cargo/engine)
- cost = 45
- containertype = /obj/structure/largecrate
- containername = "Cargo Train Tug Crate"
- group = "Operations"
-
-/datum/supply_packs/cargotrailer
- name = "Cargo Train Trolley"
- contains = list(/obj/vehicle/train/cargo/trolley)
- cost = 15
- containertype = /obj/structure/largecrate
- containername = "Cargo Train Trolley Crate"
- group = "Operations"
-
-/datum/supply_packs/hydroponics // -- Skie
- name = "Hydroponics Supply Crate"
- contains = list(/obj/item/weapon/reagent_containers/spray/plantbgone,
- /obj/item/weapon/reagent_containers/spray/plantbgone,
- /obj/item/weapon/reagent_containers/glass/bottle/ammonia,
- /obj/item/weapon/reagent_containers/glass/bottle/ammonia,
- /obj/item/weapon/hatchet,
- /obj/item/weapon/minihoe,
- /obj/item/device/analyzer/plant_analyzer,
- /obj/item/clothing/gloves/botanic_leather,
- /obj/item/clothing/suit/apron,
- /obj/item/weapon/minihoe,
- /obj/item/weapon/storage/box/botanydisk
- ) // Updated with new things
- cost = 15
- containertype = /obj/structure/closet/crate/hydroponics
- containername = "Hydroponics crate"
- access = access_hydroponics
- group = "Hydroponics"
-
-//////// livestock
-/datum/supply_packs/organic/cow
- name = "Cow Crate"
- cost = 30
- containertype = /obj/structure/largecrate/cow
- containername = "cow crate"
- group = "Organic"
-
-/datum/supply_packs/organic/goat
- name = "Goat Crate"
- cost = 25
- containertype = /obj/structure/largecrate/goat
- containername = "goat crate"
- group = "Organic"
-
-/datum/supply_packs/organic/chicken
- name = "Chicken Crate"
- cost = 20
- containertype = /obj/structure/largecrate/chick
- containername = "chicken crate"
- group = "Organic"
-
-/datum/supply_packs/organic/corgi
- name = "Corgi Crate"
- cost = 50
- containertype = /obj/structure/largecrate/lisa
- containername = "corgi crate"
- group = "Organic"
-
-/datum/supply_packs/organic/cat
- name = "Cat crate"
- cost = 50 //Cats are worth as much as corgis.
- containertype = /obj/structure/largecrate/cat
- containername = "cat crate"
- group = "Organic"
-
-/datum/supply_packs/organic/fox
- name = "Fox Crate"
- cost = 55 //Foxes are cool.
- containertype = /obj/structure/closet/critter/fox
- containername = "fox crate"
- group = "Organic"
-
-/datum/supply_packs/seeds
- name = "Seeds Crate"
- contains = list(/obj/item/seeds/chiliseed,
- /obj/item/seeds/berryseed,
- /obj/item/seeds/cornseed,
- /obj/item/seeds/eggplantseed,
- /obj/item/seeds/tomatoseed,
- /obj/item/seeds/soyaseed,
- /obj/item/seeds/wheatseed,
- /obj/item/seeds/carrotseed,
- /obj/item/seeds/sunflowerseed,
- /obj/item/seeds/chantermycelium,
- /obj/item/seeds/potatoseed,
- /obj/item/seeds/sugarcaneseed)
- cost = 10
- containertype = /obj/structure/closet/crate/hydroponics
- containername = "Seeds crate"
- access = access_hydroponics
- group = "Hydroponics"
-
-/datum/supply_packs/weedcontrol
- name = "Weed Control Crate"
- contains = list(/obj/item/weapon/scythe,
- /obj/item/clothing/mask/gas,
- /obj/item/weapon/grenade/chem_grenade/antiweed,
- /obj/item/weapon/grenade/chem_grenade/antiweed)
- cost = 20
- containertype = /obj/structure/closet/crate/secure/hydrosec
- containername = "Weed control crate"
- access = access_hydroponics
- group = "Hydroponics"
-
-/datum/supply_packs/exoticseeds
- name = "Exotic Seeds Crate"
- contains = list(/obj/item/seeds/nettleseed,
- /obj/item/seeds/replicapod,
- /obj/item/seeds/replicapod,
- /obj/item/seeds/replicapod,
- /obj/item/seeds/plumpmycelium,
- /obj/item/seeds/libertymycelium,
- /obj/item/seeds/amanitamycelium,
- /obj/item/seeds/reishimycelium,
- /obj/item/seeds/bananaseed,
- /obj/item/seeds/eggyseed,
- /obj/item/seeds/bloodtomatoseed)
- cost = 15
- containertype = /obj/structure/closet/crate/hydroponics
- containername = "Exotic Seeds crate"
- access = access_hydroponics
- group = "Hydroponics"
-
-/datum/supply_packs/medical
- name = "Medical crate"
- contains = list(/obj/item/weapon/storage/firstaid/regular,
- /obj/item/weapon/storage/firstaid/fire,
- /obj/item/weapon/storage/firstaid/toxin,
- /obj/item/weapon/storage/firstaid/o2,
- /obj/item/weapon/storage/firstaid/adv,
- /obj/item/weapon/reagent_containers/glass/bottle/antitoxin,
- /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline,
- /obj/item/weapon/reagent_containers/glass/bottle/stoxin,
- /obj/item/weapon/storage/box/syringes,
- /obj/item/weapon/storage/box/autoinjectors)
- cost = 10
- containertype = /obj/structure/closet/crate/medical
- containername = "Medical crate"
- group = "Medical / Science"
-
-/datum/supply_packs/virus
- name = "Virus crate"
-/* contains = list(/obj/item/weapon/reagent_containers/glass/bottle/flu_virion,
- /obj/item/weapon/reagent_containers/glass/bottle/cold,
- /obj/item/weapon/reagent_containers/glass/bottle/epiglottis_virion,
- /obj/item/weapon/reagent_containers/glass/bottle/liver_enhance_virion,
- /obj/item/weapon/reagent_containers/glass/bottle/fake_gbs,
- /obj/item/weapon/reagent_containers/glass/bottle/magnitis,
- /obj/item/weapon/reagent_containers/glass/bottle/pierrot_throat,
- /obj/item/weapon/reagent_containers/glass/bottle/brainrot,
- /obj/item/weapon/reagent_containers/glass/bottle/hullucigen_virion,
- /obj/item/weapon/storage/box/syringes,
- /obj/item/weapon/storage/box/beakers,
- /obj/item/weapon/reagent_containers/glass/bottle/mutagen)*/
- contains = list(/obj/item/weapon/virusdish/random,
- /obj/item/weapon/virusdish/random,
- /obj/item/weapon/virusdish/random,
- /obj/item/weapon/virusdish/random)
- cost = 25
- containertype = "/obj/structure/closet/crate/secure"
- containername = "Virus crate"
- access = access_cmo
- group = "Medical / Science"
-
-/datum/supply_packs/metal50
- name = "50 Metal Sheets"
- contains = list(/obj/item/stack/sheet/metal)
- amount = 50
- cost = 10
- containertype = /obj/structure/closet/crate
- containername = "Metal sheets crate"
- group = "Engineering"
-
-/datum/supply_packs/glass50
- name = "50 Glass Sheets"
- contains = list(/obj/item/stack/sheet/glass)
- amount = 50
- cost = 10
- containertype = /obj/structure/closet/crate
- containername = "Glass sheets crate"
- group = "Engineering"
-
-/datum/supply_packs/electrical
- name = "Electrical maintenance crate"
- contains = list(/obj/item/weapon/storage/toolbox/electrical,
- /obj/item/weapon/storage/toolbox/electrical,
- /obj/item/clothing/gloves/yellow,
- /obj/item/clothing/gloves/yellow,
- /obj/item/weapon/stock_parts/cell,
- /obj/item/weapon/stock_parts/cell,
- /obj/item/weapon/stock_parts/cell/high,
- /obj/item/weapon/stock_parts/cell/high)
- cost = 15
- containertype = /obj/structure/closet/crate
- containername = "Electrical maintenance crate"
- group = "Engineering"
-
-/datum/supply_packs/mechanical
- name = "Mechanical maintenance crate"
- contains = list(/obj/item/weapon/storage/belt/utility/full,
- /obj/item/weapon/storage/belt/utility/full,
- /obj/item/weapon/storage/belt/utility/full,
- /obj/item/clothing/suit/storage/hazardvest,
- /obj/item/clothing/suit/storage/hazardvest,
- /obj/item/clothing/suit/storage/hazardvest,
- /obj/item/clothing/head/welding,
- /obj/item/clothing/head/welding,
- /obj/item/clothing/head/hardhat)
- cost = 10
- containertype = /obj/structure/closet/crate
- containername = "Mechanical maintenance crate"
- group = "Engineering"
-
-/datum/supply_packs/watertank
- name = "Water tank crate"
- contains = list(/obj/structure/reagent_dispensers/watertank)
- cost = 8
- containertype = /obj/structure/largecrate
- containername = "water tank crate"
- group = "Hydroponics"
-
-/datum/supply_packs/fueltank
- name = "Fuel tank crate"
- contains = list(/obj/structure/reagent_dispensers/fueltank)
- cost = 8
- containertype = /obj/structure/largecrate
- containername = "fuel tank crate"
- group = "Engineering"
-
-/datum/supply_packs/coolanttank
- name = "Coolant tank crate"
- contains = list(/obj/structure/reagent_dispensers/coolanttank)
- cost = 16
- containertype = /obj/structure/largecrate
- containername = "coolant tank crate"
- group = "Medical / Science"
-
-
-/datum/supply_packs/solar
- name = "Solar Pack crate"
- contains = list(/obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly,
- /obj/item/solar_assembly, // 21 Solar Assemblies. 1 Extra for the controller
- /obj/item/weapon/circuitboard/solar_control,
- /obj/item/weapon/tracker_electronics,
- /obj/item/weapon/paper/solar)
- cost = 20
- containertype = /obj/structure/closet/crate
- containername = "solar pack crate"
- group = "Engineering"
-
-/datum/supply_packs/engine
- name = "Emitter crate"
- contains = list(/obj/machinery/power/emitter,
- /obj/machinery/power/emitter)
- cost = 10
- containertype = /obj/structure/closet/crate/secure
- containername = "Emitter crate"
- access = access_ce
- group = "Engineering"
-
-/datum/supply_packs/engine/field_gen
- name = "Field Generator crate"
- contains = list(/obj/machinery/field_generator,
- /obj/machinery/field_generator)
- containertype = /obj/structure/closet/crate/secure
- containername = "Field Generator crate"
- access = access_ce
- group = "Engineering"
-
-/datum/supply_packs/engine/sing_gen
- name = "Singularity Generator crate"
- contains = list(/obj/machinery/the_singularitygen)
- containertype = /obj/structure/closet/crate/secure
- containername = "Singularity Generator crate"
- access = access_ce
- group = "Engineering"
-
-/datum/supply_packs/engine/collector
- name = "Collector crate"
- contains = list(/obj/machinery/power/rad_collector,
- /obj/machinery/power/rad_collector,
- /obj/machinery/power/rad_collector)
- containername = "Collector crate"
- group = "Engineering"
-
-/datum/supply_packs/engine/PA
- name = "Particle Accelerator crate"
- cost = 40
- contains = list(/obj/structure/particle_accelerator/fuel_chamber,
- /obj/machinery/particle_accelerator/control_box,
- /obj/structure/particle_accelerator/particle_emitter/center,
- /obj/structure/particle_accelerator/particle_emitter/left,
- /obj/structure/particle_accelerator/particle_emitter/right,
- /obj/structure/particle_accelerator/power_box,
- /obj/structure/particle_accelerator/end_cap)
- containertype = /obj/structure/closet/crate/secure
- containername = "Particle Accelerator crate"
- access = access_ce
- group = "Engineering"
-
-/datum/supply_packs/mecha_ripley
- name = "Circuit Crate (\"Ripley\" APLU)"
- contains = list(/obj/item/weapon/book/manual/ripley_build_and_repair,
- /obj/item/weapon/circuitboard/mecha/ripley/main, //TEMPORARY due to lack of circuitboard printer
- /obj/item/weapon/circuitboard/mecha/ripley/peripherals) //TEMPORARY due to lack of circuitboard printer
- cost = 30
- containertype = /obj/structure/closet/crate/secure
- containername = "APLU \"Ripley\" Circuit Crate"
- access = access_robotics
- group = "Engineering"
-
-/datum/supply_packs/mecha_odysseus
- name = "Circuit Crate (\"Odysseus\")"
- contains = list(/obj/item/weapon/circuitboard/mecha/odysseus/peripherals, //TEMPORARY due to lack of circuitboard printer
- /obj/item/weapon/circuitboard/mecha/odysseus/main) //TEMPORARY due to lack of circuitboard printer
- cost = 25
- containertype = /obj/structure/closet/crate/secure
- containername = "\"Odysseus\" Circuit Crate"
- access = access_robotics
- group = "Engineering"
-
-
-/datum/supply_packs/robotics
- name = "Robotics Assembly Crate"
- contains = list(/obj/item/device/assembly/prox_sensor,
- /obj/item/device/assembly/prox_sensor,
- /obj/item/device/assembly/prox_sensor,
- /obj/item/weapon/storage/toolbox/electrical,
- /obj/item/device/flash,
- /obj/item/device/flash,
- /obj/item/device/flash,
- /obj/item/device/flash,
- /obj/item/weapon/stock_parts/cell/high,
- /obj/item/weapon/stock_parts/cell/high)
- cost = 10
- containertype = /obj/structure/closet/crate/secure/gear
- containername = "Robotics Assembly"
- access = access_robotics
- group = "Engineering"
-
-/datum/supply_packs/plasma
- name = "Plasma assembly crate"
- contains = list(/obj/item/weapon/tank/plasma,
- /obj/item/weapon/tank/plasma,
- /obj/item/weapon/tank/plasma,
- /obj/item/device/assembly/igniter,
- /obj/item/device/assembly/igniter,
- /obj/item/device/assembly/igniter,
- /obj/item/device/assembly/prox_sensor,
- /obj/item/device/assembly/prox_sensor,
- /obj/item/device/assembly/prox_sensor,
- /obj/item/device/transfer_valve,
- /obj/item/device/transfer_valve,
- /obj/item/device/transfer_valve,
- /obj/item/device/assembly/timer,
- /obj/item/device/assembly/timer,
- /obj/item/device/assembly/timer)
- cost = 10
- containertype = /obj/structure/closet/crate/secure/plasma
- containername = "Plasma assembly crate"
- access = access_tox_storage
- group = "Medical / Science"
-
-/datum/supply_packs/weapons
- name = "Weapons crate"
- contains = list(/obj/item/weapon/melee/baton/loaded,
- /obj/item/weapon/melee/baton/loaded,
- /obj/item/weapon/gun/energy/laser,
- /obj/item/weapon/gun/energy/laser,
- /obj/item/weapon/gun/energy/advtaser,
- /obj/item/weapon/gun/energy/advtaser,
- /obj/item/weapon/storage/box/flashbangs,
- /obj/item/weapon/storage/box/flashbangs)
- cost = 30
- containertype = /obj/structure/closet/crate/secure/weapon
- containername = "Weapons crate"
- access = access_security
- group = "Security"
-
-/datum/supply_packs/disabler
- name = "Disabler Crate"
- contains = list(/obj/item/weapon/gun/energy/disabler,
- /obj/item/weapon/gun/energy/disabler,
- /obj/item/weapon/gun/energy/disabler)
- cost = 10
- containertype = /obj/structure/closet/crate/secure/weapon
- containername = "disabler crate"
- access = access_security
- group = "Security"
-
-/datum/supply_packs/eweapons
- name = "Experimental weapons crate"
- contains = list(/obj/item/weapon/flamethrower/full,
- /obj/item/weapon/tank/plasma,
- /obj/item/weapon/tank/plasma,
- /obj/item/weapon/tank/plasma,
- /obj/item/weapon/grenade/chem_grenade/incendiary,
- /obj/item/weapon/grenade/chem_grenade/incendiary,
- /obj/item/weapon/grenade/chem_grenade/incendiary)
- cost = 25
- containertype = /obj/structure/closet/crate/secure/weapon
- containername = "Experimental weapons crate"
- access = access_heads
- group = "Security"
-
-/datum/supply_packs/armor
- name = "Armor crate"
- contains = list(/obj/item/clothing/head/helmet,
- /obj/item/clothing/head/helmet,
- /obj/item/clothing/suit/armor/vest,
- /obj/item/clothing/suit/armor/vest)
- cost = 15
- containertype = /obj/structure/closet/crate/secure
- containername = "Armor crate"
- access = access_security
- group = "Security"
-
-/datum/supply_packs/riot
- name = "Riot gear crate"
- contains = list(/obj/item/weapon/melee/baton/loaded,
- /obj/item/weapon/melee/baton/loaded,
- /obj/item/weapon/melee/baton/loaded,
- /obj/item/weapon/shield/riot,
- /obj/item/weapon/shield/riot,
- /obj/item/weapon/shield/riot,
- /obj/item/weapon/storage/box/flashbangs,
- /obj/item/weapon/storage/box/flashbangs,
- /obj/item/weapon/storage/box/flashbangs,
- /obj/item/weapon/handcuffs,
- /obj/item/weapon/handcuffs,
- /obj/item/weapon/handcuffs,
- /obj/item/clothing/head/helmet/riot,
- /obj/item/clothing/suit/armor/riot,
- /obj/item/clothing/head/helmet/riot,
- /obj/item/clothing/suit/armor/riot,
- /obj/item/clothing/head/helmet/riot,
- /obj/item/clothing/suit/armor/riot)
- cost = 60
- containertype = /obj/structure/closet/crate/secure
- containername = "Riot gear crate"
- access = access_armory
- group = "Security"
-
-/datum/supply_packs/loyalty
- name = "Loyalty implant crate"
- contains = list (/obj/item/weapon/storage/lockbox/loyalty)
- cost = 60
- containertype = /obj/structure/closet/crate/secure
- containername = "Loyalty implant crate"
- access = access_armory
- group = "Security"
-
-/datum/supply_packs/ballistic
- name = "Ballistic gear crate"
- contains = list(/obj/item/clothing/suit/armor/bulletproof,
- /obj/item/clothing/suit/armor/bulletproof,
- /obj/item/weapon/storage/belt/bandolier,
- /obj/item/weapon/storage/belt/bandolier,
- /obj/item/weapon/gun/projectile/shotgun/combat,
- /obj/item/weapon/gun/projectile/shotgun/combat)
- cost = 50
- containertype = /obj/structure/closet/crate/secure
- containername = "Ballistic gear crate"
- access = access_armory
- group = "Security"
-
-/datum/supply_packs/shotgunammo
- name = "Shotgun shells"
- contains = list(/obj/item/ammo_casing/shotgun,
- /obj/item/ammo_casing/shotgun,
- /obj/item/ammo_casing/shotgun,
- /obj/item/ammo_casing/shotgun,
- /obj/item/ammo_casing/shotgun,
- /obj/item/ammo_casing/shotgun,
- /obj/item/ammo_casing/shotgun,
- /obj/item/ammo_casing/shotgun,
- /obj/item/ammo_casing/shotgun,
- /obj/item/ammo_casing/shotgun)
- cost = 20
- containertype = /obj/structure/closet/crate/secure
- containername = "Shotgun shells"
- access = access_armory
- group = "Security"
-
-/datum/supply_packs/expenergy
- name = "Experimental energy gear crate"
- contains = list(/obj/item/clothing/suit/armor/laserproof,
- /obj/item/clothing/suit/armor/laserproof,
- /obj/item/weapon/gun/energy/gun,
- /obj/item/weapon/gun/energy/gun)
- cost = 50
- containertype = /obj/structure/closet/crate/secure
- containername = "Experimental energy gear crate"
- access = access_armory
- group = "Security"
-
-/datum/supply_packs/exparmor
- name = "Experimental armor crate"
- contains = list(/obj/item/clothing/suit/armor/laserproof,
- /obj/item/clothing/suit/armor/bulletproof,
- /obj/item/clothing/head/helmet/riot,
- /obj/item/clothing/suit/armor/riot)
- cost = 35
- containertype = /obj/structure/closet/crate/secure
- containername = "Experimental armor crate"
- access = access_armory
- group = "Security"
-
-/datum/supply_packs/securitybarriers
- name = "Security Barriers"
- contains = list(/obj/machinery/deployable/barrier,
- /obj/machinery/deployable/barrier,
- /obj/machinery/deployable/barrier,
- /obj/machinery/deployable/barrier)
- cost = 20
- containertype = /obj/structure/closet/crate/secure/gear
- containername = "Security Barriers crate"
- group = "Security"
-
-/datum/supply_packs/securitybarriers
- name = "Shield Generators"
- contains = list(/obj/machinery/shieldwallgen,
- /obj/machinery/shieldwallgen,
- /obj/machinery/shieldwallgen,
- /obj/machinery/shieldwallgen)
- cost = 20
- containertype = /obj/structure/closet/crate/secure
- containername = "Shield Generators crate"
- access = access_teleporter
- group = "Security"
-
-/datum/supply_packs/randomised
- var/num_contained = 3 //number of items picked to be contained in a randomised crate
- contains = list(/obj/item/clothing/head/collectable/chef,
- /obj/item/clothing/head/collectable/paper,
- /obj/item/clothing/head/collectable/tophat,
- /obj/item/clothing/head/collectable/captain,
- /obj/item/clothing/head/collectable/beret,
- /obj/item/clothing/head/collectable/welding,
- /obj/item/clothing/head/collectable/flatcap,
- /obj/item/clothing/head/collectable/pirate,
- /obj/item/clothing/head/collectable/kitty,
- /obj/item/clothing/head/collectable/rabbitears,
- /obj/item/clothing/head/collectable/wizard,
- /obj/item/clothing/head/collectable/hardhat,
- /obj/item/clothing/head/collectable/HoS,
- /obj/item/clothing/head/collectable/thunderdome,
- /obj/item/clothing/head/collectable/swat,
- /obj/item/clothing/head/collectable/slime,
- /obj/item/clothing/head/collectable/police,
- /obj/item/clothing/head/collectable/slime,
- /obj/item/clothing/head/collectable/xenom,
- /obj/item/clothing/head/collectable/petehat)
- name = "Collectable hat crate!"
- cost = 200
- containertype = /obj/structure/closet/crate
- containername = "Collectable hats crate! Brought to you by Bass.inc!"
- group = "Operations"
-
-/datum/supply_packs/randomised/New()
- manifest += "Contains any [num_contained] of:"
- ..()
-
-/datum/supply_packs/artscrafts
- name = "Arts and Crafts supplies"
- contains = list(/obj/item/weapon/storage/fancy/crayons,
- /obj/item/device/camera,
- /obj/item/device/camera_film,
- /obj/item/device/camera_film,
- /obj/item/weapon/storage/photo_album,
- /obj/item/weapon/packageWrap,
- /obj/item/weapon/reagent_containers/glass/paint/red,
- /obj/item/weapon/reagent_containers/glass/paint/green,
- /obj/item/weapon/reagent_containers/glass/paint/blue,
- /obj/item/weapon/reagent_containers/glass/paint/yellow,
- /obj/item/weapon/reagent_containers/glass/paint/violet,
- /obj/item/weapon/reagent_containers/glass/paint/black,
- /obj/item/weapon/reagent_containers/glass/paint/white,
- /obj/item/weapon/reagent_containers/glass/paint/remover,
- /obj/item/weapon/contraband/poster,
- /obj/item/weapon/wrapping_paper,
- /obj/item/weapon/wrapping_paper,
- /obj/item/weapon/wrapping_paper)
- cost = 10
- containertype = "/obj/structure/closet/crate"
- containername = "Arts and Crafts crate"
- group = "Operations"
-
-
-/datum/supply_packs/randomised/contraband
- num_contained = 6
- contains = list(/obj/item/weapon/storage/pill_bottle/zoom,
- /obj/item/weapon/storage/pill_bottle/happy,
- /obj/item/weapon/storage/pill_bottle/random_drug_bottle,
- /obj/item/weapon/storage/fancy/cigarettes/dromedaryco,
- /obj/item/weapon/storage/fancy/cigarettes/cigpack_shadyjims,
- /obj/item/weapon/grenade/smokebomb,
- /obj/item/clothing/mask/cigarette/cigar/cohiba,
- /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/patron,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe,
- /obj/item/weapon/lipstick/random)
-
- name = "Contraband crate"
- cost = 30
- containertype = /obj/structure/closet/crate
- containername = "Unlabeled crate"
- contraband = 1
- group = "Operations"
-
-/datum/supply_packs/boxes
- name = "Empty Box supplies"
- contains = list(/obj/item/weapon/storage/box,
- /obj/item/weapon/storage/box,
- /obj/item/weapon/storage/box,
- /obj/item/weapon/storage/box,
- /obj/item/weapon/storage/box,
- /obj/item/weapon/storage/box,
- /obj/item/weapon/storage/box,
- /obj/item/weapon/storage/box,
- /obj/item/weapon/storage/box,
- /obj/item/weapon/storage/box)
- cost = 10
- containertype = "/obj/structure/closet/crate"
- containername = "Empty Box crate"
- group = "Operations"
-
-/datum/supply_packs/surgery
- name = "Surgery crate"
- contains = list(/obj/item/weapon/cautery,
- /obj/item/weapon/surgicaldrill,
- /obj/item/clothing/mask/breath/medical,
- /obj/item/weapon/tank/anesthetic,
- /obj/item/weapon/FixOVein,
- /obj/item/weapon/hemostat,
- /obj/item/weapon/scalpel,
- /obj/item/weapon/bonegel,
- /obj/item/weapon/retractor,
- /obj/item/weapon/bonesetter,
- /obj/item/weapon/circular_saw)
- cost = 25
- containertype = "/obj/structure/closet/crate/secure"
- containername = "Surgery crate"
- access = access_medical
- group = "Medical / Science"
-
-/datum/supply_packs/sterile
- name = "Sterile equipment crate"
- contains = list(/obj/item/clothing/under/rank/medical/green,
- /obj/item/clothing/under/rank/medical/green,
- /obj/item/weapon/storage/box/masks,
- /obj/item/weapon/storage/box/gloves)
- cost = 15
- containertype = "/obj/structure/closet/crate"
- containername = "Sterile equipment crate"
- group = "Medical / Science"
-
-/datum/supply_packs/randomised/pizza
- num_contained = 5
- contains = list(/obj/item/pizzabox/margherita,
- /obj/item/pizzabox/mushroom,
- /obj/item/pizzabox/meat,
- /obj/item/pizzabox/vegetable)
- name = "Surprise pack of five dozen pizzas"
- cost = 15
- containertype = /obj/structure/closet/crate/freezer
- containername = "Pizza crate"
- group = "Hospitality"
-
-/datum/supply_packs/formal_wear
- contains = list(/obj/item/clothing/head/that,
- /obj/item/clothing/suit/storage/lawyer/bluejacket,
- /obj/item/clothing/suit/storage/lawyer/purpjacket,
- /obj/item/clothing/under/suit_jacket,
- /obj/item/clothing/under/suit_jacket/female,
- /obj/item/clothing/under/suit_jacket/really_black,
- /obj/item/clothing/under/suit_jacket/red,
- /obj/item/clothing/shoes/black,
- /obj/item/clothing/shoes/black,
- /obj/item/clothing/suit/wcoat)
- name = "Formalwear closet"
- cost = 30
- containertype = /obj/structure/closet
- containername = "Formalwear for the best occasions."
- group = "Operations"
-/*
-/datum/supply_packs/rust_injector
- contains = list(/obj/machinery/power/rust_fuel_injector)
- name = "RUST fuel injector"
- cost = 50
- containertype = /obj/structure/closet/crate/secure/large
- containername = "RUST injector crate"
- group = "Engineering"
- access = access_engine
-
-/datum/supply_packs/rust_compressor
- contains = list(/obj/item/weapon/module/rust_fuel_compressor)
- name = "RUST fuel compressor circuitry"
- cost = 60
- containertype = /obj/structure/closet/crate/secure
- containername = "RUST fuel compressor circuitry"
- group = "Engineering"
- access = access_engine
-
-/datum/supply_packs/rust_assembly_port
- contains = list(/obj/item/weapon/module/rust_fuel_port)
- name = "RUST fuel assembly port circuitry"
- cost = 40
- containertype = /obj/structure/closet/crate/secure
- containername = "RUST fuel assembly port circuitry"
- group = "Engineering"
- access = access_engine
-
-/datum/supply_packs/rust_core
- contains = list(/obj/machinery/power/rust_core)
- name = "RUST Tokamak Core"
- cost = 75
- containertype = /obj/structure/closet/crate/secure/large
- containername = "RUST tokamak crate"
- group = "Engineering"
- access = access_engine
-*/
-/datum/supply_packs/shield_gen
- contains = list(/obj/item/weapon/circuitboard/shield_gen)
- name = "Experimental shield generator circuitry"
- cost = 50
- containertype = /obj/structure/closet/crate/secure
- containername = "Experimental shield generator"
- group = "Engineering"
- access = access_ce
-
-/datum/supply_packs/shield_cap
- contains = list(/obj/item/weapon/circuitboard/shield_cap)
- name = "Experimental shield capacitor circuitry"
- cost = 50
- containertype = /obj/structure/closet/crate/secure
- containername = "Experimental shield capacitor"
- group = "Engineering"
- access = access_ce
-
-/datum/supply_packs/eftpos
- contains = list(/obj/item/device/eftpos)
- name = "EFTPOS scanner"
- cost = 10
- containertype = /obj/structure/closet/crate
- containername = "EFTPOS crate"
- group = "Operations"
-
-/datum/supply_packs/teg
- contains = list(/obj/machinery/power/generator)
- name = "Mark I Thermoelectric Generator"
- cost = 75
- containertype = /obj/structure/closet/crate/secure/large
- containername = "Mk1 TEG crate"
- group = "Engineering"
- access = access_engine
-
-/datum/supply_packs/circulator
- contains = list(/obj/machinery/atmospherics/binary/circulator)
- name = "Binary atmospheric circulator"
- cost = 60
- containertype = /obj/structure/closet/crate/secure/large
- containername = "Atmospheric circulator crate"
- group = "Engineering"
- access = access_engine
-
-/datum/supply_packs/bee_keeper
- name = "Beekeeping Crate"
- contains = list(/obj/item/beezeez,
- /obj/item/beezeez,
- /obj/item/weapon/bee_net,
- /obj/item/apiary,
- /obj/item/queen_bee,
- /obj/item/queen_bee,
- /obj/item/queen_bee)
- cost = 20
- containertype = /obj/structure/closet/crate/hydroponics
- containername = "Beekeeping crate"
- access = access_hydroponics
- group = "Hydroponics"
-
-/datum/supply_packs/misc/lasertag
- name = "Laser Tag Crate"
- contains = list(/obj/item/weapon/gun/energy/laser/redtag,
- /obj/item/weapon/gun/energy/laser/redtag,
- /obj/item/weapon/gun/energy/laser/redtag,
- /obj/item/weapon/gun/energy/laser/bluetag,
- /obj/item/weapon/gun/energy/laser/bluetag,
- /obj/item/weapon/gun/energy/laser/bluetag,
- /obj/item/clothing/suit/redtag,
- /obj/item/clothing/suit/redtag,
- /obj/item/clothing/suit/redtag,
- /obj/item/clothing/suit/bluetag,
- /obj/item/clothing/suit/bluetag,
- /obj/item/clothing/suit/bluetag,
- /obj/item/clothing/head/helmet/redtaghelm,
- /obj/item/clothing/head/helmet/bluetaghelm)
- cost = 15
- containertype = /obj/structure/closet/crate
- containername = "laser tag crate"
- group = "Operations"
-
-/datum/supply_packs/vending
- name = "Bartending Supply Crate"
- contains = list(/obj/item/weapon/vending_refill/boozeomat,
- /obj/item/weapon/vending_refill/boozeomat,
- /obj/item/weapon/vending_refill/boozeomat,
- /obj/item/weapon/vending_refill/coffee,
- /obj/item/weapon/vending_refill/coffee,
- /obj/item/weapon/vending_refill/coffee)
- cost = 15
- containertype = /obj/structure/closet/crate
- containername = "bartending supply crate"
- group = "Operations"
-
-/datum/supply_packs/vending/snack
- name = "Snack Supply Crate"
- contains = list(/obj/item/weapon/vending_refill/snack,
- /obj/item/weapon/vending_refill/snack,
- /obj/item/weapon/vending_refill/snack)
- cost = 15
- containertype = /obj/structure/closet/crate
- containername = "snacks supply crate"
- group = "Operations"
-
-/datum/supply_packs/vending/cola
- name = "Softdrinks Supply Crate"
- contains = list(/obj/item/weapon/vending_refill/cola,
- /obj/item/weapon/vending_refill/cola,
- /obj/item/weapon/vending_refill/cola)
- cost = 15
- containertype = /obj/structure/closet/crate
- containername = "softdrinks supply crate"
- group = "Operations"
-
-/datum/supply_packs/vending/cigarette
- name = "Cigarette Supply Crate"
- contains = list(/obj/item/weapon/vending_refill/cigarette,
- /obj/item/weapon/vending_refill/cigarette,
- /obj/item/weapon/vending_refill/cigarette)
- cost = 15
- containertype = /obj/structure/closet/crate
- containername = "cigarette supply crate"
- group = "Operations"
-
-/datum/supply_packs/autodrobe
- name = "Autodrobe Supply crate"
- contains = list(/obj/item/weapon/vending_refill/autodrobe,
- /obj/item/weapon/vending_refill/autodrobe,
- /obj/item/weapon/vending_refill/autodrobe)
- cost = 15
- containertype = /obj/structure/closet/crate
- containername = "autodrobe supply crate"
- group = "Operations"
-
-/datum/supply_packs/clothingvendor
- name = "Clothing Vendor Supply crate"
- contains = list(/obj/item/weapon/vending_refill/hatdispenser,
- /obj/item/weapon/vending_refill/hatdispenser,
- /obj/item/weapon/vending_refill/hatdispenser,
- /obj/item/weapon/vending_refill/suitdispenser,
- /obj/item/weapon/vending_refill/suitdispenser,
- /obj/item/weapon/vending_refill/suitdispenser,
- /obj/item/weapon/vending_refill/shoedispenser,
- /obj/item/weapon/vending_refill/shoedispenser,
- /obj/item/weapon/vending_refill/shoedispenser)
- cost = 30
- containertype = /obj/structure/closet/crate
- containername = "clothing vendor supply crate"
- group = "Operations"
-
-/datum/supply_packs/mafia
- name = "Mafia Supply crate"
- contains = list(/obj/item/clothing/suit/browntrenchcoat =1,/obj/item/clothing/suit/blacktrenchcoat =1,/obj/item/clothing/head/fedora/whitefedora =1,
- /obj/item/clothing/head/fedora/brownfedora =1,/obj/item/clothing/head/fedora =1,/obj/item/clothing/under/flappers =1,/obj/item/clothing/under/mafia =1,/obj/item/clothing/under/mafia/vest =1,/obj/item/clothing/under/mafia/white =1,
- /obj/item/clothing/under/mafia/sue =1,/obj/item/clothing/under/mafia/tan =1, /obj/item/toy/crossbow/tommygun =2)
- cost = 15
- containertype = /obj/structure/closet/crate
- containername = "mafia supply crate"
- group = "Operations"
-
-/datum/supply_packs/fabric
- name = "Fabric crate"
- contains = list(/obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric,
- /obj/item/weapon/ore/fabric)
- cost = 30
- containertype = /obj/structure/closet/crate
- containername = "Fabric crate"
- group = "Operations"
+//SUPPLY PACKS
+//NOTE: only secure crate types use the access var (and are lockable)
+//NOTE: hidden packs only show up when the computer has been hacked.
+//ANOTER NOTE: Contraband is obtainable through modified supplycomp circuitboards.
+//BIG NOTE: Don't add living things to crates, that's bad, it will break the shuttle.
+//NEW NOTE: Do NOT set the price of any crates below 7 points. Doing so allows infinite points.
+
+var/list/all_supply_groups = list("Operations","Security","Hospitality","Engineering","Medical / Science","Hydroponics","Organic")
+
+/datum/supply_packs
+ var/name = null
+ var/list/contains = list()
+ var/manifest = ""
+ var/amount = null
+ var/cost = null
+ var/containertype = null
+ var/containername = null
+ var/access = null
+ var/hidden = 0
+ var/contraband = 0
+ var/group = "Operations"
+
+/datum/supply_packs/New()
+ manifest += ""
+ for(var/path in contains)
+ if(!path) continue
+ var/atom/movable/AM = new path()
+ manifest += "- [AM.name]
"
+ AM.loc = null //just to make sure they're deleted by the garbage collector
+ manifest += "
"
+
+/datum/supply_packs/specialops
+ name = "Special Ops supplies"
+ contains = list(/obj/item/weapon/storage/box/emps,
+ /obj/item/weapon/grenade/smokebomb,
+ /obj/item/weapon/grenade/smokebomb,
+ /obj/item/weapon/grenade/smokebomb,
+ /obj/item/weapon/pen/paralysis,
+ /obj/item/weapon/grenade/chem_grenade/incendiary)
+ cost = 20
+ containertype = /obj/structure/closet/crate
+ containername = "Special Ops crate"
+ group = "Security"
+ hidden = 1
+
+/datum/supply_packs/syndicate
+ name = "ERROR_NULL_ENTRY"
+ contains = list(/obj/item/weapon/storage/box/syndicate)
+ cost = 140
+ containertype = /obj/structure/closet/crate
+ containername = "crate"
+ hidden = 1
+
+/datum/supply_packs/food
+ name = "Food crate"
+ contains = list(/obj/item/weapon/reagent_containers/food/snacks/flour,
+ /obj/item/weapon/reagent_containers/food/snacks/flour,
+ /obj/item/weapon/reagent_containers/food/snacks/flour,
+ /obj/item/weapon/reagent_containers/food/snacks/flour,
+ /obj/item/weapon/reagent_containers/food/drinks/milk,
+ /obj/item/weapon/reagent_containers/food/drinks/milk,
+ /obj/item/weapon/storage/fancy/egg_box,
+ /obj/item/weapon/reagent_containers/food/snacks/grown/banana,
+ /obj/item/weapon/reagent_containers/food/snacks/grown/banana)
+ cost = 10
+ containertype = /obj/structure/closet/crate/freezer
+ containername = "Food crate"
+ group = "Hospitality"
+
+/datum/supply_packs/monkey
+ name = "Monkey crate"
+ contains = list (/obj/item/weapon/storage/box/monkeycubes)
+ cost = 20
+ containertype = /obj/structure/closet/crate/freezer
+ containername = "Monkey crate"
+ group = "Hydroponics"
+
+/datum/supply_packs/farwa
+ name = "Farwa crate"
+ contains = list (/obj/item/weapon/storage/box/farwacubes)
+ cost = 30
+ containertype = /obj/structure/closet/crate/freezer
+ containername = "Farwa crate"
+ group = "Hydroponics"
+
+/datum/supply_packs/skrell
+ name = "Neaera crate"
+ contains = list (/obj/item/weapon/storage/box/neaeracubes)
+ cost = 30
+ containertype = /obj/structure/closet/crate/freezer
+ containername = "Neaera crate"
+ group = "Hydroponics"
+
+/datum/supply_packs/stok
+ name = "Stok crate"
+ contains = list (/obj/item/weapon/storage/box/stokcubes)
+ cost = 30
+ containertype = /obj/structure/closet/crate/freezer
+ containername = "Stok crate"
+ group = "Hydroponics"
+
+/datum/supply_packs/beanbagammo
+ name = "Beanbag shells"
+ contains = list(/obj/item/ammo_casing/shotgun/beanbag,
+ /obj/item/ammo_casing/shotgun/beanbag,
+ /obj/item/ammo_casing/shotgun/beanbag,
+ /obj/item/ammo_casing/shotgun/beanbag,
+ /obj/item/ammo_casing/shotgun/beanbag,
+ /obj/item/ammo_casing/shotgun/beanbag,
+ /obj/item/ammo_casing/shotgun/beanbag,
+ /obj/item/ammo_casing/shotgun/beanbag,
+ /obj/item/ammo_casing/shotgun/beanbag,
+ /obj/item/ammo_casing/shotgun/beanbag)
+ cost = 10
+ containertype = /obj/structure/closet/crate
+ containername = "Beanbag shells"
+ group = "Security"
+
+/datum/supply_packs/toner
+ name = "Toner Cartridges"
+ contains = list(/obj/item/device/toner,
+ /obj/item/device/toner,
+ /obj/item/device/toner,
+ /obj/item/device/toner,
+ /obj/item/device/toner,
+ /obj/item/device/toner)
+ cost = 10
+ containertype = /obj/structure/closet/crate
+ containername = "Toner Cartridges"
+ group = "Operations"
+
+/datum/supply_packs/party
+ name = "Party equipment"
+ contains = list(/obj/item/weapon/storage/box/drinkingglasses,
+ /obj/item/weapon/reagent_containers/food/drinks/shaker,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/patron,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager,
+ /obj/item/weapon/storage/fancy/cigarettes/dromedaryco,
+ /obj/item/weapon/lipstick/random,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/beer)
+ cost = 20
+ containertype = /obj/structure/closet/crate
+ containername = "Party equipment"
+ group = "Hospitality"
+
+/datum/supply_packs/internals
+ name = "Internals crate"
+ contains = list(/obj/item/clothing/mask/gas,
+ /obj/item/clothing/mask/gas,
+ /obj/item/clothing/mask/gas,
+ /obj/item/weapon/tank/air,
+ /obj/item/weapon/tank/air,
+ /obj/item/weapon/tank/air)
+ cost = 10
+ containertype = /obj/structure/closet/crate/internals
+ containername = "Internals crate"
+ group = "Engineering"
+
+/datum/supply_packs/evacuation
+ name = "Emergency equipment"
+ contains = list(/obj/item/weapon/storage/toolbox/emergency,
+ /obj/item/weapon/storage/toolbox/emergency,
+ /obj/item/clothing/suit/storage/hazardvest,
+ /obj/item/clothing/suit/storage/hazardvest,
+ /obj/item/weapon/tank/emergency_oxygen,
+ /obj/item/weapon/tank/emergency_oxygen,
+ /obj/item/weapon/tank/emergency_oxygen,
+ /obj/item/weapon/tank/emergency_oxygen,
+ /obj/item/weapon/tank/emergency_oxygen,
+ /obj/item/clothing/mask/gas,
+ /obj/item/clothing/mask/gas,
+ /obj/item/clothing/mask/gas,
+ /obj/item/clothing/mask/gas,
+ /obj/item/clothing/mask/gas)
+ cost = 35
+ containertype = /obj/structure/closet/crate/internals
+ containername = "Emergency Crate"
+ group = "Engineering"
+
+/datum/supply_packs/inflatable
+ name = "Inflatable barriers"
+ contains = list(/obj/item/weapon/storage/briefcase/inflatable,
+ /obj/item/weapon/storage/briefcase/inflatable,
+ /obj/item/weapon/storage/briefcase/inflatable)
+ cost = 20
+ containertype = /obj/structure/closet/crate
+ containername = "Inflatable Barrier Crate"
+ group = "Engineering"
+
+/datum/supply_packs/janitor
+ name = "Janitorial supplies"
+ contains = list(/obj/item/weapon/reagent_containers/glass/bucket,
+ /obj/item/weapon/reagent_containers/glass/bucket,
+ /obj/item/weapon/reagent_containers/glass/bucket,
+ /obj/item/weapon/mop,
+ /obj/item/weapon/caution,
+ /obj/item/weapon/caution,
+ /obj/item/weapon/caution,
+ /obj/item/weapon/storage/bag/trash,
+ /obj/item/weapon/reagent_containers/spray/cleaner,
+ /obj/item/weapon/reagent_containers/glass/rag,
+ /obj/item/weapon/grenade/chem_grenade/cleaner,
+ /obj/item/weapon/grenade/chem_grenade/cleaner,
+ /obj/item/weapon/grenade/chem_grenade/cleaner)
+ cost = 10
+ containertype = /obj/structure/closet/crate
+ containername = "Janitorial supplies"
+ group = "Operations"
+
+/datum/supply_packs/janicart
+ name = "Janitorial Cart and Galoshes crate"
+ contains = list(/obj/structure/janitorialcart,
+ /obj/item/clothing/shoes/galoshes)
+ cost = 10
+ containertype = /obj/structure/largecrate
+ containername = "janitorial cart crate"
+
+/datum/supply_packs/lightbulbs
+ name = "Replacement lights"
+ contains = list(/obj/item/weapon/storage/box/lights/mixed,
+ /obj/item/weapon/storage/box/lights/mixed,
+ /obj/item/weapon/storage/box/lights/mixed)
+ cost = 10
+ containertype = /obj/structure/closet/crate
+ containername = "Replacement lights"
+ group = "Engineering"
+
+/datum/supply_packs/costume
+ name = "Standard Costume crate"
+ contains = list(/obj/item/weapon/storage/backpack/clown,
+ /obj/item/clothing/shoes/clown_shoes,
+ /obj/item/clothing/mask/gas/clown_hat,
+ /obj/item/clothing/under/rank/clown,
+ /obj/item/weapon/bikehorn,
+ /obj/item/clothing/under/mime,
+ /obj/item/clothing/shoes/black,
+ /obj/item/clothing/gloves/color/white,
+ /obj/item/clothing/mask/gas/mime,
+ /obj/item/clothing/head/beret,
+ /obj/item/clothing/suit/suspenders,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing)
+ cost = 10
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Standard Costumes"
+ access = access_theatre
+ group = "Operations"
+
+/datum/supply_packs/wizard
+ name = "Wizard costume"
+ contains = list(/obj/item/weapon/staff,
+ /obj/item/clothing/suit/wizrobe/fake,
+ /obj/item/clothing/shoes/sandal,
+ /obj/item/clothing/head/wizard/fake)
+ cost = 20
+ containertype = /obj/structure/closet/crate
+ containername = "Wizard costume crate"
+ group = "Operations"
+
+/datum/supply_packs/mule
+ name = "MULEbot Crate"
+ contains = list(/obj/machinery/bot/mulebot)
+ cost = 20
+ containertype = /obj/structure/largecrate/mule
+ containername = "MULEbot Crate"
+ group = "Operations"
+
+/datum/supply_packs/cargotrain
+ name = "Cargo Train Tug"
+ contains = list(/obj/vehicle/train/cargo/engine)
+ cost = 45
+ containertype = /obj/structure/largecrate
+ containername = "Cargo Train Tug Crate"
+ group = "Operations"
+
+/datum/supply_packs/cargotrailer
+ name = "Cargo Train Trolley"
+ contains = list(/obj/vehicle/train/cargo/trolley)
+ cost = 15
+ containertype = /obj/structure/largecrate
+ containername = "Cargo Train Trolley Crate"
+ group = "Operations"
+
+/datum/supply_packs/hydroponics // -- Skie
+ name = "Hydroponics Supply Crate"
+ contains = list(/obj/item/weapon/reagent_containers/spray/plantbgone,
+ /obj/item/weapon/reagent_containers/spray/plantbgone,
+ /obj/item/weapon/reagent_containers/glass/bottle/ammonia,
+ /obj/item/weapon/reagent_containers/glass/bottle/ammonia,
+ /obj/item/weapon/hatchet,
+ /obj/item/weapon/minihoe,
+ /obj/item/device/analyzer/plant_analyzer,
+ /obj/item/clothing/gloves/botanic_leather,
+ /obj/item/clothing/suit/apron,
+ /obj/item/weapon/minihoe,
+ /obj/item/weapon/storage/box/botanydisk
+ ) // Updated with new things
+ cost = 15
+ containertype = /obj/structure/closet/crate/hydroponics
+ containername = "Hydroponics crate"
+ access = access_hydroponics
+ group = "Hydroponics"
+
+//////// livestock
+/datum/supply_packs/organic/cow
+ name = "Cow Crate"
+ cost = 30
+ containertype = /obj/structure/largecrate/cow
+ containername = "cow crate"
+ group = "Organic"
+
+/datum/supply_packs/organic/goat
+ name = "Goat Crate"
+ cost = 25
+ containertype = /obj/structure/largecrate/goat
+ containername = "goat crate"
+ group = "Organic"
+
+/datum/supply_packs/organic/chicken
+ name = "Chicken Crate"
+ cost = 20
+ containertype = /obj/structure/largecrate/chick
+ containername = "chicken crate"
+ group = "Organic"
+
+/datum/supply_packs/organic/corgi
+ name = "Corgi Crate"
+ cost = 50
+ containertype = /obj/structure/largecrate/lisa
+ containername = "corgi crate"
+ group = "Organic"
+
+/datum/supply_packs/organic/cat
+ name = "Cat crate"
+ cost = 50 //Cats are worth as much as corgis.
+ containertype = /obj/structure/largecrate/cat
+ containername = "cat crate"
+ group = "Organic"
+
+/datum/supply_packs/organic/fox
+ name = "Fox Crate"
+ cost = 55 //Foxes are cool.
+ containertype = /obj/structure/closet/critter/fox
+ containername = "fox crate"
+ group = "Organic"
+
+/datum/supply_packs/seeds
+ name = "Seeds Crate"
+ contains = list(/obj/item/seeds/chiliseed,
+ /obj/item/seeds/berryseed,
+ /obj/item/seeds/cornseed,
+ /obj/item/seeds/eggplantseed,
+ /obj/item/seeds/tomatoseed,
+ /obj/item/seeds/soyaseed,
+ /obj/item/seeds/wheatseed,
+ /obj/item/seeds/carrotseed,
+ /obj/item/seeds/sunflowerseed,
+ /obj/item/seeds/chantermycelium,
+ /obj/item/seeds/potatoseed,
+ /obj/item/seeds/sugarcaneseed)
+ cost = 10
+ containertype = /obj/structure/closet/crate/hydroponics
+ containername = "Seeds crate"
+ access = access_hydroponics
+ group = "Hydroponics"
+
+/datum/supply_packs/weedcontrol
+ name = "Weed Control Crate"
+ contains = list(/obj/item/weapon/scythe,
+ /obj/item/clothing/mask/gas,
+ /obj/item/weapon/grenade/chem_grenade/antiweed,
+ /obj/item/weapon/grenade/chem_grenade/antiweed)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure/hydrosec
+ containername = "Weed control crate"
+ access = access_hydroponics
+ group = "Hydroponics"
+
+/datum/supply_packs/exoticseeds
+ name = "Exotic Seeds Crate"
+ contains = list(/obj/item/seeds/nettleseed,
+ /obj/item/seeds/replicapod,
+ /obj/item/seeds/replicapod,
+ /obj/item/seeds/replicapod,
+ /obj/item/seeds/plumpmycelium,
+ /obj/item/seeds/libertymycelium,
+ /obj/item/seeds/amanitamycelium,
+ /obj/item/seeds/reishimycelium,
+ /obj/item/seeds/bananaseed,
+ /obj/item/seeds/eggyseed,
+ /obj/item/seeds/bloodtomatoseed)
+ cost = 15
+ containertype = /obj/structure/closet/crate/hydroponics
+ containername = "Exotic Seeds crate"
+ access = access_hydroponics
+ group = "Hydroponics"
+
+/datum/supply_packs/medical
+ name = "Medical crate"
+ contains = list(/obj/item/weapon/storage/firstaid/regular,
+ /obj/item/weapon/storage/firstaid/fire,
+ /obj/item/weapon/storage/firstaid/toxin,
+ /obj/item/weapon/storage/firstaid/o2,
+ /obj/item/weapon/storage/firstaid/adv,
+ /obj/item/weapon/reagent_containers/glass/bottle/antitoxin,
+ /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline,
+ /obj/item/weapon/reagent_containers/glass/bottle/stoxin,
+ /obj/item/weapon/storage/box/syringes,
+ /obj/item/weapon/storage/box/autoinjectors)
+ cost = 10
+ containertype = /obj/structure/closet/crate/medical
+ containername = "Medical crate"
+ group = "Medical / Science"
+
+/datum/supply_packs/virus
+ name = "Virus crate"
+/* contains = list(/obj/item/weapon/reagent_containers/glass/bottle/flu_virion,
+ /obj/item/weapon/reagent_containers/glass/bottle/cold,
+ /obj/item/weapon/reagent_containers/glass/bottle/epiglottis_virion,
+ /obj/item/weapon/reagent_containers/glass/bottle/liver_enhance_virion,
+ /obj/item/weapon/reagent_containers/glass/bottle/fake_gbs,
+ /obj/item/weapon/reagent_containers/glass/bottle/magnitis,
+ /obj/item/weapon/reagent_containers/glass/bottle/pierrot_throat,
+ /obj/item/weapon/reagent_containers/glass/bottle/brainrot,
+ /obj/item/weapon/reagent_containers/glass/bottle/hullucigen_virion,
+ /obj/item/weapon/storage/box/syringes,
+ /obj/item/weapon/storage/box/beakers,
+ /obj/item/weapon/reagent_containers/glass/bottle/mutagen)*/
+ contains = list(/obj/item/weapon/virusdish/random,
+ /obj/item/weapon/virusdish/random,
+ /obj/item/weapon/virusdish/random,
+ /obj/item/weapon/virusdish/random)
+ cost = 25
+ containertype = "/obj/structure/closet/crate/secure"
+ containername = "Virus crate"
+ access = access_cmo
+ group = "Medical / Science"
+
+/datum/supply_packs/metal50
+ name = "50 Metal Sheets"
+ contains = list(/obj/item/stack/sheet/metal)
+ amount = 50
+ cost = 10
+ containertype = /obj/structure/closet/crate
+ containername = "Metal sheets crate"
+ group = "Engineering"
+
+/datum/supply_packs/glass50
+ name = "50 Glass Sheets"
+ contains = list(/obj/item/stack/sheet/glass)
+ amount = 50
+ cost = 10
+ containertype = /obj/structure/closet/crate
+ containername = "Glass sheets crate"
+ group = "Engineering"
+
+/datum/supply_packs/electrical
+ name = "Electrical maintenance crate"
+ contains = list(/obj/item/weapon/storage/toolbox/electrical,
+ /obj/item/weapon/storage/toolbox/electrical,
+ /obj/item/clothing/gloves/yellow,
+ /obj/item/clothing/gloves/yellow,
+ /obj/item/weapon/stock_parts/cell,
+ /obj/item/weapon/stock_parts/cell,
+ /obj/item/weapon/stock_parts/cell/high,
+ /obj/item/weapon/stock_parts/cell/high)
+ cost = 15
+ containertype = /obj/structure/closet/crate
+ containername = "Electrical maintenance crate"
+ group = "Engineering"
+
+/datum/supply_packs/mechanical
+ name = "Mechanical maintenance crate"
+ contains = list(/obj/item/weapon/storage/belt/utility/full,
+ /obj/item/weapon/storage/belt/utility/full,
+ /obj/item/weapon/storage/belt/utility/full,
+ /obj/item/clothing/suit/storage/hazardvest,
+ /obj/item/clothing/suit/storage/hazardvest,
+ /obj/item/clothing/suit/storage/hazardvest,
+ /obj/item/clothing/head/welding,
+ /obj/item/clothing/head/welding,
+ /obj/item/clothing/head/hardhat)
+ cost = 10
+ containertype = /obj/structure/closet/crate
+ containername = "Mechanical maintenance crate"
+ group = "Engineering"
+
+/datum/supply_packs/watertank
+ name = "Water tank crate"
+ contains = list(/obj/structure/reagent_dispensers/watertank)
+ cost = 8
+ containertype = /obj/structure/largecrate
+ containername = "water tank crate"
+ group = "Hydroponics"
+
+/datum/supply_packs/fueltank
+ name = "Fuel tank crate"
+ contains = list(/obj/structure/reagent_dispensers/fueltank)
+ cost = 8
+ containertype = /obj/structure/largecrate
+ containername = "fuel tank crate"
+ group = "Engineering"
+
+/datum/supply_packs/coolanttank
+ name = "Coolant tank crate"
+ contains = list(/obj/structure/reagent_dispensers/coolanttank)
+ cost = 16
+ containertype = /obj/structure/largecrate
+ containername = "coolant tank crate"
+ group = "Medical / Science"
+
+
+/datum/supply_packs/solar
+ name = "Solar Pack crate"
+ contains = list(/obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly,
+ /obj/item/solar_assembly, // 21 Solar Assemblies. 1 Extra for the controller
+ /obj/item/weapon/circuitboard/solar_control,
+ /obj/item/weapon/tracker_electronics,
+ /obj/item/weapon/paper/solar)
+ cost = 20
+ containertype = /obj/structure/closet/crate
+ containername = "solar pack crate"
+ group = "Engineering"
+
+/datum/supply_packs/engine
+ name = "Emitter crate"
+ contains = list(/obj/machinery/power/emitter,
+ /obj/machinery/power/emitter)
+ cost = 10
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Emitter crate"
+ access = access_ce
+ group = "Engineering"
+
+/datum/supply_packs/engine/field_gen
+ name = "Field Generator crate"
+ contains = list(/obj/machinery/field_generator,
+ /obj/machinery/field_generator)
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Field Generator crate"
+ access = access_ce
+ group = "Engineering"
+
+/datum/supply_packs/engine/sing_gen
+ name = "Singularity Generator crate"
+ contains = list(/obj/machinery/the_singularitygen)
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Singularity Generator crate"
+ access = access_ce
+ group = "Engineering"
+
+/datum/supply_packs/engine/collector
+ name = "Collector crate"
+ contains = list(/obj/machinery/power/rad_collector,
+ /obj/machinery/power/rad_collector,
+ /obj/machinery/power/rad_collector)
+ containername = "Collector crate"
+ group = "Engineering"
+
+/datum/supply_packs/engine/PA
+ name = "Particle Accelerator crate"
+ cost = 40
+ contains = list(/obj/structure/particle_accelerator/fuel_chamber,
+ /obj/machinery/particle_accelerator/control_box,
+ /obj/structure/particle_accelerator/particle_emitter/center,
+ /obj/structure/particle_accelerator/particle_emitter/left,
+ /obj/structure/particle_accelerator/particle_emitter/right,
+ /obj/structure/particle_accelerator/power_box,
+ /obj/structure/particle_accelerator/end_cap)
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Particle Accelerator crate"
+ access = access_ce
+ group = "Engineering"
+
+/datum/supply_packs/mecha_ripley
+ name = "Circuit Crate (\"Ripley\" APLU)"
+ contains = list(/obj/item/weapon/book/manual/ripley_build_and_repair,
+ /obj/item/weapon/circuitboard/mecha/ripley/main, //TEMPORARY due to lack of circuitboard printer
+ /obj/item/weapon/circuitboard/mecha/ripley/peripherals) //TEMPORARY due to lack of circuitboard printer
+ cost = 30
+ containertype = /obj/structure/closet/crate/secure
+ containername = "APLU \"Ripley\" Circuit Crate"
+ access = access_robotics
+ group = "Engineering"
+
+/datum/supply_packs/mecha_odysseus
+ name = "Circuit Crate (\"Odysseus\")"
+ contains = list(/obj/item/weapon/circuitboard/mecha/odysseus/peripherals, //TEMPORARY due to lack of circuitboard printer
+ /obj/item/weapon/circuitboard/mecha/odysseus/main) //TEMPORARY due to lack of circuitboard printer
+ cost = 25
+ containertype = /obj/structure/closet/crate/secure
+ containername = "\"Odysseus\" Circuit Crate"
+ access = access_robotics
+ group = "Engineering"
+
+
+/datum/supply_packs/robotics
+ name = "Robotics Assembly Crate"
+ contains = list(/obj/item/device/assembly/prox_sensor,
+ /obj/item/device/assembly/prox_sensor,
+ /obj/item/device/assembly/prox_sensor,
+ /obj/item/weapon/storage/toolbox/electrical,
+ /obj/item/device/flash,
+ /obj/item/device/flash,
+ /obj/item/device/flash,
+ /obj/item/device/flash,
+ /obj/item/weapon/stock_parts/cell/high,
+ /obj/item/weapon/stock_parts/cell/high)
+ cost = 10
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Robotics Assembly"
+ access = access_robotics
+ group = "Engineering"
+
+/datum/supply_packs/plasma
+ name = "Plasma assembly crate"
+ contains = list(/obj/item/weapon/tank/plasma,
+ /obj/item/weapon/tank/plasma,
+ /obj/item/weapon/tank/plasma,
+ /obj/item/device/assembly/igniter,
+ /obj/item/device/assembly/igniter,
+ /obj/item/device/assembly/igniter,
+ /obj/item/device/assembly/prox_sensor,
+ /obj/item/device/assembly/prox_sensor,
+ /obj/item/device/assembly/prox_sensor,
+ /obj/item/device/transfer_valve,
+ /obj/item/device/transfer_valve,
+ /obj/item/device/transfer_valve,
+ /obj/item/device/assembly/timer,
+ /obj/item/device/assembly/timer,
+ /obj/item/device/assembly/timer)
+ cost = 10
+ containertype = /obj/structure/closet/crate/secure/plasma
+ containername = "Plasma assembly crate"
+ access = access_tox_storage
+ group = "Medical / Science"
+
+/datum/supply_packs/weapons
+ name = "Weapons crate"
+ contains = list(/obj/item/weapon/melee/baton/loaded,
+ /obj/item/weapon/melee/baton/loaded,
+ /obj/item/weapon/gun/energy/laser,
+ /obj/item/weapon/gun/energy/laser,
+ /obj/item/weapon/gun/energy/advtaser,
+ /obj/item/weapon/gun/energy/advtaser,
+ /obj/item/weapon/storage/box/flashbangs,
+ /obj/item/weapon/storage/box/flashbangs)
+ cost = 30
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "Weapons crate"
+ access = access_security
+ group = "Security"
+
+/datum/supply_packs/disabler
+ name = "Disabler Crate"
+ contains = list(/obj/item/weapon/gun/energy/disabler,
+ /obj/item/weapon/gun/energy/disabler,
+ /obj/item/weapon/gun/energy/disabler)
+ cost = 10
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "disabler crate"
+ access = access_security
+ group = "Security"
+
+/datum/supply_packs/eweapons
+ name = "Experimental weapons crate"
+ contains = list(/obj/item/weapon/flamethrower/full,
+ /obj/item/weapon/tank/plasma,
+ /obj/item/weapon/tank/plasma,
+ /obj/item/weapon/tank/plasma,
+ /obj/item/weapon/grenade/chem_grenade/incendiary,
+ /obj/item/weapon/grenade/chem_grenade/incendiary,
+ /obj/item/weapon/grenade/chem_grenade/incendiary)
+ cost = 25
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "Experimental weapons crate"
+ access = access_heads
+ group = "Security"
+
+/datum/supply_packs/armor
+ name = "Armor crate"
+ contains = list(/obj/item/clothing/head/helmet,
+ /obj/item/clothing/head/helmet,
+ /obj/item/clothing/suit/armor/vest,
+ /obj/item/clothing/suit/armor/vest)
+ cost = 15
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Armor crate"
+ access = access_security
+ group = "Security"
+
+/datum/supply_packs/riot
+ name = "Riot gear crate"
+ contains = list(/obj/item/weapon/melee/baton/loaded,
+ /obj/item/weapon/melee/baton/loaded,
+ /obj/item/weapon/melee/baton/loaded,
+ /obj/item/weapon/shield/riot,
+ /obj/item/weapon/shield/riot,
+ /obj/item/weapon/shield/riot,
+ /obj/item/weapon/storage/box/flashbangs,
+ /obj/item/weapon/storage/box/flashbangs,
+ /obj/item/weapon/storage/box/flashbangs,
+ /obj/item/weapon/handcuffs,
+ /obj/item/weapon/handcuffs,
+ /obj/item/weapon/handcuffs,
+ /obj/item/clothing/head/helmet/riot,
+ /obj/item/clothing/suit/armor/riot,
+ /obj/item/clothing/head/helmet/riot,
+ /obj/item/clothing/suit/armor/riot,
+ /obj/item/clothing/head/helmet/riot,
+ /obj/item/clothing/suit/armor/riot)
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Riot gear crate"
+ access = access_armory
+ group = "Security"
+
+/datum/supply_packs/loyalty
+ name = "Loyalty implant crate"
+ contains = list (/obj/item/weapon/storage/lockbox/loyalty)
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Loyalty implant crate"
+ access = access_armory
+ group = "Security"
+
+/datum/supply_packs/ballistic
+ name = "Ballistic gear crate"
+ contains = list(/obj/item/clothing/suit/armor/bulletproof,
+ /obj/item/clothing/suit/armor/bulletproof,
+ /obj/item/weapon/storage/belt/bandolier,
+ /obj/item/weapon/storage/belt/bandolier,
+ /obj/item/weapon/gun/projectile/shotgun/combat,
+ /obj/item/weapon/gun/projectile/shotgun/combat)
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Ballistic gear crate"
+ access = access_armory
+ group = "Security"
+
+/datum/supply_packs/shotgunammo
+ name = "Shotgun shells"
+ contains = list(/obj/item/ammo_casing/shotgun,
+ /obj/item/ammo_casing/shotgun,
+ /obj/item/ammo_casing/shotgun,
+ /obj/item/ammo_casing/shotgun,
+ /obj/item/ammo_casing/shotgun,
+ /obj/item/ammo_casing/shotgun,
+ /obj/item/ammo_casing/shotgun,
+ /obj/item/ammo_casing/shotgun,
+ /obj/item/ammo_casing/shotgun,
+ /obj/item/ammo_casing/shotgun)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Shotgun shells"
+ access = access_armory
+ group = "Security"
+
+/datum/supply_packs/expenergy
+ name = "Experimental energy gear crate"
+ contains = list(/obj/item/clothing/suit/armor/laserproof,
+ /obj/item/clothing/suit/armor/laserproof,
+ /obj/item/weapon/gun/energy/gun,
+ /obj/item/weapon/gun/energy/gun)
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Experimental energy gear crate"
+ access = access_armory
+ group = "Security"
+
+/datum/supply_packs/exparmor
+ name = "Experimental armor crate"
+ contains = list(/obj/item/clothing/suit/armor/laserproof,
+ /obj/item/clothing/suit/armor/bulletproof,
+ /obj/item/clothing/head/helmet/riot,
+ /obj/item/clothing/suit/armor/riot)
+ cost = 35
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Experimental armor crate"
+ access = access_armory
+ group = "Security"
+
+/datum/supply_packs/securitybarriers
+ name = "Security Barriers"
+ contains = list(/obj/machinery/deployable/barrier,
+ /obj/machinery/deployable/barrier,
+ /obj/machinery/deployable/barrier,
+ /obj/machinery/deployable/barrier)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure/gear
+ containername = "Security Barriers crate"
+ group = "Security"
+
+/datum/supply_packs/securitybarriers
+ name = "Shield Generators"
+ contains = list(/obj/machinery/shieldwallgen,
+ /obj/machinery/shieldwallgen,
+ /obj/machinery/shieldwallgen,
+ /obj/machinery/shieldwallgen)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Shield Generators crate"
+ access = access_teleporter
+ group = "Security"
+
+/datum/supply_packs/randomised
+ var/num_contained = 3 //number of items picked to be contained in a randomised crate
+ contains = list(/obj/item/clothing/head/collectable/chef,
+ /obj/item/clothing/head/collectable/paper,
+ /obj/item/clothing/head/collectable/tophat,
+ /obj/item/clothing/head/collectable/captain,
+ /obj/item/clothing/head/collectable/beret,
+ /obj/item/clothing/head/collectable/welding,
+ /obj/item/clothing/head/collectable/flatcap,
+ /obj/item/clothing/head/collectable/pirate,
+ /obj/item/clothing/head/collectable/kitty,
+ /obj/item/clothing/head/collectable/rabbitears,
+ /obj/item/clothing/head/collectable/wizard,
+ /obj/item/clothing/head/collectable/hardhat,
+ /obj/item/clothing/head/collectable/HoS,
+ /obj/item/clothing/head/collectable/thunderdome,
+ /obj/item/clothing/head/collectable/swat,
+ /obj/item/clothing/head/collectable/slime,
+ /obj/item/clothing/head/collectable/police,
+ /obj/item/clothing/head/collectable/slime,
+ /obj/item/clothing/head/collectable/xenom,
+ /obj/item/clothing/head/collectable/petehat)
+ name = "Collectable hat crate!"
+ cost = 200
+ containertype = /obj/structure/closet/crate
+ containername = "Collectable hats crate! Brought to you by Bass.inc!"
+ group = "Operations"
+
+/datum/supply_packs/randomised/New()
+ manifest += "Contains any [num_contained] of:"
+ ..()
+
+/datum/supply_packs/artscrafts
+ name = "Arts and Crafts supplies"
+ contains = list(/obj/item/weapon/storage/fancy/crayons,
+ /obj/item/device/camera,
+ /obj/item/device/camera_film,
+ /obj/item/device/camera_film,
+ /obj/item/weapon/storage/photo_album,
+ /obj/item/weapon/packageWrap,
+ /obj/item/weapon/reagent_containers/glass/paint/red,
+ /obj/item/weapon/reagent_containers/glass/paint/green,
+ /obj/item/weapon/reagent_containers/glass/paint/blue,
+ /obj/item/weapon/reagent_containers/glass/paint/yellow,
+ /obj/item/weapon/reagent_containers/glass/paint/violet,
+ /obj/item/weapon/reagent_containers/glass/paint/black,
+ /obj/item/weapon/reagent_containers/glass/paint/white,
+ /obj/item/weapon/reagent_containers/glass/paint/remover,
+ /obj/item/weapon/contraband/poster,
+ /obj/item/weapon/wrapping_paper,
+ /obj/item/weapon/wrapping_paper,
+ /obj/item/weapon/wrapping_paper)
+ cost = 10
+ containertype = "/obj/structure/closet/crate"
+ containername = "Arts and Crafts crate"
+ group = "Operations"
+
+
+/datum/supply_packs/randomised/contraband
+ num_contained = 6
+ contains = list(/obj/item/weapon/storage/pill_bottle/zoom,
+ /obj/item/weapon/storage/pill_bottle/happy,
+ /obj/item/weapon/storage/pill_bottle/random_drug_bottle,
+ /obj/item/weapon/storage/fancy/cigarettes/dromedaryco,
+ /obj/item/weapon/storage/fancy/cigarettes/cigpack_shadyjims,
+ /obj/item/weapon/grenade/smokebomb,
+ /obj/item/clothing/mask/cigarette/cigar/cohiba,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/patron,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe,
+ /obj/item/weapon/lipstick/random)
+
+ name = "Contraband crate"
+ cost = 30
+ containertype = /obj/structure/closet/crate
+ containername = "Unlabeled crate"
+ contraband = 1
+ group = "Operations"
+
+/datum/supply_packs/boxes
+ name = "Empty Box supplies"
+ contains = list(/obj/item/weapon/storage/box,
+ /obj/item/weapon/storage/box,
+ /obj/item/weapon/storage/box,
+ /obj/item/weapon/storage/box,
+ /obj/item/weapon/storage/box,
+ /obj/item/weapon/storage/box,
+ /obj/item/weapon/storage/box,
+ /obj/item/weapon/storage/box,
+ /obj/item/weapon/storage/box,
+ /obj/item/weapon/storage/box)
+ cost = 10
+ containertype = "/obj/structure/closet/crate"
+ containername = "Empty Box crate"
+ group = "Operations"
+
+/datum/supply_packs/surgery
+ name = "Surgery crate"
+ contains = list(/obj/item/weapon/cautery,
+ /obj/item/weapon/surgicaldrill,
+ /obj/item/clothing/mask/breath/medical,
+ /obj/item/weapon/tank/anesthetic,
+ /obj/item/weapon/FixOVein,
+ /obj/item/weapon/hemostat,
+ /obj/item/weapon/scalpel,
+ /obj/item/weapon/bonegel,
+ /obj/item/weapon/retractor,
+ /obj/item/weapon/bonesetter,
+ /obj/item/weapon/circular_saw)
+ cost = 25
+ containertype = "/obj/structure/closet/crate/secure"
+ containername = "Surgery crate"
+ access = access_medical
+ group = "Medical / Science"
+
+/datum/supply_packs/sterile
+ name = "Sterile equipment crate"
+ contains = list(/obj/item/clothing/under/rank/medical/green,
+ /obj/item/clothing/under/rank/medical/green,
+ /obj/item/weapon/storage/box/masks,
+ /obj/item/weapon/storage/box/gloves)
+ cost = 15
+ containertype = "/obj/structure/closet/crate"
+ containername = "Sterile equipment crate"
+ group = "Medical / Science"
+
+/datum/supply_packs/randomised/pizza
+ num_contained = 5
+ contains = list(/obj/item/pizzabox/margherita,
+ /obj/item/pizzabox/mushroom,
+ /obj/item/pizzabox/meat,
+ /obj/item/pizzabox/vegetable)
+ name = "Surprise pack of five dozen pizzas"
+ cost = 15
+ containertype = /obj/structure/closet/crate/freezer
+ containername = "Pizza crate"
+ group = "Hospitality"
+
+/datum/supply_packs/foodcart
+ name = "Food Cart crate"
+ contains = list(/obj/structure/foodcart)
+ cost = 10
+ containertype = /obj/structure/largecrate
+ containername = "food cart crate"
+ group = "Hospitality"
+
+/datum/supply_packs/formal_wear
+ contains = list(/obj/item/clothing/head/that,
+ /obj/item/clothing/suit/storage/lawyer/bluejacket,
+ /obj/item/clothing/suit/storage/lawyer/purpjacket,
+ /obj/item/clothing/under/suit_jacket,
+ /obj/item/clothing/under/suit_jacket/female,
+ /obj/item/clothing/under/suit_jacket/really_black,
+ /obj/item/clothing/under/suit_jacket/red,
+ /obj/item/clothing/shoes/black,
+ /obj/item/clothing/shoes/black,
+ /obj/item/clothing/suit/wcoat)
+ name = "Formalwear closet"
+ cost = 30
+ containertype = /obj/structure/closet
+ containername = "Formalwear for the best occasions."
+ group = "Operations"
+/*
+/datum/supply_packs/rust_injector
+ contains = list(/obj/machinery/power/rust_fuel_injector)
+ name = "RUST fuel injector"
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure/large
+ containername = "RUST injector crate"
+ group = "Engineering"
+ access = access_engine
+/datum/supply_packs/rust_compressor
+ contains = list(/obj/item/weapon/module/rust_fuel_compressor)
+ name = "RUST fuel compressor circuitry"
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure
+ containername = "RUST fuel compressor circuitry"
+ group = "Engineering"
+ access = access_engine
+/datum/supply_packs/rust_assembly_port
+ contains = list(/obj/item/weapon/module/rust_fuel_port)
+ name = "RUST fuel assembly port circuitry"
+ cost = 40
+ containertype = /obj/structure/closet/crate/secure
+ containername = "RUST fuel assembly port circuitry"
+ group = "Engineering"
+ access = access_engine
+/datum/supply_packs/rust_core
+ contains = list(/obj/machinery/power/rust_core)
+ name = "RUST Tokamak Core"
+ cost = 75
+ containertype = /obj/structure/closet/crate/secure/large
+ containername = "RUST tokamak crate"
+ group = "Engineering"
+ access = access_engine
+*/
+/datum/supply_packs/shield_gen
+ contains = list(/obj/item/weapon/circuitboard/shield_gen)
+ name = "Experimental shield generator circuitry"
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Experimental shield generator"
+ group = "Engineering"
+ access = access_ce
+
+/datum/supply_packs/shield_cap
+ contains = list(/obj/item/weapon/circuitboard/shield_cap)
+ name = "Experimental shield capacitor circuitry"
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Experimental shield capacitor"
+ group = "Engineering"
+ access = access_ce
+
+/datum/supply_packs/eftpos
+ contains = list(/obj/item/device/eftpos)
+ name = "EFTPOS scanner"
+ cost = 10
+ containertype = /obj/structure/closet/crate
+ containername = "EFTPOS crate"
+ group = "Operations"
+
+/datum/supply_packs/teg
+ contains = list(/obj/machinery/power/generator)
+ name = "Mark I Thermoelectric Generator"
+ cost = 75
+ containertype = /obj/structure/closet/crate/secure/large
+ containername = "Mk1 TEG crate"
+ group = "Engineering"
+ access = access_engine
+
+/datum/supply_packs/circulator
+ contains = list(/obj/machinery/atmospherics/binary/circulator)
+ name = "Binary atmospheric circulator"
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure/large
+ containername = "Atmospheric circulator crate"
+ group = "Engineering"
+ access = access_engine
+
+/datum/supply_packs/bee_keeper
+ name = "Beekeeping Crate"
+ contains = list(/obj/item/beezeez,
+ /obj/item/beezeez,
+ /obj/item/weapon/bee_net,
+ /obj/item/apiary,
+ /obj/item/queen_bee,
+ /obj/item/queen_bee,
+ /obj/item/queen_bee)
+ cost = 20
+ containertype = /obj/structure/closet/crate/hydroponics
+ containername = "Beekeeping crate"
+ access = access_hydroponics
+ group = "Hydroponics"
+
+/datum/supply_packs/misc/lasertag
+ name = "Laser Tag Crate"
+ contains = list(/obj/item/weapon/gun/energy/laser/redtag,
+ /obj/item/weapon/gun/energy/laser/redtag,
+ /obj/item/weapon/gun/energy/laser/redtag,
+ /obj/item/weapon/gun/energy/laser/bluetag,
+ /obj/item/weapon/gun/energy/laser/bluetag,
+ /obj/item/weapon/gun/energy/laser/bluetag,
+ /obj/item/clothing/suit/redtag,
+ /obj/item/clothing/suit/redtag,
+ /obj/item/clothing/suit/redtag,
+ /obj/item/clothing/suit/bluetag,
+ /obj/item/clothing/suit/bluetag,
+ /obj/item/clothing/suit/bluetag,
+ /obj/item/clothing/head/helmet/redtaghelm,
+ /obj/item/clothing/head/helmet/bluetaghelm)
+ cost = 15
+ containertype = /obj/structure/closet/crate
+ containername = "laser tag crate"
+ group = "Operations"
+
+/datum/supply_packs/vending
+ name = "Bartending Supply Crate"
+ contains = list(/obj/item/weapon/vending_refill/boozeomat,
+ /obj/item/weapon/vending_refill/boozeomat,
+ /obj/item/weapon/vending_refill/boozeomat,
+ /obj/item/weapon/vending_refill/coffee,
+ /obj/item/weapon/vending_refill/coffee,
+ /obj/item/weapon/vending_refill/coffee)
+ cost = 15
+ containertype = /obj/structure/closet/crate
+ containername = "bartending supply crate"
+ group = "Operations"
+
+/datum/supply_packs/vending/snack
+ name = "Snack Supply Crate"
+ contains = list(/obj/item/weapon/vending_refill/snack,
+ /obj/item/weapon/vending_refill/snack,
+ /obj/item/weapon/vending_refill/snack)
+ cost = 15
+ containertype = /obj/structure/closet/crate
+ containername = "snacks supply crate"
+ group = "Operations"
+
+/datum/supply_packs/vending/cola
+ name = "Softdrinks Supply Crate"
+ contains = list(/obj/item/weapon/vending_refill/cola,
+ /obj/item/weapon/vending_refill/cola,
+ /obj/item/weapon/vending_refill/cola)
+ cost = 15
+ containertype = /obj/structure/closet/crate
+ containername = "softdrinks supply crate"
+ group = "Operations"
+
+/datum/supply_packs/vending/cigarette
+ name = "Cigarette Supply Crate"
+ contains = list(/obj/item/weapon/vending_refill/cigarette,
+ /obj/item/weapon/vending_refill/cigarette,
+ /obj/item/weapon/vending_refill/cigarette)
+ cost = 15
+ containertype = /obj/structure/closet/crate
+ containername = "cigarette supply crate"
+ group = "Operations"
+
+/datum/supply_packs/autodrobe
+ name = "Autodrobe Supply crate"
+ contains = list(/obj/item/weapon/vending_refill/autodrobe,
+ /obj/item/weapon/vending_refill/autodrobe,
+ /obj/item/weapon/vending_refill/autodrobe)
+ cost = 15
+ containertype = /obj/structure/closet/crate
+ containername = "autodrobe supply crate"
+ group = "Operations"
+
+/datum/supply_packs/clothingvendor
+ name = "Clothing Vendor Supply crate"
+ contains = list(/obj/item/weapon/vending_refill/hatdispenser,
+ /obj/item/weapon/vending_refill/hatdispenser,
+ /obj/item/weapon/vending_refill/hatdispenser,
+ /obj/item/weapon/vending_refill/suitdispenser,
+ /obj/item/weapon/vending_refill/suitdispenser,
+ /obj/item/weapon/vending_refill/suitdispenser,
+ /obj/item/weapon/vending_refill/shoedispenser,
+ /obj/item/weapon/vending_refill/shoedispenser,
+ /obj/item/weapon/vending_refill/shoedispenser)
+ cost = 30
+ containertype = /obj/structure/closet/crate
+ containername = "clothing vendor supply crate"
+ group = "Operations"
+
+/datum/supply_packs/mafia
+ name = "Mafia Supply crate"
+ contains = list(/obj/item/clothing/suit/browntrenchcoat =1,/obj/item/clothing/suit/blacktrenchcoat =1,/obj/item/clothing/head/fedora/whitefedora =1,
+ /obj/item/clothing/head/fedora/brownfedora =1,/obj/item/clothing/head/fedora =1,/obj/item/clothing/under/flappers =1,/obj/item/clothing/under/mafia =1,/obj/item/clothing/under/mafia/vest =1,/obj/item/clothing/under/mafia/white =1,
+ /obj/item/clothing/under/mafia/sue =1,/obj/item/clothing/under/mafia/tan =1, /obj/item/toy/crossbow/tommygun =2)
+ cost = 15
+ containertype = /obj/structure/closet/crate
+ containername = "mafia supply crate"
+ group = "Operations"
+
+/datum/supply_packs/fabric
+ name = "Fabric crate"
+ contains = list(/obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric,
+ /obj/item/weapon/ore/fabric)
+ cost = 30
+ containertype = /obj/structure/closet/crate
+ containername = "Fabric crate"
+ group = "Operations"
\ No newline at end of file
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 596ed5e9d97..02924c8657d 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -386,7 +386,7 @@
thunk(L)
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
- if(L && L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))
+ if(L && L.client && (L.client.prefs.sound & SOUND_AMBIENCE))
if(!L.client.ambience_playing)
L.client.ambience_playing = 1
L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = 2)
diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm
index d4b1a0d44a6..e028702a44e 100644
--- a/code/game/dna/dna2.dm
+++ b/code/game/dna/dna2.dm
@@ -163,7 +163,7 @@ var/global/list/bad_blocks[0]
// Set a DNA UI block's raw value.
/datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0)
if (block<=0) return
- ASSERT(value>=0)
+ ASSERT(value>0)
ASSERT(value<=4095)
UI[block]=value
dirtyUI=1
@@ -178,7 +178,10 @@ var/global/list/bad_blocks[0]
// Set a DNA UI block's value, given a value and a max possible value.
// Used in hair and facial styles (value being the index and maxvalue being the len of the hairstyle list)
/datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue,var/defer=0)
- if (block<=0) return
+ if (block<=0)
+ return
+ if(value == 0)
+ value = 1
ASSERT(maxvalue<=4095)
var/range = (4095 / maxvalue)
if(value)
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index 27bae141374..76d198d796f 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -9,7 +9,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
config_tag = "changeling"
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Blueshield", "Nanotrasen Representative", "Security Pod Pilot", "Magistrate", "Brig Physician", "Internal Affairs Agent")
- protected_species = list("Machine")
+ protected_species = list("Machine", "Slime People")
required_players = 2
required_players_secret = 10
required_enemies = 1
@@ -90,31 +90,53 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
var/datum/objective/absorb/absorb_objective = new
absorb_objective.owner = changeling
- absorb_objective.gen_amount_goal(2, 3)
+ absorb_objective.gen_amount_goal(6, 8)
changeling.objectives += absorb_objective
- var/datum/objective/assassinate/kill_objective = new
- kill_objective.owner = changeling
- kill_objective.find_target()
- changeling.objectives += kill_objective
+ if(prob(60))
+ var/datum/objective/steal/steal_objective = new
+ steal_objective.owner = changeling
+ steal_objective.find_target()
+ changeling.objectives += steal_objective
+ else
+ var/datum/objective/debrain/debrain_objective = new
+ debrain_objective.owner = changeling
+ debrain_objective.find_target()
+ changeling.objectives += debrain_objective
- var/datum/objective/steal/steal_objective = new
- steal_objective.owner = changeling
- steal_objective.find_target()
- changeling.objectives += steal_objective
+ var/list/active_ais = active_ais()
+ if(active_ais.len && prob(4)) // Leaving this at a flat chance for now, problems with the num_players() proc due to latejoin antags.
+ var/datum/objective/destroy/destroy_objective = new
+ destroy_objective.owner = changeling
+ destroy_objective.find_target()
+ changeling.objectives += destroy_objective
+ else
+ var/datum/objective/assassinate/kill_objective = new
+ kill_objective.owner = changeling
+ kill_objective.find_target()
+ changeling.objectives += kill_objective
+ if (!(locate(/datum/objective/escape) in changeling.objectives))
+ var/datum/objective/escape/escape_with_identity/identity_theft = new
+ identity_theft.owner = changeling
+ identity_theft.target = kill_objective.target
+ if(identity_theft.target && identity_theft.target.current)
+ var/target_real_name = identity_theft.target.current.real_name
+ identity_theft.explanation_text = "Escape on the shuttle or an escape pod with the identity of [target_real_name], the [identity_theft.target.assigned_role] while wearing their identification card."
+ else
+ identity_theft.explanation_text = "Free objective"
+ changeling.objectives += identity_theft
- switch(rand(1,100))
- if(1 to 80)
- if (!(locate(/datum/objective/escape) in changeling.objectives))
- var/datum/objective/escape/escape_objective = new
- escape_objective.owner = changeling
- changeling.objectives += escape_objective
+ if (!(locate(/datum/objective/escape) in changeling.objectives))
+ if(prob(70))
+ var/datum/objective/escape/escape_objective = new
+ escape_objective.owner = changeling
+ changeling.objectives += escape_objective
else
- if (!(locate(/datum/objective/survive) in changeling.objectives))
- var/datum/objective/survive/survive_objective = new
- survive_objective.owner = changeling
- changeling.objectives += survive_objective
+ var/datum/objective/escape/escape_with_identity/identity_theft = new
+ identity_theft.owner = changeling
+ identity_theft.find_target()
+ changeling.objectives += identity_theft
return
/datum/game_mode/proc/greet_changeling(var/datum/mind/changeling, var/you_are=1)
@@ -162,7 +184,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
/datum/game_mode/proc/auto_declare_completion_changeling()
if(changelings.len)
- var/text = "The changelings were:"
+ var/text = "The changelings were:"
for(var/datum/mind/changeling in changelings)
var/changelingwin = 1
@@ -181,7 +203,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
//Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
text += "
Changeling ID: [changeling.changeling.changelingID]."
- text += "
Genomes Absorbed: [changeling.changeling.absorbedcount]"
+ text += "
Genomes Extracted: [changeling.changeling.absorbedcount]"
if(changeling.objectives.len)
var/count = 1
@@ -209,19 +231,25 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
/datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind)
var/list/absorbed_dna = list()
- var/list/absorbed_species = list()
var/list/absorbed_languages = list()
- var/absorbedcount = 0
+ var/list/protected_dna = list() //DNA that is not lost when capacity is otherwise full.
+ var/dna_max = 4 //How many extra DNA strands the changeling can store for transformation.
+ var/absorbedcount = 1 //Would require at least 1 sample to take on the form of a human
var/chem_charges = 20
var/chem_recharge_rate = 0.5
+ var/chem_recharge_slowdown = 0
var/chem_storage = 50
- var/sting_range = 1
+ var/sting_range = 2
var/changelingID = "Changeling"
var/geneticdamage = 0
var/isabsorbing = 0
- var/geneticpoints = 5
+ var/geneticpoints = 10
var/purchasedpowers = list()
var/mimicing = ""
+ var/canrespec = 0
+ var/changeling_speak = 0
+ var/datum/dna/chosen_dna
+ var/obj/effect/proc_holder/changeling/sting/chosen_sting
/datum/changeling/New(var/gender=FEMALE)
..()
@@ -234,16 +262,61 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
changelingID = "[honorific] [changelingID]"
else
changelingID = "[honorific] [rand(1,999)]"
+ absorbed_dna.len = dna_max
/datum/changeling/proc/regenerate()
- chem_charges = min(max(0, chem_charges+chem_recharge_rate), chem_storage)
+ chem_charges = min(max(0, chem_charges + chem_recharge_rate - chem_recharge_slowdown), chem_storage)
geneticdamage = max(0, geneticdamage-1)
/datum/changeling/proc/GetDNA(var/dna_owner)
- var/datum/dna/chosen_dna
- for(var/datum/dna/DNA in absorbed_dna)
+ for(var/datum/dna/DNA in (absorbed_dna + protected_dna))
if(dna_owner == DNA.real_name)
- chosen_dna = DNA
- break
- return chosen_dna
+ return DNA
+
+/datum/changeling/proc/has_dna(var/datum/dna/tDNA)
+ for(var/datum/dna/D in (absorbed_dna + protected_dna))
+ if(tDNA.unique_enzymes == D.unique_enzymes && tDNA.uni_identity == D.uni_identity && tDNA.species == D.species)
+ return 1
+ return 0
+
+/datum/changeling/proc/can_absorb_dna(var/mob/living/carbon/user, var/mob/living/carbon/target)
+ if(absorbed_dna[1] == user.dna)//If our current DNA is the stalest, we gotta ditch it.
+ user << "We have reached our capacity to store genetic information! We must transform before absorbing more."
+ return
+
+ if(!target || !target.dna)
+ user << "This creature does not have any DNA."
+ return
+
+ var/mob/living/carbon/human/T = target
+ if(!istype(T))
+ user << "[T] is not compatible with our biology."
+ return
+
+ if((M_NOCLONE || SKELETON || M_HUSK) in T.mutations)
+ user << "DNA of [target] is ruined beyond usability!"
+ return
+
+ if(T.species.flags & IS_SYNTHETIC)
+ user << "This creature does not have DNA!"
+ return
+
+ if(T.species.flags & NO_SCAN)
+ user << "We do not know how to parse this creature's DNA!"
+ return
+
+ if(has_dna(target.dna))
+ user << "We already have this DNA in storage!"
+
+ return 1
+
+//More snowflake stuff, but for languages.
+/datum/changeling/proc/changeling_update_languages(var/updated_languages, var/mob/living/carbon/user)
+ if(!istype(user) || !user)
+ return
+ user.languages = list()
+ for(var/language in updated_languages)
+ user.languages += language
+
+ return
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/changeling_power.dm b/code/game/gamemodes/changeling/changeling_power.dm
new file mode 100644
index 00000000000..36df179ae32
--- /dev/null
+++ b/code/game/gamemodes/changeling/changeling_power.dm
@@ -0,0 +1,79 @@
+/*
+ * Don't use the apostrophe in name or desc. Causes script errors.
+ * TODO: combine atleast some of the functionality with /proc_holder/spell
+ */
+
+/obj/effect/proc_holder/changeling
+ panel = "Changeling"
+ name = "Prototype Sting"
+ desc = "" // Fluff
+ var/helptext = "" // Details
+ var/chemical_cost = 0 // negative chemical cost is for passive abilities (chemical glands)
+ var/dna_cost = -1 //cost of the sting in dna points. 0 = auto-purchase, -1 = cannot be purchased
+ var/req_dna = 0 //amount of dna needed to use this ability. Changelings always have atleast 1
+ var/req_human = 0 //if you need to be human to use this ability
+ var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
+ var/genetic_damage = 0 // genetic damage caused by using the sting. Nothing to do with cloneloss.
+ var/max_genetic_damage = 100 // hard counter for spamming abilities. Not used/balanced much yet.
+
+/obj/effect/proc_holder/changeling/proc/on_purchase(var/mob/user)
+ return
+
+/obj/effect/proc_holder/changeling/Click()
+ var/mob/user = usr
+ if(!user || !user.mind || !user.mind.changeling)
+ return
+ try_to_sting(user)
+
+/obj/effect/proc_holder/changeling/proc/try_to_sting(var/mob/user, var/mob/target)
+ if(!user.mind || !user.mind.changeling)
+ return
+ if(!can_sting(user, target))
+ return
+ var/datum/changeling/c = user.mind.changeling
+ if(sting_action(user, target))
+ sting_feedback(user, target)
+ take_chemical_cost(c)
+
+/obj/effect/proc_holder/changeling/proc/sting_action(var/mob/user, var/mob/target)
+ return 0
+
+/obj/effect/proc_holder/changeling/proc/sting_feedback(var/mob/user, var/mob/target)
+ return 0
+
+/obj/effect/proc_holder/changeling/proc/take_chemical_cost(var/datum/changeling/changeling)
+ changeling.chem_charges -= chemical_cost
+ changeling.geneticdamage += genetic_damage
+
+//Fairly important to remember to return 1 on success >.<
+/obj/effect/proc_holder/changeling/proc/can_sting(var/mob/user, var/mob/target)
+ if(!ishuman(user) && !ismonkey(user)) //typecast everything from mob to carbon from this point onwards
+ return 0
+ if(req_human && !ishuman(user))
+ user << "We cannot do that in this form!"
+ return 0
+ var/datum/changeling/c = user.mind.changeling
+ if(c.chem_chargesWe require at least [chemical_cost] unit\s of chemicals to do that!"
+ return 0
+ if(c.absorbedcountWe require at least [req_dna] sample\s of compatible DNA."
+ return 0
+ if(req_stat < user.stat)
+ user << "We are incapacitated."
+ return 0
+ if((user.status_flags & FAKEDEATH) && name!="Regenerate")
+ user << "We are incapacitated."
+ return 0
+ if(c.geneticdamage > max_genetic_damage)
+ user << "Our genomes are still reassembling. We need time to recover first."
+ return 0
+ return 1
+
+//used in /mob/Stat()
+/obj/effect/proc_holder/changeling/proc/can_be_used_by(var/mob/user)
+ if(!ishuman(user) && !ismonkey(user))
+ return 0
+ if(req_human && !ishuman(user))
+ return 0
+ return 1
diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm
deleted file mode 100644
index c6df778144d..00000000000
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ /dev/null
@@ -1,944 +0,0 @@
-//Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human
-/mob/proc/make_changeling()
-
- if(!mind) return
- if(!mind.changeling) mind.changeling = new /datum/changeling(gender)
- if(!ishuman(src) && !ismonkey(src)) return
- verbs += /datum/changeling/proc/EvolutionMenu
-
- var/lesser_form = !ishuman(src)
-
- if(!powerinstances.len)
- for(var/P in powers)
- powerinstances += new P()
-
- // Code to auto-purchase free powers.
- for(var/datum/power/changeling/P in powerinstances)
- if(!P.genomecost) // Is it free?
- if(!(P in mind.changeling.purchasedpowers)) // Do we not have it already?
- mind.changeling.purchasePower(mind, P.name, 0)// Purchase it. Don't remake our verbs, we're doing it after this.
-
- for(var/datum/power/changeling/P in mind.changeling.purchasedpowers)
- if(P.isVerb)
- if(lesser_form && !P.allowduringlesserform) continue
- if(!(P in src.verbs))
- src.verbs += P.verbpath
-
- mind.changeling.absorbed_dna |= dna
-
- var/mob/living/carbon/human/H = src
- if(istype(H))
- mind.changeling.absorbed_species += H.species.name
-
- for(var/language in languages)
- if(!(language in mind.changeling.absorbed_languages))
- mind.changeling.absorbed_languages += language
-
- return 1
-
-//removes our changeling verbs
-/mob/proc/remove_changeling_powers()
- if(!mind || !mind.changeling) return
- for(var/datum/power/changeling/P in mind.changeling.purchasedpowers)
- if(P.isVerb)
- verbs -= P.verbpath
-
-
-//Helper proc. Does all the checks and stuff for us to avoid copypasta
-/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0)
-
- if(!src.mind) return
- if(!iscarbon(src)) return
-
- var/datum/changeling/changeling = src.mind.changeling
- if(!changeling)
- world.log << "[src] has the changeling_transform() verb but is not a changeling."
- return
-
- if(src.stat > max_stat)
- src << "We are incapacitated."
- return
-
- if(changeling.absorbed_dna.len < required_dna)
- src << "We require at least [required_dna] samples of compatible DNA."
- return
-
- if(changeling.chem_charges < required_chems)
- src << "We require at least [required_chems] units of chemicals to do that!"
- return
-
- if(changeling.geneticdamage > max_genetic_damage)
- src << "Our geneomes are still reassembling. We need time to recover first."
- return
-
- return changeling
-
-
-//Used to dump the languages from the changeling datum into the actual mob.
-/mob/proc/changeling_update_languages(var/updated_languages)
-
- languages = list()
- for(var/language in updated_languages)
- languages += language
-
- return
-
-//Used to switch species based on the changeling datum.
-/mob/proc/changeling_change_species()
-
- set category = "Changeling"
- set name = "Change Species (5)"
-
- var/mob/living/carbon/human/H = src
- if(!istype(H))
- src << "We may only use this power while in humanoid form."
- return
-
- var/datum/changeling/changeling = changeling_power(5,1,0)
- if(!changeling) return
-
- if(changeling.absorbed_species.len < 2)
- src << "We do not know of any other species genomes to use."
- return
-
- var/S = input("Select the target species: ", "Target Species", null) as null|anything in changeling.absorbed_species
- if(!S) return
-
- domutcheck(src, null)
-
- changeling.chem_charges -= 5
- changeling.geneticdamage = 30
-
- src.visible_message("[src] transforms!")
-
- src.verbs -= /mob/proc/changeling_change_species
- H.set_species(S,null,1) //Until someone moves body colour into DNA, they're going to have to use the default.
-
- spawn(10)
- src.verbs += /mob/proc/changeling_change_species
- src.regenerate_icons()
-
- changeling_update_languages(changeling.absorbed_languages)
- feedback_add_details("changeling_powers","TR")
-
- return 1
-
-//Absorbs the victim's DNA making them uncloneable. Requires a strong grip on the victim.
-//Doesn't cost anything as it's the most basic ability.
-/mob/proc/changeling_absorb_dna()
- set category = "Changeling"
- set name = "Absorb DNA"
-
- var/datum/changeling/changeling = changeling_power(0,0,100)
- if(!changeling) return
-
- var/obj/item/weapon/grab/G = src.get_active_hand()
- if(!istype(G))
- src << "We must be grabbing a creature in our active hand to absorb them."
- return
-
- var/mob/living/carbon/human/T = G.affecting
- if(!istype(T))
- src << "[T] is not compatible with our biology."
- return
-
- if(T.species.flags & NO_SCAN)
- src << "We do not know how to parse this creature's DNA!"
- return
-
- if((M_NOCLONE || SKELETON) in T.mutations)
- src << "This creature's DNA is ruined beyond useability!"
- return
-
- if(!G.state == GRAB_KILL)
- src << "We must have a tighter grip to absorb this creature."
- return
-
- if(changeling.isabsorbing)
- src << "We are already absorbing!"
- return
-
- changeling.isabsorbing = 1
- for(var/stage = 1, stage<=3, stage++)
- switch(stage)
- if(1)
- src << "This creature is compatible. We must hold still..."
- if(2)
- src << "We extend a proboscis."
- src.visible_message("[src] extends a proboscis!")
- if(3)
- src << "We stab [T] with the proboscis."
- src.visible_message("[src] stabs [T] with the proboscis!")
- T << "You feel a sharp stabbing pain!"
- var/datum/organ/external/affecting = T.get_organ(src.zone_sel.selecting)
- if(affecting.take_damage(39,0,1,0,"large organic needle"))
- T:UpdateDamageIcon()
- continue
-
- feedback_add_details("changeling_powers","A[stage]")
- if(!do_mob(src, T, 150))
- src << "Our absorption of [T] has been interrupted!"
- changeling.isabsorbing = 0
- return
-
- src << "We have absorbed [T]!"
- src.visible_message("[src] sucks the fluids from [T]!")
- T << "You have been absorbed by the changeling!"
-
- T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set.
- changeling.absorbed_dna |= T.dna
- if(src.nutrition < 400) src.nutrition = min((src.nutrition + T.nutrition), 400)
-
- changeling.chem_charges += 10
- changeling.geneticpoints += 2
-
- //Steal all of their languages!
- for(var/language in T.languages)
- if(!(language in changeling.absorbed_languages))
- changeling.absorbed_languages += language
-
- changeling_update_languages(changeling.absorbed_languages)
-
- //Steal their species!
- if(T.species && !(T.species.name in changeling.absorbed_species))
- changeling.absorbed_species += T.species.name
-
- if(T.mind && T.mind.changeling)
- if(T.mind.changeling.absorbed_dna)
- for(var/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot
- if(dna_data in changeling.absorbed_dna)
- continue
- changeling.absorbed_dna += dna_data
- changeling.absorbedcount++
- T.mind.changeling.absorbed_dna.len = 1
-
- if(T.mind.changeling.purchasedpowers)
- for(var/datum/power/changeling/Tp in T.mind.changeling.purchasedpowers)
- if(Tp in changeling.purchasedpowers)
- continue
- else
- changeling.purchasedpowers += Tp
-
- if(!Tp.isVerb)
- call(Tp.verbpath)()
- else
- changeling.purchasedpowers += Tp
-
- if(!Tp.isVerb)
- call(Tp.verbpath)()
- else
- src.make_changeling()
-
- changeling.chem_charges += T.mind.changeling.chem_charges
- changeling.geneticpoints += T.mind.changeling.geneticpoints
- T.mind.changeling.chem_charges = 0
- T.mind.changeling.geneticpoints = 0
- T.mind.changeling.absorbedcount = 0
-
- changeling.absorbedcount++
- changeling.isabsorbing = 0
-
- T.death(0)
- T.Drain()
- return 1
-
-
-//Change our DNA to that of somebody we've absorbed.
-/mob/proc/changeling_transform()
- set category = "Changeling"
- set name = "Transform (5)"
-
- var/datum/changeling/changeling = changeling_power(5,1,0)
- if(!changeling) return
-
- var/list/names = list()
- for(var/datum/dna/DNA in changeling.absorbed_dna)
- names += "[DNA.real_name]"
-
- var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names
- if(!S) return
-
- var/datum/dna/chosen_dna = changeling.GetDNA(S)
- if(!chosen_dna)
- return
-
- changeling.chem_charges -= 5
- src.visible_message("[src] transforms!")
- changeling.geneticdamage = 30
- src.dna = chosen_dna.Clone()
- src.real_name = chosen_dna.real_name
- src.flavor_text = ""
- if(ishuman(src))
- var/mob/living/carbon/human/H = src
- H.set_species()
- src.UpdateAppearance()
- domutcheck(src, null)
-
- src.verbs -= /mob/proc/changeling_transform
- spawn(10) src.verbs += /mob/proc/changeling_transform
-
- feedback_add_details("changeling_powers","TR")
- return 1
-
-
-//Transform into a monkey.
-/mob/proc/changeling_lesser_form()
- set category = "Changeling"
- set name = "Lesser Form (1)"
-
- var/datum/changeling/changeling = changeling_power(1,0,0)
- if(!changeling) return
-
- if(src.has_brain_worms())
- src << "We cannot perform this ability at the present time!"
- return
-
- var/mob/living/carbon/C = src
- changeling.chem_charges--
- C.remove_changeling_powers()
- C.visible_message("[C] transforms!")
- changeling.geneticdamage = 30
- C << "Our genes cry out!"
-
- //TODO replace with monkeyize proc
- var/list/implants = list() //Try to preserve implants.
- for(var/obj/item/weapon/implant/W in C)
- implants += W
-
- C.monkeyizing = 1
- C.canmove = 0
- C.icon = null
- C.overlays.Cut()
- C.invisibility = 101
-
- var/atom/movable/overlay/animation = new /atom/movable/overlay( C.loc )
- animation.icon_state = "blank"
- animation.icon = 'icons/mob/mob.dmi'
- animation.master = src
- flick("h2monkey", animation)
- sleep(48)
- del(animation)
-
- var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey(src)
- O.dna = C.dna.Clone()
- C.dna = null
-
- for(var/obj/item/W in C)
- C.drop_from_inventory(W)
- for(var/obj/T in C)
- del(T)
-
- O.loc = C.loc
- O.name = "monkey ([copytext(md5(C.real_name), 2, 6)])"
- O.setToxLoss(C.getToxLoss())
- O.adjustBruteLoss(C.getBruteLoss())
- O.setOxyLoss(C.getOxyLoss())
- O.adjustFireLoss(C.getFireLoss())
- O.stat = C.stat
- O.a_intent = "harm"
- for(var/obj/item/weapon/implant/I in implants)
- I.loc = O
- I.implanted = O
-
- C.mind.transfer_to(O)
-
- O.make_changeling(1)
- O.verbs += /mob/proc/changeling_lesser_transform
- O.changeling_update_languages(changeling.absorbed_languages)
-
- feedback_add_details("changeling_powers","LF")
- del(C)
- return 1
-
-
-//Transform into a human
-/mob/proc/changeling_lesser_transform()
- set category = "Changeling"
- set name = "Transform (1)"
-
- var/datum/changeling/changeling = changeling_power(1,1,0)
- if(!changeling) return
-
- var/list/names = list()
- for(var/datum/dna/DNA in changeling.absorbed_dna)
- names += "[DNA.real_name]"
-
- var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names
- if(!S) return
-
- var/datum/dna/chosen_dna = changeling.GetDNA(S)
- if(!chosen_dna)
- return
-
- var/mob/living/carbon/C = src
-
- changeling.chem_charges--
- C.remove_changeling_powers()
- C.visible_message("[C] transforms!")
- C.dna = chosen_dna.Clone()
-
- var/list/implants = list()
- for (var/obj/item/weapon/implant/I in C) //Still preserving implants
- implants += I
-
- C.monkeyizing = 1
- C.canmove = 0
- C.icon = null
- C.overlays.Cut()
- C.invisibility = 101
- var/atom/movable/overlay/animation = new /atom/movable/overlay( C.loc )
- animation.icon_state = "blank"
- animation.icon = 'icons/mob/mob.dmi'
- animation.master = src
- flick("monkey2h", animation)
- sleep(48)
- del(animation)
-
- for(var/obj/item/W in src)
- C.u_equip(W)
- if (C.client)
- C.client.screen -= W
- if (W)
- W.loc = C.loc
- W.dropped(C)
- W.layer = initial(W.layer)
-
- var/mob/living/carbon/human/O = new /mob/living/carbon/human( src, delay_ready_dna=1 )
- if (C.dna.GetUIState(DNA_UI_GENDER))
- O.gender = FEMALE
- else
- O.gender = MALE
- O.dna = C.dna.Clone()
- C.dna = null
- O.real_name = chosen_dna.real_name
- O.set_species()
- for(var/obj/T in C)
- del(T)
-
- O.loc = C.loc
-
- O.UpdateAppearance()
- domutcheck(O, null)
- O.setToxLoss(C.getToxLoss())
- O.adjustBruteLoss(C.getBruteLoss())
- O.setOxyLoss(C.getOxyLoss())
- O.adjustFireLoss(C.getFireLoss())
- O.stat = C.stat
- for (var/obj/item/weapon/implant/I in implants)
- I.loc = O
- I.implanted = O
-
- C.mind.transfer_to(O)
- O.make_changeling()
- O.changeling_update_languages(changeling.absorbed_languages)
-
- feedback_add_details("changeling_powers","LFT")
- del(C)
- return 1
-
-
-//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay.
-/*
-/mob/verb/honk()
- set name = "OH HOLY FUCK"
- set category = "Debug"
- var/yes = 0
- if(src in mob_list)
- yes = 1
- else
- var/mob/M = locate(src) in mob_list
- if(M == src)
- yes = 1
- usr << "[yes ? "\blue" : "\red"] You are [yes ? "" : "not "]in the mob list"
-*/
-/mob/proc/changeling_returntolife()
- set category = "Changeling"
- set name = "Return To Life (20)"
- var/datum/changeling/changeling = changeling_power(20,1,100,DEAD)
- if(!changeling) return
-
- var/mob/living/carbon/C = src
- if(changeling_power(20,1,100,DEAD))
- changeling.chem_charges -= 20
- dead_mob_list -= C
- living_mob_list |= C
- C.stat = CONSCIOUS
- C.tod = null
- C.setToxLoss(0)
- C.setOxyLoss(0)
- C.setCloneLoss(0)
- C.setBrainLoss(0)
- C.SetParalysis(0)
- C.SetStunned(0)
- C.SetWeakened(0)
- C.radiation = 0
- C.heal_overall_damage(C.getBruteLoss(), C.getFireLoss())
- C.reagents.clear_reagents()
- C.germ_level = 0
- C.next_pain_time = 0
- C.traumatic_shock = 0
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- H.vessel.reagent_list = list()
- H.vessel.add_reagent("blood",560)
- H.shock_stage = 0
- spawn(1)
- H.fixblood()
- for(var/organ_name in H.organs_by_name)
- var/datum/organ/external/O = H.organs_by_name[organ_name]
- for(var/obj/item/weapon/shard/shrapnel/s in O.implants)
- if(istype(s))
- O.implants -= s
- H.contents -= s
- del(s)
- O.amputated = 0
- O.brute_dam = 0
- O.burn_dam = 0
- O.damage_state = "00"
- O.germ_level = 0
- O.hidden = null
- O.number_wounds = 0
- O.open = 0
- O.perma_injury = 0
- O.stage = 0
- O.status = 0
- O.trace_chemicals = list()
- O.wounds = list()
- O.wound_update_accuracy = 1
- for(var/n in H.internal_organs_by_name)
- var/datum/organ/internal/IO = H.internal_organs_by_name[n]
- IO.damage = 0
- IO.trace_chemicals = list()
- H.updatehealth()
- C << "We have regenerated."
- C.visible_message("[src] appears to wake from the dead, having healed all wounds.")
- C.status_flags &= ~(FAKEDEATH)
- C.update_canmove()
- C.make_changeling()
- src.verbs -= /mob/proc/changeling_returntolife
- feedback_add_details("changeling_powers","RJ")
-
-/mob/proc/changeling_fakedeath()
- set category = "Changeling"
- set name = "Regenerative Stasis (20)"
-
- var/datum/changeling/changeling = changeling_power(20,1,100,DEAD)
- if(!changeling) return
-
- var/mob/living/carbon/C = src
- if(!C.stat && alert("Are we sure we wish to fake our death?",,"Yes","No") == "No")//Confirmation for living changelings if they want to fake their death
- return
- C << "We will attempt to regenerate our form."
-
- C.status_flags |= FAKEDEATH //play dead
- C.update_canmove()
- C.remove_changeling_powers()
-
- C.emote("deathgasp")
- C.tod = worldtime2text()
-
- spawn(rand(800,1200))
- src << "We are now ready to regenerate."
- src.verbs += /mob/proc/changeling_returntolife
- feedback_add_details("changeling_powers","FD")
- return 1
-
-
-//Boosts the range of your next sting attack by 1
-/mob/proc/changeling_boost_range()
- set category = "Changeling"
- set name = "Ranged Sting (10)"
- set desc="Your next sting ability can be used against targets 2 squares away."
-
- var/datum/changeling/changeling = changeling_power(10,0,100)
- if(!changeling) return 0
- changeling.chem_charges -= 10
- src << "Your throat adjusts to launch the sting."
- changeling.sting_range = 2
- src.verbs -= /mob/proc/changeling_boost_range
- spawn(5) src.verbs += /mob/proc/changeling_boost_range
- feedback_add_details("changeling_powers","RS")
- return 1
-
-
-//Recover from stuns.
-/mob/proc/changeling_unstun()
- set category = "Changeling"
- set name = "Epinephrine Sacs (45)"
- set desc = "Removes all stuns"
-
- var/datum/changeling/changeling = changeling_power(45,0,100,UNCONSCIOUS)
- if(!changeling) return 0
- changeling.chem_charges -= 45
-
- var/mob/living/carbon/human/C = src
- C.stat = 0
- C.SetParalysis(0)
- C.SetStunned(0)
- C.SetWeakened(0)
- C.adjustStaminaLoss(-75)
- C.reagents.add_reagent("synaptizine", 20)
- C.lying = 0
- C.update_canmove()
-
- src.verbs -= /mob/proc/changeling_unstun
- spawn(5) src.verbs += /mob/proc/changeling_unstun
- feedback_add_details("changeling_powers","UNS")
- return 1
-
-
-//Speeds up chemical regeneration
-/mob/proc/changeling_fastchemical()
- src.mind.changeling.chem_recharge_rate *= 2
- return 1
-
-//Increases macimum chemical storage
-/mob/proc/changeling_engorgedglands()
- src.mind.changeling.chem_storage += 25
- return 1
-
-
-//Prevents AIs tracking you but makes you easily detectable to the human-eye.
-/mob/proc/changeling_digitalcamo()
- set category = "Changeling"
- set name = "Toggle Digital Camoflague"
- set desc = "The AI can no longer track us, but we will look different if examined. Has a constant cost while active."
-
- var/datum/changeling/changeling = changeling_power()
- if(!changeling) return 0
-
- var/mob/living/carbon/human/C = src
- if(C.digitalcamo) C << "We return to normal."
- else C << "We distort our form to prevent AI-tracking."
- C.digitalcamo = !C.digitalcamo
-
- spawn(0)
- while(C && C.digitalcamo && C.mind && C.mind.changeling)
- C.mind.changeling.chem_charges = max(C.mind.changeling.chem_charges - 1, 0)
- sleep(40)
-
- src.verbs -= /mob/proc/changeling_digitalcamo
- spawn(5) src.verbs += /mob/proc/changeling_digitalcamo
- feedback_add_details("changeling_powers","CAM")
- return 1
-
-
-//Starts healing you every second for 10 seconds. Can be used whilst unconscious.
-/mob/proc/changeling_rapidregen()
- set category = "Changeling"
- set name = "Rapid Regeneration (30)"
- set desc = "Begins rapidly regenerating. Does not effect stuns or chemicals."
-
- var/datum/changeling/changeling = changeling_power(30,0,100,UNCONSCIOUS)
- if(!changeling) return 0
- src.mind.changeling.chem_charges -= 30
-
- var/mob/living/carbon/human/C = src
- if(ishuman(src))
- var/mob/living/carbon/human/H=src
- if(H.said_last_words)
- H.said_last_words=0
-
- spawn(0)
- for(var/i = 0, i<10,i++)
- if(C)
- C.adjustBruteLoss(-10)
- C.adjustToxLoss(-10)
- C.adjustOxyLoss(-10)
- C.adjustFireLoss(-10)
- sleep(10)
-
- src.verbs -= /mob/proc/changeling_rapidregen
- spawn(5) src.verbs += /mob/proc/changeling_rapidregen
- feedback_add_details("changeling_powers","RR")
- return 1
-
-// HIVE MIND UPLOAD/DOWNLOAD DNA
-
-var/list/datum/dna/hivemind_bank = list()
-
-/mob/proc/changeling_hiveupload()
- set category = "Changeling"
- set name = "Hive Channel (10)"
- set desc = "Allows you to channel DNA in the airwaves to allow other changelings to absorb it."
-
- var/datum/changeling/changeling = changeling_power(10,1)
- if(!changeling) return
-
- var/list/names = list()
- for(var/datum/dna/DNA in changeling.absorbed_dna)
- if(!(DNA in hivemind_bank))
- names += DNA.real_name
-
- if(names.len <= 0)
- src << "The airwaves already have all of our DNA."
- return
-
- var/S = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names
- if(!S) return
-
- var/datum/dna/chosen_dna = changeling.GetDNA(S)
- if(!chosen_dna)
- return
-
- changeling.chem_charges -= 10
- hivemind_bank += chosen_dna
- src << "We channel the DNA of [S] to the air."
- feedback_add_details("changeling_powers","HU")
- return 1
-
-/mob/proc/changeling_hivedownload()
- set category = "Changeling"
- set name = "Hive Absorb (20)"
- set desc = "Allows you to absorb DNA that is being channelled in the airwaves."
-
- var/datum/changeling/changeling = changeling_power(20,1)
- if(!changeling) return
-
- var/list/names = list()
- for(var/datum/dna/DNA in hivemind_bank)
- if(!(DNA in changeling.absorbed_dna))
- names[DNA.real_name] = DNA
-
- if(names.len <= 0)
- src << "There's no new DNA to absorb from the air."
- return
-
- var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names
- if(!S) return
- var/datum/dna/chosen_dna = names[S]
- if(!chosen_dna)
- return
-
- changeling.chem_charges -= 20
- changeling.absorbed_dna += chosen_dna
- src << "We absorb the DNA of [S] from the air."
- feedback_add_details("changeling_powers","HD")
- return 1
-
-// Fake Voice
-
-/mob/proc/changeling_mimicvoice()
- set category = "Changeling"
- set name = "Mimic Voice"
- set desc = "Shape our vocal glands to form a voice of someone we choose. We cannot regenerate chemicals when mimicing."
-
-
- var/datum/changeling/changeling = changeling_power()
- if(!changeling) return
-
- if(changeling.mimicing)
- changeling.mimicing = ""
- src << "We return our vocal glands to their original location."
- return
-
- var/mimic_voice = stripped_input(usr, "Enter a name to mimic.", "Mimic Voice", null, MAX_NAME_LEN)
- if(!mimic_voice)
- return
-
- changeling.mimicing = mimic_voice
-
- src << "We shape our glands to take the voice of [mimic_voice], this will stop us from regenerating chemicals while active."
- src << "Use this power again to return to our original voice and reproduce chemicals again."
-
- feedback_add_details("changeling_powers","MV")
-
- spawn(0)
- while(src && src.mind && src.mind.changeling && src.mind.changeling.mimicing)
- src.mind.changeling.chem_charges = max(src.mind.changeling.chem_charges - 1, 0)
- sleep(40)
- if(src && src.mind && src.mind.changeling)
- src.mind.changeling.mimicing = ""
- //////////
- //STINGS// //They get a pretty header because there's just so fucking many of them ;_;
- //////////
-
-/mob/proc/sting_can_reach(mob/M as mob, sting_range = 1)
- if(M.loc == src.loc) return 1 //target and source are in the same thing
- if(!isturf(src.loc) || !isturf(M.loc)) return 0 //One is inside, the other is outside something.
- if(AStar(src.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, sting_range)) //If a path exists, good!
- return 1
- return 0
-
-//Handles the general sting code to reduce on copypasta (seeming as somebody decided to make SO MANY dumb abilities)
-/mob/proc/changeling_sting(var/required_chems=0, var/verb_path)
- var/datum/changeling/changeling = changeling_power(required_chems)
- if(!changeling) return
-
- var/list/victims = list()
- for(var/mob/living/carbon/C in oview(changeling.sting_range))
- victims += C
- var/mob/living/carbon/T = input(src, "Who will we sting?") as null|anything in victims
-
- if(!T) return
- if(!(T in view(changeling.sting_range))) return
- if(!sting_can_reach(T, changeling.sting_range)) return
- if(!changeling_power(required_chems)) return
-
- if(ishuman(T))
- var/mob/living/carbon/human/H = T
- if(H.species.flags & IS_SYNTHETIC)
- src << "This won't work on synthetics."
- return
-
- changeling.chem_charges -= required_chems
- changeling.sting_range = 1
- src.verbs -= verb_path
- spawn(10) src.verbs += verb_path
-
- src << "We stealthily sting [T]."
- if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting
- T << "You feel a tiny prick."
- return
-
-
-/mob/proc/changeling_lsdsting()
- set category = "Changeling"
- set name = "Hallucination Sting (15)"
- set desc = "Causes terror in the target."
-
- var/mob/living/carbon/T = changeling_sting(15,/mob/proc/changeling_lsdsting)
- if(!T) return 0
- spawn(rand(300,600))
- if(T) T.hallucination += 400
- feedback_add_details("changeling_powers","HS")
- return 1
-
-/mob/proc/changeling_silence_sting()
- set category = "Changeling"
- set name = "Silence sting (10)"
- set desc="Sting target"
-
- var/mob/living/carbon/T = changeling_sting(10,/mob/proc/changeling_silence_sting)
- if(!T) return 0
- T.silent += 30
- feedback_add_details("changeling_powers","SS")
- return 1
-
-/mob/proc/changeling_blind_sting()
- set category = "Changeling"
- set name = "Blind sting (20)"
- set desc="Sting target"
-
- var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_blind_sting)
- if(!T) return 0
- T << "Your eyes burn horrificly!"
- T.disabilities |= NEARSIGHTED
- spawn(300) T.disabilities &= ~NEARSIGHTED
- T.eye_blind = 10
- T.eye_blurry = 20
- feedback_add_details("changeling_powers","BS")
- return 1
-
-/mob/proc/changeling_deaf_sting()
- set category = "Changeling"
- set name = "Deaf sting (5)"
- set desc="Sting target:"
-
- var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_deaf_sting)
- if(!T) return 0
- T << "Your ears pop and begin ringing loudly!"
- T.sdisabilities |= DEAF
- spawn(300) T.sdisabilities &= ~DEAF
- feedback_add_details("changeling_powers","DS")
- return 1
-
-/mob/proc/changeling_paralysis_sting()
- set category = "Changeling"
- set name = "Paralysis sting (30)"
- set desc="Sting target"
-
- var/mob/living/carbon/T = changeling_sting(30,/mob/proc/changeling_paralysis_sting)
- if(!T) return 0
- T << "Your muscles begin to painfully tighten."
- T.Weaken(20)
- feedback_add_details("changeling_powers","PS")
- return 1
-
-/mob/proc/changeling_transformation_sting()
- set category = "Changeling"
- set name = "Transformation sting (40)"
- set desc="Sting target"
-
- var/datum/changeling/changeling = changeling_power(40)
- if(!changeling) return 0
-
-
-
- var/list/names = list()
- for(var/datum/dna/DNA in changeling.absorbed_dna)
- names += "[DNA.real_name]"
-
- var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names
- if(!S) return
-
- var/datum/dna/chosen_dna = changeling.GetDNA(S)
- if(!chosen_dna)
- return
-
- var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_transformation_sting)
- if(!T) return 0
- if((M_HUSK in T.mutations) || (!ishuman(T) && !ismonkey(T)))
- src << "Our sting appears ineffective against its DNA."
- return 0
- T.visible_message("[T] transforms!")
- T.dna = chosen_dna.Clone()
- T.real_name = chosen_dna.real_name
- T.UpdateAppearance()
- domutcheck(T, null)
- feedback_add_details("changeling_powers","TS")
- return 1
-
-/mob/proc/changeling_unfat_sting()
- set category = "Changeling"
- set name = "Unfat sting (5)"
- set desc = "Sting target"
-
- var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_unfat_sting)
- if(!T) return 0
- T << "You feel a small prick as stomach churns violently and you become to feel skinnier."
- T.overeatduration = 0
- T.nutrition -= 100
- feedback_add_details("changeling_powers","US")
- return 1
-
-/mob/proc/changeling_DEATHsting()
- set category = "Changeling"
- set name = "Death Sting (40)"
- set desc = "Causes spasms onto death."
-
- var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_DEATHsting)
- if(!T) return 0
- T << "You feel a small prick and your chest becomes tight."
- T.silent = 10
- T.Paralyse(10)
- T.Jitter(1000)
- if(T.reagents) T.reagents.add_reagent("lexorin", 40)
- feedback_add_details("changeling_powers","DTHS")
- return 1
-
-/mob/proc/changeling_extract_dna_sting()
- set category = "Changeling"
- set name = "Extract DNA Sting (40)"
- set desc="Stealthily sting a target to extract their DNA."
-
- var/datum/changeling/changeling = null
- if(src.mind && src.mind.changeling)
- changeling = src.mind.changeling
- if(!changeling)
- return 0
-
- var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting)
- if(!T) return 0
- if(T.species.flags & NO_SCAN) // Yeah, this needs the same protection, otherwise you can steal DNA from Slime People and then blood overdose when you turn into one.
- src << "We do not know how to parse this creature's DNA!"
- changeling.chem_charges += 40
- return 0
-
- T.dna.real_name = T.real_name
- changeling.absorbed_dna |= T.dna
- if(T.species && !(T.species.name in changeling.absorbed_species))
- changeling.absorbed_species += T.species.name
-
- feedback_add_details("changeling_powers","ED")
- return 1
diff --git a/code/game/gamemodes/changeling/evolution_menu.dm b/code/game/gamemodes/changeling/evolution_menu.dm
new file mode 100644
index 00000000000..370a65d42a0
--- /dev/null
+++ b/code/game/gamemodes/changeling/evolution_menu.dm
@@ -0,0 +1,404 @@
+var/list/sting_paths
+// totally stolen from the new player panel. YAYY
+
+/obj/effect/proc_holder/changeling/evolution_menu
+ name = "-Evolution Menu-" //Dashes are so it's listed before all the other abilities.
+ desc = "Choose our method of subjugation."
+ dna_cost = 0
+
+/obj/effect/proc_holder/changeling/evolution_menu/Click()
+ if(!usr || !usr.mind || !usr.mind.changeling)
+ return
+ var/datum/changeling/changeling = usr.mind.changeling
+
+ if(!sting_paths)
+ sting_paths = init_subtypes(/obj/effect/proc_holder/changeling)
+
+ var/dat = create_menu(changeling)
+ usr << browse(dat, "window=powers;size=600x700")//900x480
+
+
+/obj/effect/proc_holder/changeling/evolution_menu/proc/create_menu(var/datum/changeling/changeling)
+ var/dat
+ dat +="Changling Evolution Menu"
+
+ //javascript, the part that does most of the work~
+ dat += {"
+
+
+
+
+
+
+ "}
+
+ //body tag start + onload and onkeypress (onkeyup) javascript event calls
+ dat += ""
+
+ //title + search bar
+ dat += {"
+
+
+
+ "}
+
+ //player table header
+ dat += {"
+
+ "}
+
+ var/i = 1
+ for(var/obj/effect/proc_holder/changeling/cling_power in sting_paths)
+
+ if(cling_power.dna_cost <= 0) //Let's skip the crap we start with. Keeps the evolution menu uncluttered.
+ continue
+
+ var/ownsthis = changeling.has_sting(cling_power)
+
+ var/color
+ if(ownsthis)
+ if(i%2 == 0)
+ color = "#d8ebd8"
+ else
+ color = "#c3dec3"
+ else
+ if(i%2 == 0)
+ color = "#f2f2f2"
+ else
+ color = "#e6e6e6"
+
+
+ dat += {"
+
+
+
+
+
+ Evolve [cling_power][ownsthis ? " - Purchased" : (cling_power.req_dna>changeling.absorbedcount ? " - Requires [cling_power.req_dna] absorptions" : " - Cost: [cling_power.dna_cost]")]
+
+
+ |
+
+
+ "}
+
+ i++
+
+
+ //player table ending
+ dat += {"
+
+
+
+
+
+ "}
+ return dat
+
+
+/obj/effect/proc_holder/changeling/evolution_menu/Topic(href, href_list)
+ ..()
+ if(!(iscarbon(usr) && usr.mind && usr.mind.changeling))
+ return
+
+ if(href_list["P"])
+ usr.mind.changeling.purchasePower(usr, href_list["P"])
+ else if(href_list["readapt"])
+ usr.mind.changeling.lingRespec(usr)
+ var/dat = create_menu(usr.mind.changeling)
+ usr << browse(dat, "window=powers;size=600x700")
+/////
+
+/datum/changeling/proc/purchasePower(var/mob/living/carbon/user, var/sting_name)
+
+ var/obj/effect/proc_holder/changeling/thepower = null
+
+ if(!sting_paths)
+ sting_paths = init_subtypes(/obj/effect/proc_holder/changeling)
+ for(var/obj/effect/proc_holder/changeling/cling_sting in sting_paths)
+ if(cling_sting.name == sting_name)
+ thepower = cling_sting
+
+ if(thepower == null)
+ user << "This is awkward. Changeling power purchase failed, please report this bug to a coder!"
+ return
+
+ if(absorbedcount < thepower.req_dna)
+ user << "We lack the energy to evolve this ability!"
+ return
+
+ if(has_sting(thepower))
+ user << "We have already evolved this ability!"
+ return
+
+ if(thepower.dna_cost < 0)
+ user << "We cannot evolve this ability."
+ return
+
+ if(geneticpoints < thepower.dna_cost)
+ user << "We have reached our capacity for abilities."
+ return
+
+ if(user.status_flags & FAKEDEATH)//To avoid potential exploits by buying new powers while in stasis, which clears your verblist.
+ user << "We lack the energy to evolve new abilities right now."
+ return
+
+ geneticpoints -= thepower.dna_cost
+ purchasedpowers += thepower
+ thepower.on_purchase(user)
+
+//Reselect powers
+/datum/changeling/proc/lingRespec(var/mob/user)
+ if(!ishuman(user))
+ user << "We can't remove our evolutions in this form!"
+ return
+ if(canrespec)
+ user << "We have removed our evolutions from this form, and are now ready to readapt."
+ user.remove_changeling_powers(1)
+ canrespec = 0
+ user.make_changeling()
+ return 1
+ else
+ user << "You lack the power to readapt your evolutions!"
+ return 0
+
+/mob/proc/make_changeling()
+ if(!mind)
+ return
+ if(!ishuman(src) && !ismonkey(src))
+ return
+ if(!mind.changeling)
+ mind.changeling = new /datum/changeling(gender)
+ if(!sting_paths)
+ sting_paths = init_subtypes(/obj/effect/proc_holder/changeling)
+ if(mind.changeling.purchasedpowers)
+ remove_changeling_powers(1)
+
+ for(var/language in languages)
+ if(!(language in mind.changeling.absorbed_languages))
+ mind.changeling.absorbed_languages += language
+
+ // purchase free powers.
+ for(var/obj/effect/proc_holder/changeling/path in sting_paths)
+ //var/obj/effect/proc_holder/changeling/S = new path()
+ if(!path.dna_cost)
+ if(!mind.changeling.has_sting(path))
+ mind.changeling.purchasedpowers += path
+ path.on_purchase(src)
+
+ var/mob/living/carbon/C = src //only carbons have dna now, so we have to typecaste
+ mind.changeling.absorbed_dna |= C.dna
+ return 1
+
+/datum/changeling/proc/reset()
+ chosen_sting = null
+ geneticpoints = initial(geneticpoints)
+ sting_range = initial(sting_range)
+ chem_storage = initial(chem_storage)
+ chem_recharge_rate = initial(chem_recharge_rate)
+ chem_charges = min(chem_charges, chem_storage)
+ chem_recharge_slowdown = initial(chem_recharge_slowdown)
+ mimicing = ""
+
+/mob/proc/remove_changeling_powers(var/keep_free_powers=0)
+ if(ishuman(src) || ismonkey(src))
+ if(mind && mind.changeling)
+ digitalcamo = 0
+ mind.changeling.changeling_speak = 0
+ mind.changeling.reset()
+ for(var/obj/effect/proc_holder/changeling/p in mind.changeling.purchasedpowers)
+ if(!(p.dna_cost == 0 && keep_free_powers))
+ mind.changeling.purchasedpowers -= p
+
+/datum/changeling/proc/has_sting(obj/effect/proc_holder/changeling/power)
+ for(var/obj/effect/proc_holder/changeling/P in purchasedpowers)
+ if(power.name == P.name)
+ return 1
+ return 0
diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm
deleted file mode 100644
index 68458760855..00000000000
--- a/code/game/gamemodes/changeling/modularchangling.dm
+++ /dev/null
@@ -1,506 +0,0 @@
-// READ: Don't use the apostrophe in name or desc. Causes script errors.
-
-var/list/powers = typesof(/datum/power/changeling) - /datum/power/changeling //needed for the badmin verb for now
-var/list/datum/power/changeling/powerinstances = list()
-
-/datum/power //Could be used by other antags too
- var/name = "Power"
- var/desc = "Placeholder"
- var/helptext = ""
- var/isVerb = 1 // Is it an active power, or passive?
- var/verbpath // Path to a verb that contains the effects.
-
-/datum/power/changeling
- var/allowduringlesserform = 0
- var/genomecost = 500000 // Cost for the changling to evolve this power.
-
-/datum/power/changeling/absorb_dna
- name = "Absorb DNA"
- desc = "Permits us to syphon the DNA from a human. They become one with us, and we become stronger."
- genomecost = 0
- verbpath = /mob/proc/changeling_absorb_dna
-
-/datum/power/changeling/transform
- name = "Transform"
- desc = "We take on the apperance and voice of one we have absorbed."
- genomecost = 0
- verbpath = /mob/proc/changeling_transform
-
-/datum/power/changeling/change_species
- name = "Change Species"
- desc = "We take on the apperance of a species that we have absorbed."
- genomecost = 0
- verbpath = /mob/proc/changeling_change_species
-
-/datum/power/changeling/fakedeath
- name = "Regenerative Stasis"
- desc = "We become weakened to a death-like state, where we will rise again from death."
- helptext = "Can be used before or after death. Duration varies greatly."
- genomecost = 0
- allowduringlesserform = 1
- verbpath = /mob/proc/changeling_fakedeath
-
-// Hivemind
-
-/datum/power/changeling/hive_upload
- name = "Hive Channel"
- desc = "We can channel a DNA into the airwaves, allowing our fellow changelings to absorb it and transform into it as if they acquired the DNA themselves."
- helptext = "Allows other changelings to absorb the DNA you channel from the airwaves. Will not help them towards their absorb objectives."
- genomecost = 0
- verbpath = /mob/proc/changeling_hiveupload
-
-/datum/power/changeling/hive_download
- name = "Hive Absorb"
- desc = "We can absorb a single DNA from the airwaves, allowing us to use more disguises with help from our fellow changelings."
- helptext = "Allows you to absorb a single DNA and use it. Does not count towards your absorb objective."
- genomecost = 0
- verbpath = /mob/proc/changeling_hivedownload
-
-/datum/power/changeling/lesser_form
- name = "Lesser Form"
- desc = "We debase ourselves and become lesser. We become a monkey."
- genomecost = 1
- verbpath = /mob/proc/changeling_lesser_form
-
-/datum/power/changeling/deaf_sting
- name = "Deaf Sting"
- desc = "We silently sting a human, completely deafening them for a short time."
- genomecost = 1
- allowduringlesserform = 1
- verbpath = /mob/proc/changeling_deaf_sting
-
-/datum/power/changeling/blind_sting
- name = "Blind Sting"
- desc = "We silently sting a human, completely blinding them for a short time."
- genomecost = 2
- allowduringlesserform = 1
- verbpath = /mob/proc/changeling_blind_sting
-
-/datum/power/changeling/silence_sting
- name = "Silence Sting"
- desc = "We silently sting a human, completely silencing them for a short time."
- helptext = "Does not provide a warning to a victim that they have been stung, until they try to speak and cannot."
- genomecost = 3
- allowduringlesserform = 1
- verbpath = /mob/proc/changeling_silence_sting
-
-/datum/power/changeling/mimicvoice
- name = "Mimic Voice"
- desc = "We shape our vocal glands to sound like a desired voice."
- helptext = "Will turn your voice into the name that you enter. We must constantly expend chemicals to maintain our form like this"
- genomecost = 3
- verbpath = /mob/proc/changeling_mimicvoice
-
-/datum/power/changeling/extractdna
- name = "Extract DNA"
- desc = "We stealthily sting a target and extract the DNA from them."
- helptext = "Will give you the DNA of your target, allowing you to transform into them. Does not count towards absorb objectives."
- genomecost = 4
- allowduringlesserform = 1
- verbpath = /mob/proc/changeling_extract_dna_sting
-
-/datum/power/changeling/transformation_sting
- name = "Transformation Sting"
- desc = "We silently sting a human, injecting a retrovirus that forces them to transform into another."
- helptext = "Does not provide a warning to others. The victim will transform much like a changeling would."
- genomecost = 3
- verbpath = /mob/proc/changeling_transformation_sting
-
-/datum/power/changeling/paralysis_sting
- name = "Paralysis Sting"
- desc = "We silently sting a human, paralyzing them for a short time."
- genomecost = 4
- verbpath = /mob/proc/changeling_paralysis_sting
-
-/datum/power/changeling/LSDSting
- name = "Hallucination Sting"
- desc = "We evolve the ability to sting a target with a powerful hallunicationary chemical."
- helptext = "The target does not notice they have been stung. The effect occurs after 30 to 60 seconds."
- genomecost = 3
- verbpath = /mob/proc/changeling_lsdsting
-
-/datum/power/changeling/DeathSting
- name = "Death Sting"
- desc = "We silently sting a human, filling him with potent chemicals. His rapid death is all but assured."
- genomecost = 10
- verbpath = /mob/proc/changeling_DEATHsting
-
-/datum/power/changeling/unfat_sting
- name = "Unfat Sting"
- desc = "We silently sting a human, forcing them to rapidly metobolize their fat."
- genomecost = 1
- verbpath = /mob/proc/changeling_unfat_sting
-
-/datum/power/changeling/boost_range
- name = "Boost Range"
- desc = "We evolve the ability to shoot our stingers at humans, with some preperation."
- genomecost = 2
- allowduringlesserform = 1
- verbpath = /mob/proc/changeling_boost_range
-
-/datum/power/changeling/Epinephrine
- name = "Epinephrine sacs"
- desc = "We evolve additional sacs of adrenaline throughout our body."
- helptext = "Gives the ability to instantly recover from stuns. High chemical cost."
- genomecost = 4
- verbpath = /mob/proc/changeling_unstun
-
-/datum/power/changeling/ChemicalSynth
- name = "Rapid Chemical-Synthesis"
- desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster."
- helptext = "Doubles the rate at which we naturally recharge chemicals."
- genomecost = 4
- isVerb = 0
- verbpath = /mob/proc/changeling_fastchemical
-/*
-/datum/power/changeling/AdvChemicalSynth
- name = "Advanced Chemical-Synthesis"
- desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster."
- helptext = "Doubles the rate at which we naturally recharge chemicals."
- genomecost = 8
- isVerb = 0
- verbpath = /mob/proc/changeling_fastchemical
-*/
-/datum/power/changeling/EngorgedGlands
- name = "Engorged Chemical Glands"
- desc = "Our chemical glands swell, permitting us to store more chemicals inside of them."
- helptext = "Allows us to store an extra 25 units of chemicals."
- genomecost = 4
- isVerb = 0
- verbpath = /mob/proc/changeling_engorgedglands
-
-/datum/power/changeling/DigitalCamoflague
- name = "Digital Camoflauge"
- desc = "We evolve the ability to distort our form and proprtions, defeating common altgorthms used to detect lifeforms on cameras."
- helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us.. uncanny. We must constantly expend chemicals to maintain our form like this."
- genomecost = 3
- allowduringlesserform = 1
- verbpath = /mob/proc/changeling_digitalcamo
-
-/datum/power/changeling/rapidregeneration
- name = "Rapid Regeneration"
- desc = "We evolve the ability to rapidly regenerate, negating the need for stasis."
- helptext = "Heals a moderate amount of damage every tick."
- genomecost = 8
- verbpath = /mob/proc/changeling_rapidregen
-
-
-
-// Modularchangling, totally stolen from the new player panel. YAYY
-/datum/changeling/proc/EvolutionMenu()//The new one
- set category = "Changeling"
- set desc = "Level up!"
-
- if(!usr || !usr.mind || !usr.mind.changeling) return
- src = usr.mind.changeling
-
- if(!powerinstances.len)
- for(var/P in powers)
- powerinstances += new P()
-
- var/dat = "Changling Evolution Menu"
-
- //javascript, the part that does most of the work~
- dat += {"
-
-
-
-
-
-
- "}
-
- //body tag start + onload and onkeypress (onkeyup) javascript event calls
- dat += ""
-
- //title + search bar
- dat += {"
-
-
-
- "}
-
- //player table header
- dat += {"
-
- "}
-
- var/i = 1
- for(var/datum/power/changeling/P in powerinstances)
- var/ownsthis = 0
-
- if(P in purchasedpowers)
- ownsthis = 1
-
-
- var/color = "#e6e6e6"
- if(i%2 == 0)
- color = "#f2f2f2"
-
-
- dat += {"
-
-
-
-
-
- Evolve [P] - Cost: [ownsthis ? "Purchased" : P.genomecost]
-
-
- |
-
-
- "}
-
- i++
-
-
- //player table ending
- dat += {"
-
-
-
-
-
- "}
-
- usr << browse(dat, "window=powers;size=900x480")
-
-
-/datum/changeling/Topic(href, href_list)
- ..()
- if(!ismob(usr))
- return
-
- if(href_list["P"])
- var/datum/mind/M = usr.mind
- if(!istype(M))
- return
- purchasePower(M, href_list["P"])
- call(/datum/changeling/proc/EvolutionMenu)()
-
-
-
-/datum/changeling/proc/purchasePower(var/datum/mind/M, var/Pname, var/remake_verbs = 1)
- if(!M || !M.changeling)
- return
-
- var/datum/power/changeling/Thepower = Pname
-
-
- for (var/datum/power/changeling/P in powerinstances)
- //world << "[P] - [Pname] = [P.name == Pname ? "True" : "False"]"
- if(P.name == Pname)
- Thepower = P
- break
-
-
- if(Thepower == null)
- M.current << "This is awkward. Changeling power purchase failed, please report this bug to a coder!"
- return
-
- if(Thepower in purchasedpowers)
- M.current << "We have already evolved this ability!"
- return
-
-
- if(geneticpoints < Thepower.genomecost)
- M.current << "We cannot evolve this... yet. We must acquire more DNA."
- return
-
- geneticpoints -= Thepower.genomecost
-
- purchasedpowers += Thepower
-
- if(!Thepower.isVerb && Thepower.verbpath)
- call(M.current, Thepower.verbpath)()
- else if(remake_verbs)
- M.current.make_changeling()
-
diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm
new file mode 100644
index 00000000000..6acb6e5a66d
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/absorb.dm
@@ -0,0 +1,107 @@
+/obj/effect/proc_holder/changeling/absorbDNA
+ name = "Absorb DNA"
+ desc = "Absorb the DNA of our victim."
+ chemical_cost = 0
+ dna_cost = 0
+ req_human = 1
+ max_genetic_damage = 100
+
+/obj/effect/proc_holder/changeling/absorbDNA/can_sting(var/mob/living/carbon/user)
+ if(!..())
+ return
+
+ var/datum/changeling/changeling = user.mind.changeling
+ if(changeling.isabsorbing)
+ user << "We are already absorbing!"
+ return
+
+ var/obj/item/weapon/grab/G = user.get_active_hand()
+ if(!istype(G))
+ user << "We must be grabbing a creature in our active hand to absorb them."
+ return
+ if(G.state <= GRAB_NECK)
+ user << "We must have a tighter grip to absorb this creature."
+ return
+
+ var/mob/living/carbon/target = G.affecting
+ return changeling.can_absorb_dna(user,target)
+
+
+
+/obj/effect/proc_holder/changeling/absorbDNA/sting_action(var/mob/user)
+ var/datum/changeling/changeling = user.mind.changeling
+ var/obj/item/weapon/grab/G = user.get_active_hand()
+ var/mob/living/carbon/human/target = G.affecting
+ changeling.isabsorbing = 1
+ for(var/stage = 1, stage<=3, stage++)
+ switch(stage)
+ if(1)
+ user << "This creature is compatible. We must hold still..."
+ if(2)
+ user << "We extend a proboscis."
+ user.visible_message("[user] extends a proboscis!")
+ if(3)
+ user << "We stab [target] with the proboscis."
+ user.visible_message("[user] stabs [target] with the proboscis!")
+ target << "You feel a sharp stabbing pain!"
+ target.take_overall_damage(40)
+ feedback_add_details("changeling_powers","A[stage]")
+ if(!do_mob(user, target, 150))
+ user << "Our absorption of [target] has been interrupted!"
+ changeling.isabsorbing = 0
+ return
+
+ user << "We have absorbed [target]!"
+ user.visible_message("[user] sucks the fluids from [target]!")
+ target << "You have been absorbed by the changeling!"
+
+ if(!changeling.has_dna(target.dna))
+ changeling.absorb_dna(target, user)
+
+ if(user.nutrition < 450) // Nutrition level before overeat_duration starts ticking for you to become obese.
+ user.nutrition = min((user.nutrition + target.nutrition), 450)
+
+ if(target.mind)//if the victim has got a mind
+
+ target.mind.show_memory(src, 0) //I can read your mind, kekeke. Output all their notes.
+
+ if(target.mind.changeling)//If the target was a changeling, suck out their extra juice and objective points!
+ changeling.chem_charges += min(target.mind.changeling.chem_charges, changeling.chem_storage)
+ changeling.absorbedcount += (target.mind.changeling.absorbedcount)
+
+ target.mind.changeling.absorbed_dna.len = 1
+ target.mind.changeling.absorbedcount = 0
+
+
+ changeling.chem_charges=min(changeling.chem_charges+10, changeling.chem_storage)
+
+ changeling.isabsorbing = 0
+ changeling.canrespec = 1
+
+ target.death(0)
+ target.Drain()
+ return 1
+
+
+
+//Absorbs the target DNA.
+/datum/changeling/proc/absorb_dna(mob/living/carbon/T, var/mob/user)
+ if(absorbed_dna.len)
+ absorbed_dna.Cut(1,2)
+ T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set.
+ var/datum/dna/new_dna = T.dna.Clone()
+ //Steal all of their languages!
+ for(var/language in T.languages)
+ if(!(language in absorbed_languages))
+ absorbed_languages += language
+ changeling_update_languages(absorbed_languages, user)
+
+ absorbedcount++
+ store_dna(new_dna, user)
+
+/datum/changeling/proc/store_dna(var/datum/dna/new_dna, var/mob/user)
+ for(var/datum/objective/escape/escape_with_identity/E in user.mind.objectives)
+ if(E.target_real_name == new_dna.real_name)
+ protected_dna |= new_dna
+ return
+ absorbed_dna |= new_dna
diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
new file mode 100644
index 00000000000..d40da71fff1
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
@@ -0,0 +1,24 @@
+//Augmented Eyesight: Gives you thermal and night vision - bye bye, flashlights. Also, high DNA cost because of how powerful it is.
+//Possible todo: make a custom message for directing a penlight/flashlight at the eyes - not sure what would display though.
+
+/obj/effect/proc_holder/changeling/augmented_eyesight
+ name = "Augmented Eyesight"
+ desc = "Creates heat receptors in our eyes and dramatically increases light sensing ability."
+ helptext = "Grants us night vision and thermal vision. It may be toggled on or off."
+ chemical_cost = 0
+ dna_cost = 2 //Would be 1 without thermal vision
+ var/active = 0 //Whether or not vision is enhanced
+
+/obj/effect/proc_holder/changeling/augmented_eyesight/sting_action(var/mob/user)
+ active = !active
+ if(active)
+ user << "We feel a minute twitch in our eyes, and darkness creeps away."
+ else
+ user << "Our vision dulls. Shadows gather."
+ user.sight &= ~SEE_MOBS
+ while(active)
+ user.see_in_dark = 8
+ user.see_invisible = 2
+ user.sight |= SEE_MOBS
+ sleep(1) //BAD THINGS HAPPEN WITHOUT THIS.
+ return 1
diff --git a/code/game/gamemodes/changeling/powers/digitalcamo.dm b/code/game/gamemodes/changeling/powers/digitalcamo.dm
new file mode 100644
index 00000000000..92ae8e7781e
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/digitalcamo.dm
@@ -0,0 +1,17 @@
+/obj/effect/proc_holder/changeling/digitalcamo
+ name = "Digital Camouflage"
+ desc = "By evolving the ability to distort our form and proprotions, we defeat common altgorithms used to detect lifeforms on cameras."
+ helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us... uncanny."
+ dna_cost = 1
+
+//Prevents AIs tracking you but makes you easily detectable to the human-eye.
+/obj/effect/proc_holder/changeling/digitalcamo/sting_action(var/mob/user)
+
+ if(user.digitalcamo)
+ user << "We return to normal."
+ else
+ user << "We distort our form to prevent AI-tracking."
+ user.digitalcamo = !user.digitalcamo
+
+ feedback_add_details("changeling_powers","CAM")
+ return 1
diff --git a/code/game/gamemodes/changeling/powers/epinephrine.dm b/code/game/gamemodes/changeling/powers/epinephrine.dm
new file mode 100644
index 00000000000..55ce85cf88d
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/epinephrine.dm
@@ -0,0 +1,27 @@
+/obj/effect/proc_holder/changeling/epinephrine
+ name = "Epinephrine Overdose"
+ desc = "We evolve additional sacs of adrenaline throughout our body."
+ helptext = "Removes all stuns instantly and adds a short-term reduction in further stuns. Can be used while unconscious. Continued use poisons the body."
+ chemical_cost = 30
+ dna_cost = 2
+ req_human = 1
+ req_stat = UNCONSCIOUS
+
+//Recover from stuns.
+/obj/effect/proc_holder/changeling/epinephrine/sting_action(var/mob/living/user)
+
+ if(user.lying)
+ user << "We arise."
+ else
+ user << "Adrenaline rushes through us."
+ user.stat = 0
+ user.SetParalysis(0)
+ user.SetStunned(0)
+ user.SetWeakened(0)
+ user.lying = 0
+ user.update_canmove()
+ user.reagents.add_reagent("synaptizine", 20)
+ user.adjustStaminaLoss(-75)
+
+ feedback_add_details("changeling_powers","UNS")
+ return 1
diff --git a/code/game/gamemodes/changeling/powers/fakedeath.dm b/code/game/gamemodes/changeling/powers/fakedeath.dm
new file mode 100644
index 00000000000..9a4b144cc71
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/fakedeath.dm
@@ -0,0 +1,36 @@
+/obj/effect/proc_holder/changeling/fakedeath
+ name = "Regenerative Stasis"
+ desc = "We fall into a stasis, allowing us to regenerate."
+ chemical_cost = 15
+ dna_cost = 0
+ req_dna = 1
+ req_stat = DEAD
+ max_genetic_damage = 100
+
+
+//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay.
+/obj/effect/proc_holder/changeling/fakedeath/sting_action(var/mob/living/user)
+
+ user << "We begin our stasis, preparing energy to arise once more."
+
+ user.status_flags |= FAKEDEATH //play dead
+ user.update_canmove()
+
+ if(user.stat != DEAD)
+ user.emote("deathgasp")
+ user.tod = worldtime2text()
+
+ spawn(800)
+ if(user && user.mind && user.mind.changeling && user.mind.changeling.purchasedpowers)
+ user << "We are ready to regenerate."
+ user.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/revive(null)
+
+ feedback_add_details("changeling_powers","FD")
+ return 1
+
+/obj/effect/proc_holder/changeling/fakedeath/can_sting(var/mob/user)
+ if(user.status_flags & FAKEDEATH)
+ return
+ if(!user.stat && alert("Are we sure we wish to fake our death?",,"Yes","No") == "No")//Confirmation for living changelings if they want to fake their death
+ return
+ return ..()
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/fleshmend.dm b/code/game/gamemodes/changeling/powers/fleshmend.dm
new file mode 100644
index 00000000000..97889d1c9e3
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/fleshmend.dm
@@ -0,0 +1,25 @@
+/obj/effect/proc_holder/changeling/fleshmend
+ name = "Fleshmend"
+ desc = "Our flesh rapidly regenerates, healing our wounds."
+ helptext = "Heals a moderate amount of damage over a short period of time. Can be used while unconscious."
+ chemical_cost = 25
+ dna_cost = 2
+ req_stat = UNCONSCIOUS
+
+//Starts healing you every second for 10 seconds. Can be used whilst unconscious.
+/obj/effect/proc_holder/changeling/fleshmend/sting_action(var/mob/living/user)
+ user << "We begin to heal rapidly."
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.restore_blood()
+ H.shock_stage = 0
+ spawn(1)
+ H.fixblood()
+ spawn(0)
+ for(var/i = 0, i<10,i++)
+ user.heal_overall_damage(10, 10)
+ user.adjustOxyLoss(-10)
+ sleep(10)
+
+ feedback_add_details("changeling_powers","RR")
+ return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/glands.dm b/code/game/gamemodes/changeling/powers/glands.dm
new file mode 100644
index 00000000000..d08bd3021aa
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/glands.dm
@@ -0,0 +1,13 @@
+/obj/effect/proc_holder/changeling/glands
+ name = "Engorged Chemical Glands"
+ desc = "Our chemical glands swell, permitting us to store more chemicals inside of them."
+ helptext = "Allows us to store an extra 25 units of chemicals, and doubles production rate."
+ dna_cost = 2
+ chemical_cost = -1
+
+/obj/effect/proc_holder/changeling/glands/on_purchase(var/mob/user)
+ ..()
+ var/datum/changeling/changeling=user.mind.changeling
+ changeling.chem_storage += 25
+ changeling.chem_recharge_rate *=2
+ return
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/hivemind.dm b/code/game/gamemodes/changeling/powers/hivemind.dm
new file mode 100644
index 00000000000..853b7081fed
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/hivemind.dm
@@ -0,0 +1,92 @@
+//HIVEMIND COMMUNICATION (:g)
+/obj/effect/proc_holder/changeling/hivemind_comms
+ name = "Hivemind Communication"
+ desc = "We tune our senses to the airwaves to allow us to discreetly communicate and exchange DNA with other changelings."
+ helptext = "We will be able to talk with other changelings with :g. Exchanged DNA do not count towards absorb objectives."
+ dna_cost = 0
+ chemical_cost = -1
+
+/obj/effect/proc_holder/changeling/hivemind_comms/on_purchase(var/mob/user)
+ ..()
+ var/datum/changeling/changeling=user.mind.changeling
+ changeling.changeling_speak = 1
+ user << "Use say \":g message\" to communicate with the other changelings."
+ var/obj/effect/proc_holder/changeling/hivemind_upload/S1 = new
+ if(!changeling.has_sting(S1))
+ changeling.purchasedpowers+=S1
+ var/obj/effect/proc_holder/changeling/hivemind_download/S2 = new
+ if(!changeling.has_sting(S2))
+ changeling.purchasedpowers+=S2
+ return
+
+// HIVE MIND UPLOAD/DOWNLOAD DNA
+var/list/datum/dna/hivemind_bank = list()
+
+/obj/effect/proc_holder/changeling/hivemind_upload
+ name = "Hive Channel DNA"
+ desc = "Allows us to channel DNA in the airwaves to allow other changelings to absorb it."
+ chemical_cost = 10
+ dna_cost = -1
+
+/obj/effect/proc_holder/changeling/hivemind_upload/sting_action(var/mob/user)
+ var/datum/changeling/changeling = user.mind.changeling
+ var/list/names = list()
+ for(var/datum/dna/DNA in (changeling.absorbed_dna+changeling.protected_dna))
+ if(!(DNA in hivemind_bank))
+ names += DNA.real_name
+
+ if(names.len <= 0)
+ user << "The airwaves already have all of our DNA."
+ return
+
+ var/chosen_name = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names
+ if(!chosen_name)
+ return
+
+ var/datum/dna/chosen_dna = changeling.GetDNA(chosen_name)
+ if(!chosen_dna)
+ return
+
+ hivemind_bank += chosen_dna
+ user << "We channel the DNA of [chosen_name] to the air."
+ feedback_add_details("changeling_powers","HU")
+ return 1
+
+/obj/effect/proc_holder/changeling/hivemind_download
+ name = "Hive Absorb DNA"
+ desc = "Allows us to absorb DNA that has been channeled to the airwaves. Does not count towards absorb objectives."
+ chemical_cost = 10
+ dna_cost = -1
+
+/obj/effect/proc_holder/changeling/hivemind_download/can_sting(var/mob/living/carbon/user)
+ if(!..())
+ return
+ var/datum/changeling/changeling = user.mind.changeling
+ if(changeling.absorbed_dna[1] == user.dna)//If our current DNA is the stalest, we gotta ditch it.
+ user << "We have reached our capacity to store genetic information! We must transform before absorbing more."
+ return
+ return 1
+
+/obj/effect/proc_holder/changeling/hivemind_download/sting_action(var/mob/user)
+ var/datum/changeling/changeling = user.mind.changeling
+ var/list/names = list()
+ for(var/datum/dna/DNA in hivemind_bank)
+ if(!(DNA in changeling.absorbed_dna))
+ names[DNA.real_name] = DNA
+
+ if(names.len <= 0)
+ user << "There's no new DNA to absorb from the air."
+ return
+
+ var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names
+ if(!S) return
+ var/datum/dna/chosen_dna = names[S]
+ if(!chosen_dna)
+ return
+
+ if(changeling.absorbed_dna.len)
+ changeling.absorbed_dna.Cut(1,2)
+ changeling.store_dna(chosen_dna, user)
+ user << "We absorb the DNA of [S] from the air."
+ feedback_add_details("changeling_powers","HD")
+ return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/humanform.dm b/code/game/gamemodes/changeling/powers/humanform.dm
new file mode 100644
index 00000000000..b50c23197c4
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/humanform.dm
@@ -0,0 +1,74 @@
+/obj/effect/proc_holder/changeling/humanform
+ name = "Human form"
+ desc = "We change into a human."
+ chemical_cost = 5
+ genetic_damage = 3
+ req_dna = 1
+ max_genetic_damage = 3
+
+
+//Transform into a human.
+/obj/effect/proc_holder/changeling/humanform/sting_action(var/mob/living/carbon/user)
+ var/datum/changeling/changeling = user.mind.changeling
+ var/list/names = list()
+ for(var/datum/dna/DNA in (changeling.absorbed_dna+changeling.protected_dna))
+ names += "[DNA.real_name]"
+
+ var/chosen_name = input("Select the target DNA: ", "Target DNA", null) as null|anything in names
+ if(!chosen_name)
+ return
+
+ var/datum/dna/chosen_dna = changeling.GetDNA(chosen_name)
+ if(!chosen_dna)
+ return
+ if(!user)
+ return 0
+ user << "We transform our appearance."
+ user.dna = chosen_dna
+
+ var/list/implants = list()
+ for (var/obj/item/weapon/implant/I in user) //Still preserving implants
+ implants += I
+
+ for(var/obj/item/W in src)
+ user.u_equip(W)
+ if (user.client)
+ user.client.screen -= W
+ if (W)
+ W.loc = user.loc
+ W.dropped(user)
+ W.layer = initial(W.layer)
+
+ var/mob/living/carbon/human/O = new /mob/living/carbon/human( user, delay_ready_dna=1 )
+ if (user.dna.GetUIState(DNA_UI_GENDER))
+ O.gender = FEMALE
+ else
+ O.gender = MALE
+ O.dna = user.dna.Clone()
+ user.dna = null
+ O.real_name = chosen_dna.real_name
+ O.set_species()
+ for(var/obj/T in user)
+ del(T)
+
+ O.loc = user.loc
+
+ O.UpdateAppearance()
+ domutcheck(O, null)
+ O.setToxLoss(user.getToxLoss())
+ O.adjustBruteLoss(user.getBruteLoss())
+ O.setOxyLoss(user.getOxyLoss())
+ O.adjustFireLoss(user.getFireLoss())
+ O.stat = user.stat
+ for (var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+
+ user.mind.transfer_to(O)
+ O.mind.changeling.changeling_update_languages(changeling.absorbed_languages)
+ O.mind.changeling.purchasedpowers -= src
+ //O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/lesserform(null)
+ feedback_add_details("changeling_powers","LFT")
+ qdel(user)
+ return 1
+
diff --git a/code/game/gamemodes/changeling/powers/lesserform.dm b/code/game/gamemodes/changeling/powers/lesserform.dm
new file mode 100644
index 00000000000..0069b7cbfd2
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/lesserform.dm
@@ -0,0 +1,67 @@
+/obj/effect/proc_holder/changeling/lesserform
+ name = "Lesser form"
+ desc = "We debase ourselves and become lesser. We become a monkey."
+ chemical_cost = 5
+ dna_cost = 1
+ genetic_damage = 3
+ req_human = 1
+
+//Transform into a monkey.
+/obj/effect/proc_holder/changeling/lesserform/sting_action(var/mob/living/carbon/human/user)
+ var/datum/changeling/changeling = user.mind.changeling
+ if(!user)
+ return 0
+ if(user.has_brain_worms())
+ user << "We cannot perform this ability at the present time!"
+ return
+ user << "Our genes cry out!"
+
+ var/mob/living/carbon/C = user
+
+ //TODO replace with monkeyize proc
+ var/list/implants = list() //Try to preserve implants.
+ for(var/obj/item/weapon/implant/W in C)
+ implants += W
+
+ C.monkeyizing = 1
+ C.canmove = 0
+ C.icon = null
+ C.overlays.Cut()
+ C.invisibility = 101
+
+ var/atom/movable/overlay/animation = new /atom/movable/overlay( C.loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("h2monkey", animation)
+ sleep(30)
+ del(animation)
+
+ var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey(src)
+ O.dna = C.dna.Clone()
+ C.dna = null
+
+ for(var/obj/item/W in C)
+ C.drop_from_inventory(W)
+ for(var/obj/T in C)
+ del(T)
+
+ O.loc = C.loc
+ O.name = "monkey ([copytext(md5(C.real_name), 2, 6)])"
+ O.setToxLoss(C.getToxLoss())
+ O.adjustBruteLoss(C.getBruteLoss())
+ O.setOxyLoss(C.getOxyLoss())
+ O.adjustFireLoss(C.getFireLoss())
+ O.stat = C.stat
+ O.a_intent = "harm"
+ for(var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+
+ C.mind.transfer_to(O)
+ O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
+ O.mind.changeling.changeling_update_languages(changeling.absorbed_languages)
+
+ feedback_add_details("changeling_powers","LF")
+ qdel(C)
+ return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/mimic_voice.dm b/code/game/gamemodes/changeling/powers/mimic_voice.dm
new file mode 100644
index 00000000000..9d637245196
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/mimic_voice.dm
@@ -0,0 +1,28 @@
+/obj/effect/proc_holder/changeling/mimicvoice
+ name = "Mimic Voice"
+ desc = "We shape our vocal glands to sound like a desired voice."
+ helptext = "Will turn your voice into the name that you enter. We must constantly expend chemicals to maintain our form like this."
+ chemical_cost = 0 //constant chemical drain hardcoded
+ dna_cost = 1
+ req_human = 1
+
+
+// Fake Voice
+/obj/effect/proc_holder/changeling/mimicvoice/sting_action(var/mob/user)
+ var/datum/changeling/changeling=user.mind.changeling
+ if(changeling.mimicing)
+ changeling.mimicing = ""
+ changeling.chem_recharge_slowdown -= 0.5
+ user << "We return our vocal glands to their original position."
+ return
+
+ var/mimic_voice = stripped_input(user, "Enter a name to mimic.", "Mimic Voice", null, MAX_NAME_LEN)
+ if(!mimic_voice)
+ return
+
+ changeling.mimicing = mimic_voice
+ changeling.chem_recharge_slowdown += 0.5
+ user << "We shape our glands to take the voice of [mimic_voice], this will stop us from regenerating chemicals while active."
+ user << "Use this power again to return to our original voice and reproduce chemicals again."
+
+ feedback_add_details("changeling_powers","MV")
diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm
new file mode 100644
index 00000000000..31fd7c577dd
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/mutations.dm
@@ -0,0 +1,339 @@
+/*
+ Changeling Mutations! ~By Miauw (ALL OF IT :V)
+ Contains:
+ Arm Blade
+ Space Suit
+ Shield
+ Armor
+*/
+
+
+//Parent to shields and blades because muh copypasted code.
+/obj/effect/proc_holder/changeling/weapon
+ name = "Organic Weapon"
+ desc = "Go tell a coder if you see this"
+ helptext = "Yell at coderbus"
+ chemical_cost = 1000
+ dna_cost = -1
+ genetic_damage = 1000
+
+ var/weapon_type
+ var/weapon_name_simple
+
+/obj/effect/proc_holder/changeling/weapon/try_to_sting(var/mob/user, var/mob/target)
+ if(istype(user.l_hand, weapon_type)) //Not the nicest way to do it, but eh
+ qdel(user.l_hand)
+ user.visible_message("With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!", "We assimilate the [weapon_name_simple] back into our body.", "With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!", "We assimilate the [weapon_name_simple] back into our body.", "[H] casts off their [suit_name_simple]!", "We cast off our [suit_name_simple][genetic_damage > 0 ? ", temporarily weakening our genomes." : "."]", "You hear the organic matter ripping and tearing!")
+ qdel(H.wear_suit)
+ qdel(H.head)
+ H.update_inv_wear_suit()
+ H.update_inv_head()
+ H.update_hair()
+
+ if(blood_on_castoff)
+ var/turf/simulated/T = get_turf(H)
+ if(istype(T))
+ T.add_blood(H) //So real blood decals
+ playsound(H.loc, 'sound/effects/splat.ogg', 50, 1) //So real sounds
+
+ changeling.geneticdamage += genetic_damage //Casting off a space suit leaves you weak for a few seconds.
+ changeling.chem_recharge_slowdown -= recharge_slowdown
+ return
+ ..(H, target)
+
+/obj/effect/proc_holder/changeling/suit/sting_action(var/mob/living/carbon/human/user)
+ if(user.wear_suit && !user.wear_suit.canremove)
+ user << "\the [user.wear_suit] is stuck to your body, you cannot grow a [suit_name_simple] over it!"
+ return
+ if(user.head && !user.head.canremove)
+ user << "\the [user.head] is stuck on your head, you cannot grow a [helmet_name_simple] over it!"
+ return
+
+ user.u_equip(user.head)
+ user.u_equip(user.wear_suit)
+
+ user.equip_to_slot_if_possible(new suit_type(user), slot_wear_suit, 1, 1, 1)
+ user.equip_to_slot_if_possible(new helmet_type(user), slot_head, 1, 1, 1)
+
+ var/datum/changeling/changeling = user.mind.changeling
+ changeling.chem_recharge_slowdown += recharge_slowdown
+ return 1
+
+
+//fancy headers yo
+/***************************************\
+|***************ARM BLADE***************|
+\***************************************/
+/obj/effect/proc_holder/changeling/weapon/arm_blade
+ name = "Arm Blade"
+ desc = "We reform one of our arms into a deadly blade."
+ helptext = "Cannot be used while in lesser form."
+ chemical_cost = 20
+ dna_cost = 2
+ genetic_damage = 10
+ req_human = 1
+ max_genetic_damage = 20
+ weapon_type = /obj/item/weapon/melee/arm_blade
+ weapon_name_simple = "blade"
+
+/obj/item/weapon/melee/arm_blade
+ name = "arm blade"
+ desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter"
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "arm_blade"
+ item_state = "arm_blade"
+ icon_override = 'icons/mob/in-hand/changeling.dmi'
+ w_class = 5.0
+ sharp = 1
+ edge = 1
+ canremove = 0
+ force = 25
+ throwforce = 0 //Just to be on the safe side
+ throw_range = 0
+ throw_speed = 0
+
+/obj/item/weapon/melee/arm_blade/New()
+ ..()
+ if(ismob(loc))
+ loc.visible_message("A grotesque blade forms around [loc.name]\'s arm!", "Our arm twists and mutates, transforming it into a deadly blade.", "You hear organic matter ripping and tearing!")
+
+/obj/item/weapon/melee/arm_blade/dropped(mob/user)
+ user.visible_message("With a sickening crunch, [user] reforms his blade into an arm!", "We assimilate the blade back into our body.", "The airlock's motors resist our efforts to force it."
+ return
+
+ else if(A.locked)
+ user << "The airlock's bolts prevent it from being forced."
+ return
+
+ else
+ //user.say("Heeeeeeeeeerrre's Johnny!")
+ user.visible_message("[user] forces the door to open with \his [src]!", "We force the door to open.", "You hear a metal screeching sound.")
+ A.open(1)
+
+
+/***************************************\
+|****************SHIELD*****************|
+\***************************************/
+/obj/effect/proc_holder/changeling/weapon/shield
+ name = "Organic Shield"
+ desc = "We reform one of our arms into a hard shield."
+ helptext = "Organic tissue cannot resist damage forever, the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form."
+ chemical_cost = 20
+ dna_cost = 1
+ genetic_damage = 12
+ req_human = 1
+ max_genetic_damage = 20
+
+ weapon_type = /obj/item/weapon/shield/changeling
+ weapon_name_simple = "shield"
+
+/obj/effect/proc_holder/changeling/weapon/shield/sting_action(var/mob/user)
+ var/datum/changeling/changeling = user.mind.changeling //So we can read the absorbedcount.
+ if(!changeling)
+ return
+
+ var/obj/item/weapon/shield/changeling/S = ..(user)
+ S.remaining_uses = round(changeling.absorbedcount * 3)
+ return 1
+
+/obj/item/weapon/shield/changeling
+ name = "shield-like mass"
+ desc = "A mass of tough, boney tissue. You can still see the fingers as a twisted pattern in the shield."
+ canremove = 0
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "ling_shield"
+ icon_override = 'icons/mob/in-hand/changeling.dmi'
+
+ var/remaining_uses //Set by the changeling ability.
+
+/obj/item/weapon/shield/changeling/New()
+ ..()
+ if(ismob(loc))
+ loc.visible_message("The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!", "We inflate our hand into a strong shield.", "You hear organic matter ripping and tearing!")
+
+/obj/item/weapon/shield/changeling/dropped()
+ qdel(src)
+
+/obj/item/weapon/shield/changeling/IsShield()
+ if(remaining_uses < 1)
+ if(ishuman(loc))
+ var/mob/living/carbon/human/H = loc
+ H.visible_message("With a sickening crunch, [H] reforms his shield into an arm!", "We assimilate our shield into our body", "[loc.name]\'s flesh rapidly inflates, forming a bloated mass around their body!", "We inflate our flesh, creating a spaceproof suit!", "You hear organic matter ripping and tearing!")
+ processing_objects += src
+
+/obj/item/clothing/suit/space/changeling/dropped()
+ qdel(src)
+
+/obj/item/clothing/suit/space/changeling/process()
+ if(ishuman(loc))
+ var/mob/living/carbon/human/H = loc
+ H.reagents.add_reagent("dexalinp", REAGENTS_METABOLISM)
+
+/obj/item/clothing/head/helmet/space/changeling
+ name = "flesh mass"
+ icon_state = "lingspacehelmet"
+ desc = "A covering of pressure and temperature-resistant organic tissue with a glass-like chitin front."
+ flags = HEADCOVERSEYES | BLOCKHAIR | HEADCOVERSMOUTH | STOPSPRESSUREDMAGE
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
+ canremove = 0
+
+/obj/item/clothing/head/helmet/space/changeling/dropped()
+ qdel(src)
+
+
+/***************************************\
+|*****************ARMOR*****************|
+\***************************************/
+/obj/effect/proc_holder/changeling/suit/armor
+ name = "Chitinous Armor"
+ desc = "We turn our skin into tough chitin to protect us from damage."
+ helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Retreating the armor damages our genomes. Cannot be used in lesser form."
+ chemical_cost = 20
+ dna_cost = 2
+ genetic_damage = 11
+ req_human = 1
+ max_genetic_damage = 20
+
+ suit_type = /obj/item/clothing/suit/armor/changeling
+ helmet_type = /obj/item/clothing/head/helmet/changeling
+ suit_name_simple = "armor"
+ helmet_name_simple = "helmet"
+ recharge_slowdown = 0.25
+
+/obj/item/clothing/suit/armor/changeling
+ name = "chitinous mass"
+ desc = "A tough, hard covering of black chitin."
+ icon_state = "lingarmor"
+ body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
+ slowdown = 2
+ armor = list(melee = 65, bullet = 20, laser = 10, energy = 13, bomb = 0, bio = 0, rad = 0)
+ canremove = 0
+ flags_inv = HIDEJUMPSUIT
+ cold_protection = 0
+ heat_protection = 0
+
+/obj/item/clothing/suit/armor/changeling/New()
+ ..()
+ if(ismob(loc))
+ loc.visible_message("[loc.name]\'s flesh turns black, quickly transforming into a hard, chitinous mass!", "We harden our flesh, creating a suit of armor!", "You hear organic matter ripping and tearing!")
+
+/obj/item/clothing/suit/armor/changeling/dropped()
+ qdel(src)
+
+/obj/item/clothing/head/helmet/changeling
+ name = "chitinous mass"
+ desc = "A tough, hard covering of black chitin with transparent chitin in front."
+ icon_state = "lingarmorhelmet"
+ flags = HEADCOVERSEYES | BLOCKHAIR
+ armor = list(melee = 70, bullet = 15, laser = 7,energy = 10, bomb = 5, bio = 2, rad = 0)
+ canremove = 0
+ flags_inv = HIDEEARS
+
+/obj/item/clothing/head/helmet/changeling/dropped()
+ qdel(src)
diff --git a/code/game/gamemodes/changeling/powers/panacea.dm b/code/game/gamemodes/changeling/powers/panacea.dm
new file mode 100644
index 00000000000..f6721af7f47
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/panacea.dm
@@ -0,0 +1,25 @@
+/obj/effect/proc_holder/changeling/panacea
+ name = "Anatomic Panacea"
+ desc = "Expels impurifications from our form; curing diseases, removing toxins and radiation, and resetting our genetic code completely."
+ helptext = "Can be used while unconscious."
+ chemical_cost = 20
+ dna_cost = 1
+ req_stat = UNCONSCIOUS
+
+//Heals the things that the other regenerative abilities don't.
+/obj/effect/proc_holder/changeling/panacea/sting_action(var/mob/user)
+
+ user << "We cleanse impurities from our form."
+ user.reagents.add_reagent("ryetalyn", 10)
+ user.reagents.add_reagent("hyronalin", 10)
+ user.reagents.add_reagent("anti_toxin", 20)
+
+ if(istype(user, /mob/living/carbon))
+ var/mob/living/carbon/C = user
+ if(C.virus2.len)
+ for (var/ID in C.virus2)
+ var/datum/disease2/disease/V = C.virus2[ID]
+ C.antibodies |= V.antigen
+
+ feedback_add_details("changeling_powers","AP")
+ return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm
new file mode 100644
index 00000000000..526172fdf38
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/revive.dm
@@ -0,0 +1,73 @@
+/obj/effect/proc_holder/changeling/revive
+ name = "Regenerate"
+ desc = "We regenerate, healing all damage from our form."
+ req_stat = DEAD
+
+//Revive from regenerative stasis
+/obj/effect/proc_holder/changeling/revive/sting_action(var/mob/living/carbon/user)
+
+ if(user.stat == DEAD)
+ dead_mob_list -= user
+ living_mob_list += user
+ user.stat = CONSCIOUS
+ user.tod = null
+ user.setToxLoss(0)
+ user.setOxyLoss(0)
+ user.setCloneLoss(0)
+ user.setBrainLoss(0)
+ user.SetParalysis(0)
+ user.SetStunned(0)
+ user.SetWeakened(0)
+ user.radiation = 0
+ user.eye_blind = 0
+ user.eye_blurry = 0
+ user.ear_deaf = 0
+ user.ear_damage = 0
+ user.heal_overall_damage(user.getBruteLoss(), user.getFireLoss())
+ user.reagents.clear_reagents()
+ user.germ_level = 0
+ user.next_pain_time = 0
+ user.traumatic_shock = 0
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.restore_blood()
+ H.shock_stage = 0
+ spawn(1)
+ H.fixblood()
+ for(var/organ_name in H.organs_by_name)
+ var/datum/organ/external/O = H.organs_by_name[organ_name]
+ for(var/obj/item/weapon/shard/shrapnel/s in O.implants)
+ if(istype(s))
+ O.implants -= s
+ H.contents -= s
+ del(s)
+ O.amputated = 0
+ O.brute_dam = 0
+ O.burn_dam = 0
+ O.damage_state = "00"
+ O.germ_level = 0
+ O.hidden = null
+ O.number_wounds = 0
+ O.open = 0
+ O.perma_injury = 0
+ O.stage = 0
+ O.status = 0
+ O.trace_chemicals = list()
+ O.wounds = list()
+ O.wound_update_accuracy = 1
+ for(var/n in H.internal_organs_by_name)
+ var/datum/organ/internal/IO = H.internal_organs_by_name[n]
+ IO.damage = 0
+ IO.trace_chemicals = list()
+ H.updatehealth()
+ user << "We have regenerated."
+
+ user.regenerate_icons()
+ user.hud_updateflag |= 1 << HEALTH_HUD
+ user.hud_updateflag |= 1 << STATUS_HUD
+
+ user.status_flags &= ~(FAKEDEATH)
+ user.update_canmove()
+ user.mind.changeling.purchasedpowers -= src
+ feedback_add_details("changeling_powers","CR")
+ return 1
diff --git a/code/game/gamemodes/changeling/powers/shriek.dm b/code/game/gamemodes/changeling/powers/shriek.dm
new file mode 100644
index 00000000000..cb9cc06c62b
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/shriek.dm
@@ -0,0 +1,46 @@
+/obj/effect/proc_holder/changeling/resonant_shriek
+ name = "Resonant Shriek"
+ desc = "Our lungs and vocal chords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded."
+ helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors."
+ chemical_cost = 20
+ dna_cost = 1
+ req_human = 1
+
+//A flashy ability, good for crowd control and sewing chaos.
+/obj/effect/proc_holder/changeling/resonant_shriek/sting_action(var/mob/user)
+ for(var/mob/living/M in get_mobs_in_view(4, user))
+ if(iscarbon(M))
+ if(!M.mind || !M.mind.changeling)
+ M.ear_deaf = max(0, M.ear_deaf + 30)
+ M.ear_damage = max(0, M.ear_damage)
+ M.confused += 20
+ M.Jitter(50)
+ else
+ M << sound('sound/effects/screech.ogg')
+
+ if(issilicon(M))
+ M << sound('sound/weapons/flash.ogg')
+ M.Weaken(rand(5,10))
+
+ for(var/obj/machinery/light/L in range(4, user))
+ L.on = 1
+ L.broken()
+
+ feedback_add_details("changeling_powers","RS")
+ return 1
+
+/obj/effect/proc_holder/changeling/dissonant_shriek
+ name = "Dissonant Shriek"
+ desc = "We shift our vocal cords to release a high-frequency sound that overloads nearby electronics."
+ chemical_cost = 20
+ dna_cost = 1
+
+//A flashy ability, good for crowd control and sewing chaos.
+/obj/effect/proc_holder/changeling/dissonant_shriek/sting_action(var/mob/user)
+ for(var/obj/machinery/light/L in range(5, usr))
+ L.on = 1
+ L.broken()
+ empulse(get_turf(user), 2, 5, 1)
+ return 1
+
+
diff --git a/code/game/gamemodes/changeling/powers/spiders.dm b/code/game/gamemodes/changeling/powers/spiders.dm
new file mode 100644
index 00000000000..52f8ecd31bd
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/spiders.dm
@@ -0,0 +1,16 @@
+/obj/effect/proc_holder/changeling/spiders
+ name = "Spread Infestation"
+ desc = "Our form divides, creating arachnids which will grow into deadly beasts."
+ helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 5 DNA absorptions."
+ chemical_cost = 45
+ dna_cost = 1
+ req_dna = 5
+
+//Makes some spiderlings. Good for setting traps and causing general trouble.
+/obj/effect/proc_holder/changeling/spiders/sting_action(var/mob/user)
+ for(var/i=0, i<4, i++)
+ var/obj/effect/spider/spiderling/S = new(user.loc)
+ S.grow_as = /mob/living/simple_animal/hostile/giant_spider/hunter
+
+ feedback_add_details("changeling_powers","SI")
+ return 1
diff --git a/code/game/gamemodes/changeling/powers/strained_muscles.dm b/code/game/gamemodes/changeling/powers/strained_muscles.dm
new file mode 100644
index 00000000000..7c5cded0c91
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/strained_muscles.dm
@@ -0,0 +1,51 @@
+//Strained Muscles: Temporary speed boost at the cost of rapid damage
+//Limited because of hardsuits and such; ideally, used for a quick getaway
+
+/obj/effect/proc_holder/changeling/strained_muscles
+ name = "Strained Muscles"
+ desc = "We evolve the ability to reduce the acid buildup in our muscles, allowing us to move much faster."
+ helptext = "The strain will make us tired, and we will rapidly become fatigued. Standard weight restrictions, like hardsuits, still apply. Cannot be used in lesser form."
+ chemical_cost = 0
+ dna_cost = 1
+ req_human = 1
+ var/stacks = 0 //Increments every 5 seconds; damage increases over time
+ var/active = 0 //Whether or not you are a hedgehog
+
+/obj/effect/proc_holder/changeling/strained_muscles/sting_action(var/mob/living/carbon/user)
+ active = !active
+ if(active)
+ user << "Our muscles tense and strengthen."
+ else
+ user.status_flags &= ~GOTTAGOFAST
+ user << "Our muscles relax."
+ if(stacks >= 10)
+ user << "We collapse in exhaustion."
+ user.Weaken(3)
+ user.emote("gasp")
+
+ while(active)
+ user.status_flags |= GOTTAGOFAST
+ if(user.stat || user.staminaloss >= 90)
+ active = 0 //Let's use something exact instead of !active where we can.
+ user << "Our muscles relax without the energy to strengthen them."
+ user.status_flags &= ~GOTTAGOFAST
+ user.Weaken(2)
+ user.emote("gasp")
+ break
+
+ stacks++
+ //user.take_organ_damage(stacks * 0.03, 0)
+ user.staminaloss += stacks * 1.3 //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack
+
+ if(stacks == 11) //Warning message that the stacks are getting too high
+ user << "Our legs are really starting to hurt..."
+
+ sleep(40)
+
+ while(!active) //Damage stacks decrease fairly rapidly while not in sanic mode
+ if(stacks >= 1)
+ stacks--
+ sleep(20)
+
+ feedback_add_details("changeling_powers","SANIC")
+ return 1
diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm
new file mode 100644
index 00000000000..d7820d11188
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm
@@ -0,0 +1,191 @@
+/obj/effect/proc_holder/changeling/sting
+ name = "Tiny Prick"
+ desc = "Stabby stabby"
+ var/sting_icon = null
+
+/obj/effect/proc_holder/changeling/sting/Click()
+ var/mob/user = usr
+ if(!user || !user.mind || !user.mind.changeling)
+ return
+ if(!(user.mind.changeling.chosen_sting))
+ set_sting(user)
+ else
+ unset_sting(user)
+ return
+
+/obj/effect/proc_holder/changeling/sting/proc/set_sting(var/mob/user)
+ user << "We prepare our sting, use alt+click or middle mouse button on target to sting them."
+ user.mind.changeling.chosen_sting = src
+
+/obj/effect/proc_holder/changeling/sting/proc/unset_sting(var/mob/user)
+ user << "We retract our sting, we can't sting anyone for now."
+ user.mind.changeling.chosen_sting = null
+
+/mob/living/carbon/proc/unset_sting()
+ if(mind && mind.changeling && mind.changeling.chosen_sting)
+ src.mind.changeling.chosen_sting.unset_sting(src)
+
+/obj/effect/proc_holder/changeling/sting/can_sting(var/mob/user, var/mob/target)
+ if(!..())
+ return
+ if(!user.mind.changeling.chosen_sting)
+ user << "We haven't prepared our sting yet!"
+ if(!iscarbon(target))
+ return
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(H.species.flags & IS_SYNTHETIC)
+ user << "This won't work on synthetics."
+ return
+ if(!isturf(user.loc))
+ return
+ if(get_dist(user, target) > (user.mind.changeling.sting_range))
+ return //sanity check as AStar is still throwing insane stunts
+ if(!AStar(user.loc, target.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, user.mind.changeling.sting_range))
+ return //hope this ancient magic still works
+ if(target.mind && target.mind.changeling)
+ sting_feedback(user,target)
+ take_chemical_cost(user.mind.changeling)
+ return
+ return 1
+
+/obj/effect/proc_holder/changeling/sting/sting_feedback(var/mob/user, var/mob/target)
+ if(!target)
+ return
+ user << "We stealthily sting [target.name]."
+ if(target.mind && target.mind.changeling)
+ target << "You feel a tiny prick."
+ add_logs(target, user, "unsuccessfully stung")
+ return 1
+
+
+/obj/effect/proc_holder/changeling/sting/transformation
+ name = "Transformation Sting"
+ desc = "We silently sting a human, injecting a retrovirus that forces them to transform."
+ helptext = "Does not provide a warning to others. The victim will transform much like a changeling would."
+ sting_icon = "sting_transform"
+ chemical_cost = 40
+ dna_cost = 2
+ var/datum/dna/selected_dna = null
+
+/obj/effect/proc_holder/changeling/sting/transformation/Click()
+ var/mob/user = usr
+ var/datum/changeling/changeling = user.mind.changeling
+ if(changeling.chosen_sting)
+ unset_sting(user)
+ return
+ selected_dna = changeling.select_dna("Select the target DNA: ", "Target DNA")
+ if(!selected_dna)
+ return
+ ..()
+
+/obj/effect/proc_holder/changeling/sting/transformation/can_sting(var/mob/user, var/mob/target)
+ if(!..())
+ return
+ if((M_HUSK in target.mutations) || (!ishuman(target) && !ismonkey(target)))
+ user << "Our sting appears ineffective against its DNA."
+ return 0
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(H.species.flags & NO_SCAN) //Prevents transforming slimes and killing them instantly
+ user << "This won't work on a creature with abnormal genetic material."
+ return 0
+ return 1
+
+/obj/effect/proc_holder/changeling/sting/transformation/sting_action(var/mob/user, var/mob/target)
+ add_logs(target, user, "stung", object="transformation sting", addition=" new identity is [selected_dna.real_name]")
+ var/datum/dna/NewDNA = selected_dna
+ if(ismonkey(target))
+ user << "We stealthily sting [target.name]."
+ target.dna = NewDNA.Clone()
+ target.real_name = NewDNA.real_name
+ var/mob/living/carbon/human/H = target
+ if(istype(H))
+ H.set_species()
+ target.UpdateAppearance()
+ domutcheck(target, null)
+ feedback_add_details("changeling_powers","TS")
+ return 1
+
+obj/effect/proc_holder/changeling/sting/extract_dna
+ name = "Extract DNA Sting"
+ desc = "We stealthily sting a target and extract their DNA."
+ helptext = "Will give you the DNA of your target, allowing you to transform into them."
+ sting_icon = "sting_extract"
+ chemical_cost = 25
+ dna_cost = 0
+
+/obj/effect/proc_holder/changeling/sting/extract_dna/can_sting(var/mob/user, var/mob/target)
+ if(..())
+ return user.mind.changeling.can_absorb_dna(user, target)
+
+/obj/effect/proc_holder/changeling/sting/extract_dna/sting_action(var/mob/user, var/mob/living/carbon/human/target)
+ add_logs(target, user, "stung", object="extraction sting")
+ if(!(user.mind.changeling.has_dna(target.dna)))
+ user.mind.changeling.absorb_dna(target, user)
+ feedback_add_details("changeling_powers","ED")
+ return 1
+
+obj/effect/proc_holder/changeling/sting/mute
+ name = "Mute Sting"
+ desc = "We silently sting a human, completely silencing them for a short time."
+ helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot."
+ sting_icon = "sting_mute"
+ chemical_cost = 20
+ dna_cost = 2
+
+/obj/effect/proc_holder/changeling/sting/mute/sting_action(var/mob/user, var/mob/living/carbon/target)
+ add_logs(target, user, "stung", object="mute sting")
+ target.silent += 30
+ feedback_add_details("changeling_powers","MS")
+ return 1
+
+obj/effect/proc_holder/changeling/sting/blind
+ name = "Blind Sting"
+ desc = "Temporarily blinds the target."
+ helptext = "This sting completely blinds a target for a short time."
+ sting_icon = "sting_blind"
+ chemical_cost = 25
+ dna_cost = 1
+
+/obj/effect/proc_holder/changeling/sting/blind/sting_action(var/mob/user, var/mob/target)
+ add_logs(target, user, "stung", object="blind sting")
+ target << "Your eyes burn horrifically!"
+ target.disabilities |= NEARSIGHTED
+ target.eye_blind = 20
+ target.eye_blurry = 40
+ feedback_add_details("changeling_powers","BS")
+ return 1
+
+obj/effect/proc_holder/changeling/sting/LSD
+ name = "Hallucination Sting"
+ desc = "Causes terror in the target."
+ helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect occurs after 30 to 60 seconds."
+ sting_icon = "sting_lsd"
+ chemical_cost = 10
+ dna_cost = 1
+
+/obj/effect/proc_holder/changeling/sting/LSD/sting_action(var/mob/user, var/mob/living/carbon/target)
+ add_logs(target, user, "stung", object="LSD sting")
+ spawn(rand(300,600))
+ if(target)
+ target.hallucination = max(400, target.hallucination)
+ feedback_add_details("changeling_powers","HS")
+ return 1
+/*
+obj/effect/proc_holder/changeling/sting/cryo //Enable when mob cooling is fixed so that frostoil actually makes you cold, instead of mostly just hungry.
+ name = "Cryogenic Sting"
+ desc = "We silently sting a human with a cocktail of chemicals that freeze them."
+ helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing."
+ sting_icon = "sting_cryo"
+ chemical_cost = 15
+ dna_cost = 2
+
+/obj/effect/proc_holder/changeling/sting/cryo/sting_action(var/mob/user, var/mob/target)
+ add_logs(target, user, "stung", object="cryo sting")
+ if(target.reagents)
+ target.reagents.add_reagent("frostoil", 30)
+ target.reagents.add_reagent("ice", 30)
+ feedback_add_details("changeling_powers","CS")
+ return 1
+*/
diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm
new file mode 100644
index 00000000000..b6a9cf0af30
--- /dev/null
+++ b/code/game/gamemodes/changeling/powers/transform.dm
@@ -0,0 +1,37 @@
+/obj/effect/proc_holder/changeling/transform
+ name = "Transform"
+ desc = "We take on the appearance and voice of one we have absorbed."
+ chemical_cost = 5
+ dna_cost = 0
+ req_dna = 1
+ req_human = 1
+ max_genetic_damage = 3
+
+//Change our DNA to that of somebody we've absorbed.
+/obj/effect/proc_holder/changeling/transform/sting_action(var/mob/living/carbon/human/user)
+ var/datum/changeling/changeling = user.mind.changeling
+ var/datum/dna/chosen_dna = changeling.select_dna("Select the target DNA: ", "Target DNA")
+
+ if(!chosen_dna)
+ return
+ user.dna = chosen_dna.Clone()
+ user.real_name = chosen_dna.real_name
+ user.flavor_text = ""
+ if(ishuman(user))
+ user.set_species()
+ user.UpdateAppearance()
+ domutcheck(user, null)
+
+ feedback_add_details("changeling_powers","TR")
+ return 1
+
+/datum/changeling/proc/select_dna(var/prompt, var/title)
+ var/list/names = list()
+ for(var/datum/dna/DNA in (absorbed_dna+protected_dna))
+ names += "[DNA.real_name]"
+
+ var/chosen_name = input(prompt, title, null) as null|anything in names
+ if(!chosen_name)
+ return
+ var/datum/dna/chosen_dna = GetDNA(chosen_name)
+ return chosen_dna
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/traitor_chan.dm b/code/game/gamemodes/changeling/traitor_chan.dm
index 193a2e3574d..ce4c8f77887 100644
--- a/code/game/gamemodes/changeling/traitor_chan.dm
+++ b/code/game/gamemodes/changeling/traitor_chan.dm
@@ -7,7 +7,7 @@
required_players_secret = 10
required_enemies = 2
recommended_enemies = 3
- var/protected_species_changeling = list("Machine")
+ var/protected_species_changeling = list("Machine", "Slime People")
/datum/game_mode/traitor/changeling/announce()
world << "The current game mode is - Traitor+Changeling!"
@@ -24,11 +24,11 @@
for(var/job in restricted_jobs)//Removing robots from the list
if(player.assigned_role == job)
possible_changelings -= player
-
+
for(var/mob/new_player/player in player_list)
if((player.mind in possible_changelings) && (player.client.prefs.species in protected_species_changeling))
possible_changelings -= player.mind
-
+
if(possible_changelings.len>0)
var/datum/mind/changeling = pick(possible_changelings)
//possible_changelings-=changeling
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 964001722af..e5157e50bd9 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -30,7 +30,7 @@ datum/objective
proc/find_target()
var/list/possible_targets = list()
for(var/datum/mind/possible_target in ticker.minds)
- if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2))
+ if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != DEAD))
possible_targets += possible_target
if(possible_targets.len > 0)
target = pick(possible_targets)
@@ -38,7 +38,7 @@ datum/objective
proc/find_target_by_role(role, role_type=0)//Option sets either to check assigned role or special role. Default to assigned.
var/list/possible_targets = list()
for(var/datum/mind/possible_target in ticker.minds)
- if((possible_target != owner) && ishuman(possible_target.current) && ((role_type ? possible_target.special_role : possible_target.assigned_role) == role) && (possible_target.current.stat != 2) )
+ if((possible_target != owner) && ishuman(possible_target.current) && ((role_type ? possible_target.special_role : possible_target.assigned_role) == role) && (possible_target.current.stat != DEAD) )
possible_targets += possible_target
if(possible_targets.len > 0)
target = pick(possible_targets)
@@ -47,7 +47,7 @@ datum/objective
proc/find_target_with_special_role(role)
var/list/possible_targets = list()
for(var/datum/mind/possible_target in ticker.minds)
- if((possible_target != owner) && ishuman(possible_target.current) && (role && possible_target.special_role == role || !role && possible_target.special_role) && (possible_target.current.stat != 2) )
+ if((possible_target != owner) && ishuman(possible_target.current) && (role && possible_target.special_role == role || !role && possible_target.special_role) && (possible_target.current.stat != DEAD) )
possible_targets += possible_target
if(possible_targets.len > 0)
target = pick(possible_targets)
@@ -385,7 +385,7 @@ datum/objective/block
for(var/mob/living/player in player_list)
if(player.type in protected_mobs) continue
if (player.mind)
- if (player.stat != 2)
+ if (player.stat != DEAD)
if (get_turf(player) in shuttle)
return 0
return 1
@@ -420,7 +420,7 @@ datum/objective/escape
return 0
if(!emergency_shuttle.returned())
return 0
- if(!owner.current || owner.current.stat ==2)
+ if(!owner.current || owner.current.stat == DEAD)
return 0
var/turf/location = get_turf(owner.current.loc)
if(!location)
@@ -451,7 +451,14 @@ datum/objective/escape/escape_with_identity
var/target_real_name // Has to be stored because the target's real_name can change over the course of the round
find_target()
- target = ..()
+ var/list/possible_targets = list() //Copypasta because NO_SCAN races, yay for snowflakes.
+ for(var/datum/mind/possible_target in ticker.minds)
+ if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != DEAD))
+ var/mob/living/carbon/human/H = possible_target.current
+ if(!(H.species.flags & NO_SCAN))
+ possible_targets += possible_target
+ if(possible_targets.len > 0)
+ target = pick(possible_targets)
if(target && target.current)
target_real_name = target.current.real_name
explanation_text = "Escape on the shuttle or an escape pod with the identity of [target_real_name], the [target.assigned_role] while wearing their identification card."
@@ -658,7 +665,7 @@ datum/objective/download
check_completion()
if(!ishuman(owner.current))
return 0
- if(!owner.current || owner.current.stat == 2)
+ if(!owner.current || owner.current.stat == DEAD)
return 0
if(!(istype(owner.current:wear_suit, /obj/item/clothing/suit/space/space_ninja)&&owner.current:wear_suit:s_initialized))
return 0
@@ -685,25 +692,25 @@ datum/objective/capture
var/captured_amount = 0
var/area/ninja/holding/A = locate()
for(var/mob/living/carbon/human/M in A)//Humans.
- if(M.stat==2)//Dead folks are worth less.
+ if(M.stat == DEAD)//Dead folks are worth less.
captured_amount+=0.5
continue
captured_amount+=1
for(var/mob/living/carbon/monkey/M in A)//Monkeys are almost worthless, you failure.
captured_amount+=0.1
for(var/mob/living/carbon/alien/larva/M in A)//Larva are important for research.
- if(M.stat==2)
+ if(M.stat == DEAD)
captured_amount+=0.5
continue
captured_amount+=1
for(var/mob/living/carbon/alien/humanoid/M in A)//Aliens are worth twice as much as humans.
if(istype(M, /mob/living/carbon/alien/humanoid/queen))//Queens are worth three times as much as humans.
- if(M.stat==2)
+ if(M.stat == DEAD)
captured_amount+=1.5
else
captured_amount+=3
continue
- if(M.stat==2)
+ if(M.stat == DEAD)
captured_amount+=1
continue
captured_amount+=2
@@ -743,7 +750,7 @@ datum/objective/destroy
var/mob/living/silicon/ai/target_ai = pick(possible_targets)
target = target_ai.mind
if(target && target.current)
- explanation_text = "Destroy [target.name], the experimental AI."
+ explanation_text = "Destroy [target.current.real_name], the experimental AI."
else
explanation_text = "Free Objective"
return target
@@ -845,7 +852,7 @@ datum/objective/heist/kidnap
var/list/priority_targets = list()
for(var/datum/mind/possible_target in ticker.minds)
- if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && (possible_target.assigned_role != "MODE"))
+ if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && (possible_target.assigned_role != "MODE"))
possible_targets += possible_target
for(var/role in roles)
if(possible_target.assigned_role == role)
@@ -865,7 +872,7 @@ datum/objective/heist/kidnap
check_completion()
if(target && target.current)
- if (target.current.stat == 2)
+ if (target.current.stat == DEAD)
return 0 // They're dead. Fail.
//if (!target.current.restrained())
// return 0 // They're loose. Close but no cigar.
diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm
index 150911e29d6..e5c19a016be 100644
--- a/code/game/gamemodes/traitor/traitor.dm
+++ b/code/game/gamemodes/traitor/traitor.dm
@@ -107,7 +107,7 @@
assign_exchange_role(exchange_blue)
else
var/list/active_ais = active_ais()
- if(active_ais.len && prob(100/num_players()))
+ if(active_ais.len && prob(4)) // Leaving this at a flat chance for now, problems with the num_players() proc due to latejoin antags.
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = traitor
destroy_objective.find_target()
@@ -143,7 +143,7 @@
traitor.objectives += steal_objective
switch(rand(1,100))
if(1 to 30) // Die glorious death
- if (!(locate(/datum/objective/die) in traitor.objectives) && !(locate(/datum/objective/steal) in traitor.objectives))
+ if (!(locate(/datum/objective/die) in traitor.objectives) && !(locate(/datum/objective/steal) in traitor.objectives) && !(locate(/datum/objective/steal/exchange) in traitor.objectives) && !(locate(/datum/objective/steal/exchange/backstab) in traitor.objectives))
var/datum/objective/die/die_objective = new
die_objective.owner = traitor
traitor.objectives += die_objective
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index 968a166a153..bc0cfb1f7a4 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -67,7 +67,7 @@
/obj/machinery/portable_atmospherics/canister/sleeping_agent
name = "Canister: \[N2O\]"
icon_state = "redws"
- _color = list("redsw", null, null, null)
+ _color = list("redws", null, null, null)
can_label = 0
/obj/machinery/portable_atmospherics/canister/nitrogen
name = "Canister: \[N2\]"
@@ -119,11 +119,16 @@
else
update_flag |= 32
- if(oldcolor != _color || olddecals != decals)
+ if(list2params(oldcolor) == list2params(_color))
update_flag |= 64
- olddecals = decals
+ else
oldcolor = _color
+ if(list2params(olddecals) == list2params(decals))
+ update_flag |= 128
+ else
+ olddecals = decals
+
if(update_flag == old_flag)
return 1
else
@@ -138,7 +143,8 @@ update_flag
8 = tank_pressure < ONE_ATMOS
16 = tank_pressure < 15*ONE_ATMOS
32 = tank_pressure go boom.
-64 = decals/colors got changed
+64 = colors
+128 = decals
*/
if (src.destroyed)
@@ -177,6 +183,7 @@ update_flag
overlays += "can-o2"
else if(update_flag & 32)
overlays += "can-o3"
+ check_change()//call this here to update the bitflag, incase the canister gets relabeled instantly after again
return
/obj/machinery/portable_atmospherics/canister/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
@@ -416,7 +423,12 @@ update_flag
decals = list()
- var/list/tempposdecals = possibledecals
+ var/list/tempposdecals = list()
+
+ for(var/d in possibledecals)//populate the temp list
+ tempposdecals.Add(d)
+ tempposdecals[d] = possibledecals[d]
+
while (src && !src.gc_destroyed && usr)//allow the user to select (theoretically) INFINITE DECALS!!!
var/newdecal = input("Choose canister label", "Decal") as anything in tempposdecals
if (newdecal == "Done")
diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm
index 632fe6aae60..7692b31e3e4 100644
--- a/code/game/machinery/computer/robot.dm
+++ b/code/game/machinery/computer/robot.dm
@@ -123,7 +123,7 @@
if (istype(I))
if(src.check_access(I))
if (!status)
- message_admins("\blue [key_name_admin(usr)] has initiated the global cyborg killswitch!")
+ msg_admin_attack("\blue [key_name_admin(usr)] has initiated the global cyborg killswitch!")
log_game("\blue [key_name(usr)] has initiated the global cyborg killswitch!")
use_log += text("\[[time_stamp()]\] [usr.name] ([usr.ckey]) has initiated the global cyborg killswitch!")
src.status = 1
@@ -169,7 +169,7 @@
R.ResetSecurityCodes()
else
- message_admins("\blue [key_name_admin(usr)] detonated [R.name]!")
+ msg_admin_attack("\blue [key_name_admin(usr)] detonated [R.name]!")
log_game("\blue [key_name_admin(usr)] detonated [R.name]!")
use_log += text("\[[time_stamp()]\] [usr.name] ([usr.ckey]) detonated [R.name] ([R.ckey])!")
R.self_destruct()
@@ -183,7 +183,7 @@
var/choice = input("Are you certain you wish to [R.canmove ? "lock down" : "release"] [R.name]?") in list("Confirm", "Abort")
if(choice == "Confirm")
if(R && istype(R))
- message_admins("\blue [key_name_admin(usr)] [R.canmove ? "locked down" : "released"] [R.name]!")
+ msg_admin_attack("\blue [key_name_admin(usr)] [R.canmove ? "locked down" : "released"] [R.name]!")
log_game("[key_name(usr)] [R.canmove ? "locked down" : "released"] [R.name]!")
R.canmove = !R.canmove
if (R.lockcharge)
@@ -208,7 +208,7 @@
var/choice = input("Are you certain you wish to hack [R.name]?") in list("Confirm", "Abort")
if(choice == "Confirm")
if(R && istype(R))
-// message_admins("\blue [key_name_admin(usr)] emagged [R.name] using robotic console!")
+ msg_admin_attack("\blue [key_name_admin(usr)] emagged [R.name] using robotic console!")
log_game("[key_name(usr)] emagged [R.name] using robotic console!")
R.emagged = 1
if(R.hud_used)
diff --git a/code/game/machinery/laprecharger.dm b/code/game/machinery/laprecharger.dm
new file mode 100644
index 00000000000..7570227d755
--- /dev/null
+++ b/code/game/machinery/laprecharger.dm
@@ -0,0 +1,101 @@
+//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
+
+/obj/machinery/laprecharger
+ name = "laptop recharger"
+ icon = 'icons/obj/stationobjs.dmi'
+ icon_state = "recharger0"
+ anchored = 1
+ use_power = 1
+ idle_power_usage = 40
+ active_power_usage = 2500
+ var/obj/item/charging = null
+ var/icon_state_charged = "recharger2"
+ var/icon_state_charging = "recharger1"
+ var/icon_state_idle = "recharger0"
+
+/obj/machinery/laprecharger/attackby(obj/item/weapon/G as obj, mob/user as mob)
+ if(istype(user,/mob/living/silicon))
+ return
+ if(istype(G, /obj/item/weapon/gun/energy) || istype(G, /obj/item/weapon/melee/baton))
+ user << "\red The laptop recharger blinks red as you try to insert the item!"
+ return
+ if(istype(G,/obj/item/device/laptop))
+ if(charging)
+ return
+
+
+ // Checks to make sure he's not in space doing it, and that the area got proper power.
+ var/area/a = get_area(src)
+ if(!isarea(a))
+ user << "\red The [name] blinks red as you try to insert the item!"
+ return
+ if(a.power_equip == 0)
+ user << "\red The [name] blinks red as you try to insert the item!"
+ return
+
+ if(istype(G, /obj/item/device/laptop))
+ var/obj/item/device/laptop/L = G
+ if(!L.stored_computer.battery)
+ user << "There's no battery in it!"
+ return
+ user.drop_item()
+ G.loc = src
+ charging = G
+ use_power = 2
+ update_icon()
+ else if(istype(G, /obj/item/weapon/wrench))
+ if(charging)
+ user << "\red Remove the laptop first!"
+ return
+ anchored = !anchored
+ user << "You [anchored ? "attached" : "detached"] the recharger."
+ playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
+
+/obj/machinery/laprecharger/attack_hand(mob/user as mob)
+ add_fingerprint(user)
+
+ if(charging)
+ charging.update_icon()
+ charging.loc = loc
+ charging = null
+ use_power = 1
+ update_icon()
+
+/obj/machinery/laprecharger/attack_paw(mob/user as mob)
+ return attack_hand(user)
+
+/obj/machinery/laprecharger/process()
+ if(stat & (NOPOWER|BROKEN) || !anchored)
+ return
+
+ if(charging)
+ if(istype(charging, /obj/item/device/laptop))
+ var/obj/item/device/laptop/L = charging
+ if(L.stored_computer.battery.charge < L.stored_computer.battery.maxcharge)
+ L.stored_computer.battery.give(1000)
+ icon_state = icon_state_charging
+ use_power(2500)
+ else
+ icon_state = icon_state_charged
+ return
+
+
+/obj/machinery/laprecharger/emp_act(severity)
+ if(stat & (NOPOWER|BROKEN) || !anchored)
+ ..(severity)
+ return
+
+/obj/machinery/laprecharger/update_icon() //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier.
+ if(charging)
+ icon_state = icon_state_charging
+ else
+ icon_state = icon_state_idle
+
+// Atlantis: No need for that copy-pasta code, just use var to store icon_states instead.
+obj/machinery/laprecharger/wallcharger
+ name = "wall laptop recharger"
+ icon = 'icons/obj/stationobjs.dmi'
+ icon_state = "wrecharger0"
+ icon_state_idle = "wrecharger0"
+ icon_state_charging = "wrecharger1"
+ icon_state_charged = "wrecharger2"
diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm
index fcce1742ff9..2aff4b378e7 100644
--- a/code/game/machinery/syndicatebomb.dm
+++ b/code/game/machinery/syndicatebomb.dm
@@ -138,7 +138,7 @@
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
if(payload && !istype(payload, /obj/item/weapon/bombcore/training))
- message_admins("[key_name(user)]? has primed a [name] ([payload]) for detonation at [A.name] (JMP).")
+ msg_admin_attack("[key_name(user)]? has primed a [name] ([payload]) for detonation at [A.name] (JMP).")
log_game("[key_name(user)] has primed a [name] ([payload]) for detonation at [A.name]([bombturf.x],[bombturf.y],[bombturf.z])")
payload.adminlog = "The [src.name] that [key_name(user)] had primed detonated!"
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index beee3a49494..10ac7a44994 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -469,10 +469,10 @@ steam.start() -- spawns the effect
var/more = ""
if(M)
more = "(?)"
- message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1)
+ msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].")
else
- message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1)
+ msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
start()
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index 282abc1b2bc..a3e0d2f7b78 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -51,8 +51,8 @@
A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb).
bombers += "[key_name(user)] attached a [item] to a transfer valve."
- message_admins("[key_name_admin(user)] attached a [item] to a transfer valve.")
- log_game("[key_name_admin(user)] attached a [item] to a transfer valve.")
+ msg_admin_attack("[key_name_admin(user)] attached [item] to a transfer valve.")
+ log_game("[key_name_admin(user)] attached [item] to a transfer valve.")
attacher = user
nanomanager.update_uis(src) // update all UIs attached to src
return
@@ -66,7 +66,7 @@
/obj/item/device/transfer_valve/attack_self(mob/user as mob)
ui_interact(user)
-
+
/obj/item/device/transfer_valve/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
// this is the data which will be sent to the ui
@@ -77,13 +77,13 @@
data["valveOpen"] = valve_open ? 1 : 0
// update the ui if it exists, returns null if no ui is passed/found
- ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "transfer_valve.tmpl", "Tank Transfer Valve", 460, 280)
// when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
+ ui.set_initial_data(data)
// open the new ui window
ui.open()
// auto update every Master Controller tick
@@ -190,7 +190,7 @@
log_str += " Last touched by: [src.fingerprintslast][last_touch_info]"
bombers += log_str
- message_admins(log_str, 0, 1)
+ msg_admin_attack(log_str, 0, 1)
log_game(log_str)
merge_gases()
spawn(20) // In case one tank bursts
diff --git a/code/game/objects/items/policetape.dm b/code/game/objects/items/policetape.dm
index 8a1cc09c7ec..b26ae8cb769 100644
--- a/code/game/objects/items/policetape.dm
+++ b/code/game/objects/items/policetape.dm
@@ -27,7 +27,7 @@
/obj/item/tape/police
name = "police tape"
desc = "A length of police tape. Do not cross."
- req_access = list(access_security)
+ req_one_access = list(access_security,access_forensics_lockers)
icon_base = "police"
/obj/item/taperoll/engineering
diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm
index 2a6def07dca..ba7fae62304 100644
--- a/code/game/objects/items/weapons/grenades/chem_grenade.dm
+++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm
@@ -96,7 +96,7 @@
else if(clown_check(user))
// This used to go before the assembly check, but that has absolutely zero to do with priming the damn thing. You could spam the admins with it.
var/log_str = "[key_name(usr)]? has primed a [name] for detonation at [A.name] (JMP)."
- message_admins(log_str)
+ msg_admin_attack(log_str)
log_game(log_str)
bombers += "[log_str]"
user << "You prime the [name]! [det_time / 10] second\s!"
@@ -144,7 +144,7 @@
var/turf/bombturf = get_turf(loc)
var/area/A = bombturf.loc
var/log_str = "[key_name(usr)]? has completed [name] at [A.name] (JMP) [contained]."
- message_admins(log_str)
+ msg_admin_attack(log_str)
log_game(log_str)
else
user << "You need to add at least one beaker before locking the assembly."
diff --git a/code/game/objects/items/weapons/grenades/ghettobomb.dm b/code/game/objects/items/weapons/grenades/ghettobomb.dm
index e1240629ed2..830e2052bb0 100644
--- a/code/game/objects/items/weapons/grenades/ghettobomb.dm
+++ b/code/game/objects/items/weapons/grenades/ghettobomb.dm
@@ -72,7 +72,7 @@
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
var/log_str = "[key_name(usr)]? has primed a [name] for detonation at [A.name] (JMP)."
- message_admins(log_str)
+ msg_admin_attack(log_str)
log_game(log_str)
bombers += "[log_str]"
if(iscarbon(user))
diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm
index 909dff136e2..bd02b527144 100644
--- a/code/game/objects/items/weapons/grenades/grenade.dm
+++ b/code/game/objects/items/weapons/grenades/grenade.dm
@@ -63,7 +63,7 @@
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
var/log_str = "[key_name(usr)]? has primed a [name] for detonation at [A.name] (JMP)."
- message_admins(log_str)
+ msg_admin_attack(log_str)
log_game(log_str)
bombers += "[log_str]"
if(iscarbon(user))
diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm
index f38c9b477f3..4d80110cc2a 100644
--- a/code/game/objects/items/weapons/twohanded.dm
+++ b/code/game/objects/items/weapons/twohanded.dm
@@ -444,7 +444,7 @@ obj/item/weapon/twohanded/
no_embed = 1
force = 5
force_unwielded = 5
- force_wielded = 20
+ force_wielded = 30
throwforce = 15
throw_range = 1
w_class = 5
@@ -475,29 +475,31 @@ obj/item/weapon/twohanded/
/obj/item/weapon/twohanded/knighthammer/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity)
if(!proximity) return
- if(wielded)
- if(charged == 5)
- charged = 0
- if(istype(A, /mob/living/))
- var/mob/living/Z = A
- if(Z.health < 1)
- Z.visible_message("[Z.name] was blown to peices by the power of [src.name]!", \
- "You feel a powerful blow rip you apart!", \
- "You hear a heavy impact and the sound of ripping flesh!.")
- Z.gib()
- else
- Z.take_organ_damage(0,30)
- Z.visible_message("[Z.name] was sent flying by a blow from the [src.name]!", \
- "You feel a powerful blow connect with your body and send you flying!", \
- "You hear something heavy impact flesh!.")
- var/atom/throw_target = get_edge_target_turf(Z, get_dir(src, get_step_away(Z, src)))
- Z.throw_at(throw_target, 200, 4)
- else if(istype(A, /turf/simulated/wall))
+ if(charged == 5)
+ charged = 0
+ if(istype(A, /mob/living/))
+ var/mob/living/Z = A
+ if(Z.health >= 1)
+ Z.visible_message("[Z.name] was sent flying by a blow from the [src.name]!", \
+ "You feel a powerful blow connect with your body and send you flying!", \
+ "You hear something heavy impact flesh!.")
+ var/atom/throw_target = get_edge_target_turf(Z, get_dir(src, get_step_away(Z, src)))
+ Z.throw_at(throw_target, 200, 4)
+ playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
+ else if(wielded && Z.health < 1)
+ Z.visible_message("[Z.name] was blown to peices by the power of [src.name]!", \
+ "You feel a powerful blow rip you apart!", \
+ "You hear a heavy impact and the sound of ripping flesh!.")
+ Z.gib()
+ playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
+ if(wielded)
+ if(istype(A, /turf/simulated/wall))
var/turf/simulated/wall/Z = A
Z.ex_act(2)
charged = 3
+ playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
else if (istype(A, /obj/structure) || istype(A, /obj/mecha/))
var/obj/Z = A
Z.ex_act(2)
charged = 3
- playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
+ playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm
index 43618e46b73..c420450e5f4 100644
--- a/code/game/objects/items/weapons/weaponry.dm
+++ b/code/game/objects/items/weapons/weaponry.dm
@@ -113,6 +113,11 @@
viewers(user) << "[user] is falling on the [src.name]! It looks like \he's trying to commit suicide."
return(BRUTELOSS)
+/obj/item/weapon/claymore/ceremonial
+ name = "ceremonial claymore"
+ desc = "An engraved and fancy version of the claymore. It appears to be less sharp than it's more functional cousin."
+ force = 20
+
/obj/item/weapon/katana
name = "katana"
desc = "Woefully underpowered in D20"
diff --git a/code/game/objects/structures/engicart.dm b/code/game/objects/structures/engicart.dm
index 1697fff9c48..1257195ddf7 100644
--- a/code/game/objects/structures/engicart.dm
+++ b/code/game/objects/structures/engicart.dm
@@ -5,9 +5,6 @@
icon_state = "cart"
anchored = 0
density = 1
- flags = OPENCONTAINER
- //copypaste sorry
- var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
var/obj/item/stack/sheet/glass/myglass = null
var/obj/item/stack/sheet/metal/mymetal = null
var/obj/item/stack/sheet/plasteel/myplasteel = null
@@ -82,6 +79,21 @@
update_icon()
else
user << fail_msg
+ else if(istype(I, /obj/item/weapon/wrench))
+ if (!anchored && !isinspace())
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
+ user.visible_message( \
+ "[user] tightens \the [src]'s casters.", \
+ " You have tightened \the [src]'s casters.", \
+ "You hear ratchet.")
+ anchored = 1
+ else if(anchored)
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
+ user.visible_message( \
+ "[user] loosens \the [src]'s casters.", \
+ " You have loosened \the [src]'s casters.", \
+ "You hear ratchet.")
+ anchored = 0
else
usr << "You cannot interface your modules [src]!"
diff --git a/code/game/objects/structures/foodcart.dm b/code/game/objects/structures/foodcart.dm
new file mode 100644
index 00000000000..37c030aba81
--- /dev/null
+++ b/code/game/objects/structures/foodcart.dm
@@ -0,0 +1,204 @@
+/obj/structure/foodcart
+ name = "food cart"
+ desc = "A cart for transporting food and drinks."
+ icon = 'icons/obj/foodcart.dmi'
+ icon_state = "cart"
+ anchored = 0
+ density = 1
+ //Food slots
+ var/list/food_slots[6]
+ //var/obj/item/weapon/reagent_containers/food/snacks/food1 = null
+ //var/obj/item/weapon/reagent_containers/food/snacks/food2 = null
+ //var/obj/item/weapon/reagent_containers/food/snacks/food3 = null
+ //var/obj/item/weapon/reagent_containers/food/snacks/food4 = null
+ //var/obj/item/weapon/reagent_containers/food/snacks/food5 = null
+ //var/obj/item/weapon/reagent_containers/food/snacks/food6 = null
+ //Drink slots
+ var/list/drink_slots[6]
+ //var/obj/item/weapon/reagent_containers/food/drinks/drink1 = null
+ //var/obj/item/weapon/reagent_containers/food/drinks/drink2 = null
+ //var/obj/item/weapon/reagent_containers/food/drinks/drink3 = null
+ //var/obj/item/weapon/reagent_containers/food/drinks/drink4 = null
+ //var/obj/item/weapon/reagent_containers/food/drinks/drink5 = null
+ //var/obj/item/weapon/reagent_containers/food/drinks/drink6 = null
+
+/obj/structure/foodcart/proc/put_in_cart(obj/item/I, mob/user)
+ user.drop_item()
+ I.loc = src
+ updateUsrDialog()
+ user << "You put [I] into [src]."
+ return
+
+/obj/structure/foodcart/attackby(obj/item/I, mob/user)
+ var/fail_msg = "There are no open spaces for this in [src]."
+ if(!I.is_robot_module())
+ if(istype(I, /obj/item/weapon/reagent_containers/food/snacks))
+ var/success = 0
+ for(var/s=1,s<=6,s++)
+ if(!food_slots[s])
+ put_in_cart(I, user)
+ food_slots[s]=I
+ update_icon()
+ success = 1
+ break;
+ if(!success)
+ user << fail_msg
+ else if(istype(I, /obj/item/weapon/reagent_containers/food/drinks))
+ var/success = 0
+ for(var/s=1,s<=6,s++)
+ if(!drink_slots[s])
+ put_in_cart(I, user)
+ drink_slots[s]=I
+ update_icon()
+ success = 1
+ break;
+ if(!success)
+ user << fail_msg
+ else if(istype(I, /obj/item/weapon/wrench))
+ if (!anchored && !isinspace())
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
+ user.visible_message( \
+ "[user] tightens \the [src]'s casters.", \
+ " You have tightened \the [src]'s casters.", \
+ "You hear ratchet.")
+ anchored = 1
+ else if(anchored)
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
+ user.visible_message( \
+ "[user] loosens \the [src]'s casters.", \
+ " You have loosened \the [src]'s casters.", \
+ "You hear ratchet.")
+ anchored = 0
+ else
+ usr << "You cannot interface your modules [src]!"
+
+/obj/structure/foodcart/attack_hand(mob/user)
+ user.set_machine(src)
+ var/dat
+ if(food_slots[1])
+ dat += "[food_slots[1]]
"
+ if(food_slots[2])
+ dat += "[food_slots[2]]
"
+ if(food_slots[3])
+ dat += "[food_slots[3]]
"
+ if(food_slots[4])
+ dat += "[food_slots[4]]
"
+ if(food_slots[5])
+ dat += "[food_slots[5]]
"
+ if(food_slots[6])
+ dat += "[food_slots[6]]
"
+ if(drink_slots[1])
+ dat += "[drink_slots[1]]
"
+ if(drink_slots[2])
+ dat += "[drink_slots[2]]
"
+ if(drink_slots[3])
+ dat += "[drink_slots[3]]
"
+ if(drink_slots[4])
+ dat += "[drink_slots[4]]
"
+ if(drink_slots[5])
+ dat += "[drink_slots[5]]
"
+ if(drink_slots[6])
+ dat += "[drink_slots[6]]
"
+ var/datum/browser/popup = new(user, "foodcart", name, 240, 160)
+ popup.set_content(dat)
+ popup.open()
+
+/obj/structure/foodcart/Topic(href, href_list)
+ if(!in_range(src, usr))
+ return
+ if(!isliving(usr))
+ return
+ var/mob/living/user = usr
+ if(href_list["f1"])
+ if(food_slots[1])
+ user.put_in_hands(food_slots[1])
+ user << "You take [food_slots[1]] from [src]."
+ food_slots[1] = null
+ if(href_list["f2"])
+ if(food_slots[2])
+ user.put_in_hands(food_slots[2])
+ user << "You take [food_slots[2]] from [src]."
+ food_slots[2] = null
+ if(href_list["f3"])
+ if(food_slots[3])
+ user.put_in_hands(food_slots[3])
+ user << "You take [food_slots[3]] from [src]."
+ food_slots[3] = null
+ if(href_list["f4"])
+ if(food_slots[4])
+ user.put_in_hands(food_slots[4])
+ user << "You take [food_slots[4]] from [src]."
+ food_slots[4] = null
+ if(href_list["f5"])
+ if(food_slots[5])
+ user.put_in_hands(food_slots[5])
+ user << "You take [food_slots[5]] from [src]."
+ food_slots[5] = null
+ if(href_list["f6"])
+ if(food_slots[6])
+ user.put_in_hands(food_slots[6])
+ user << "You take [food_slots[6]] from [src]."
+ food_slots[6] = null
+ if(href_list["d1"])
+ if(drink_slots[1])
+ user.put_in_hands(drink_slots[1])
+ user << "You take [drink_slots[1]] from [src]."
+ drink_slots[1] = null
+ if(href_list["d2"])
+ if(drink_slots[2])
+ user.put_in_hands(drink_slots[2])
+ user << "You take [drink_slots[2]] from [src]."
+ drink_slots[2] = null
+ if(href_list["d3"])
+ if(drink_slots[3])
+ user.put_in_hands(drink_slots[3])
+ user << "You take [drink_slots[3]] from [src]."
+ drink_slots[3] = null
+ if(href_list["d4"])
+ if(drink_slots[4])
+ user.put_in_hands(drink_slots[4])
+ user << "You take [drink_slots[4]] from [src]."
+ drink_slots[4] = null
+ if(href_list["d5"])
+ if(drink_slots[5])
+ user.put_in_hands(drink_slots[5])
+ user << "You take [drink_slots[5]] from [src]."
+ drink_slots[5] = null
+ if(href_list["d6"])
+ if(drink_slots[6])
+ user.put_in_hands(drink_slots[6])
+ user << "You take [drink_slots[6]] from [src]."
+ drink_slots[6] = null
+
+ update_icon() //Not really needed without overlays, but keeping just in case
+ updateUsrDialog()
+
+/*
+Overlays for cart_unused
+/obj/structure/foodcart/update_icon()
+ overlays = null
+ if(food1)
+ overlays += "cart_food1"
+ if(food2)
+ overlays += "cart_food2"
+ if(food3)
+ overlays += "cart_food3"
+ if(food4)
+ overlays += "cart_food4"
+ if(food5)
+ overlays += "cart_food5"
+ if(food6)
+ overlays += "cart_food6"
+ if(drink1)
+ overlays += "cart_drink1"
+ if(drink2)
+ overlays += "cart_drink2"
+ if(drink3)
+ overlays += "cart_drink3"
+ if(drink4)
+ overlays += "cart_drink4"
+ if(drink5)
+ overlays += "cart_drink5"
+ if(drink6)
+ overlays += "cart_drink6"
+*/
\ No newline at end of file
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index 9ca2d7cbdb4..e6c7105796c 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -482,14 +482,29 @@
update_icon()
else
user << "[src] can't hold any more signs."
- else if(mybag)
- mybag.attackby(I, user)
else if(istype(I, /obj/item/weapon/crowbar))
user.visible_message("[user] begins to empty the contents of [src].")
if(do_after(user, 30))
usr << "You empty the contents of [src]'s bucket onto the floor."
reagents.reaction(src.loc)
src.reagents.clear_reagents()
+ else if(istype(I, /obj/item/weapon/wrench))
+ if (!anchored && !isinspace())
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
+ user.visible_message( \
+ "[user] tightens \the [src]'s casters.", \
+ " You have tightened \the [src]'s casters.", \
+ "You hear ratchet.")
+ anchored = 1
+ else if(anchored)
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
+ user.visible_message( \
+ "[user] loosens \the [src]'s casters.", \
+ " You have loosened \the [src]'s casters.", \
+ "You hear ratchet.")
+ anchored = 0
+ else if(mybag)
+ mybag.attackby(I, user)
else
usr << "You cannot interface your modules [src]!"
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 1c101cf58f4..8cdc2666bc2 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -65,7 +65,7 @@ var/global/wcColored
if(health <= 0)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
- message_admins("Window destroyed by [Proj.firer.name] ([formatPlayerPanel(Proj.firer,Proj.firer.ckey)]) via \an [Proj]! pdiff = [pdiff] at [formatJumpTo(loc)]!")
+ msg_admin_attack("Window destroyed by [Proj.firer.name] ([formatPlayerPanel(Proj.firer,Proj.firer.ckey)]) via \an [Proj]! pdiff = [pdiff] at [formatJumpTo(loc)]!")
log_admin("Window destroyed by ([Proj.firer.ckey]) via \an [Proj]! pdiff = [pdiff] at [loc]!")
destroy()
return
@@ -135,19 +135,19 @@ var/global/wcColored
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
if(M)
- message_admins("Window with pdiff [pdiff] at [formatJumpTo(loc)] deanchored by [M.real_name] ([formatPlayerPanel(M,M.ckey)])!")
+ msg_admin_attack("Window with pdiff [pdiff] at [formatJumpTo(loc)] deanchored by [M.real_name] ([formatPlayerPanel(M,M.ckey)])!")
log_admin("Window with pdiff [pdiff] at [loc] deanchored by [M.real_name] ([M.ckey])!")
else
- message_admins("Window with pdiff [pdiff] at [formatJumpTo(loc)] deanchored by [AM]!")
+ msg_admin_attack("Window with pdiff [pdiff] at [formatJumpTo(loc)] deanchored by [AM]!")
log_admin("Window with pdiff [pdiff] at [loc] deanchored by [AM]!")
if(health <= 0)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
if(M)
- message_admins("Window with pdiff [pdiff] at [formatJumpTo(loc)] destroyed by [M.real_name] ([formatPlayerPanel(M,M.ckey)])!")
+ msg_admin_attack("Window with pdiff [pdiff] at [formatJumpTo(loc)] destroyed by [M.real_name] ([formatPlayerPanel(M,M.ckey)])!")
log_admin("Window with pdiff [pdiff] at [loc] destroyed by [M.real_name] ([M.ckey])!")
else
- message_admins("Window with pdiff [pdiff] at [formatJumpTo(loc)] destroyed by [AM]!")
+ msg_admin_attack("Window with pdiff [pdiff] at [formatJumpTo(loc)] destroyed by [AM]!")
log_admin("Window with pdiff [pdiff] at [loc] destroyed by [AM]!")
destroy()
@@ -158,7 +158,7 @@ var/global/wcColored
user.visible_message("[user] smashes through [src]!")
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
- message_admins("Window destroyed by hulk [user.real_name] ([formatPlayerPanel(user,user.ckey)]) with pdiff [pdiff] at [formatJumpTo(loc)]!")
+ msg_admin_attack("Window destroyed by hulk [user.real_name] ([formatPlayerPanel(user,user.ckey)]) with pdiff [pdiff] at [formatJumpTo(loc)]!")
log_admin("Window destroyed by hulk [user.real_name] ([user.ckey]) with pdiff [pdiff] at [loc]!")
destroy()
else if (usr.a_intent == "harm")
@@ -183,7 +183,7 @@ var/global/wcColored
user.visible_message("[user] smashes through [src]!")
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
- message_admins("Window destroyed by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) with pdiff [pdiff] at [formatJumpTo(loc)]!")
+ msg_admin_attack("Window destroyed by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) with pdiff [pdiff] at [formatJumpTo(loc)]!")
destroy()
else //for nicer text~
user.visible_message("[user] smashes into [src]!")
@@ -240,7 +240,7 @@ var/global/wcColored
return
if(W.flags & NOBLUDGEON) return
-
+
if(istype(W, /obj/item/weapon/screwdriver))
if(reinf && state >= 1)
state = 3 - state
@@ -254,7 +254,7 @@ var/global/wcColored
if(!anchored)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
- message_admins("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
+ msg_admin_attack("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
log_admin("Window with pdiff [pdiff] deanchored by [user.real_name] ([user.ckey]) at [loc]!")
else if(!reinf)
anchored = !anchored
@@ -264,7 +264,7 @@ var/global/wcColored
if(!anchored)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
- message_admins("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
+ msg_admin_attack("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
log_admin("Window with pdiff [pdiff] deanchored by [user.real_name] ([user.ckey]) at [loc]!")
else if(istype(W, /obj/item/weapon/crowbar) && reinf && state <= 1)
state = 1 - state
@@ -305,7 +305,7 @@ var/global/wcColored
step(src, get_dir(user, src))
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
- message_admins("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
+ msg_admin_attack("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
log_admin("Window with pdiff [pdiff] deanchored by [user.real_name] ([user.ckey]) at [loc]!")
else
playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
@@ -325,7 +325,7 @@ var/global/wcColored
if(health <= 0)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
- message_admins("Window with pdiff [pdiff] broken at [formatJumpTo(loc)]!")
+ msg_admin_attack("Window with pdiff [pdiff] broken at [formatJumpTo(loc)]!")
destroy()
return
diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm
index 93449c76156..6a649a098f8 100644
--- a/code/game/supplyshuttle.dm
+++ b/code/game/supplyshuttle.dm
@@ -210,15 +210,14 @@ var/list/mechtoys = list(
if(slip.stamped && slip.stamped.len) //yes, the clown stamp will work. clown is the highest authority on the station, it makes sense
points += points_per_slip
find_slip = 0
- continue
// Sell phoron
- if(istype(A, /obj/item/stack/sheet/mineral/plasma))
+ else if(istype(A, /obj/item/stack/sheet/mineral/plasma))
var/obj/item/stack/sheet/mineral/plasma/P = A
plasma_count += P.amount
// Sell platinum
- if(istype(A, /obj/item/stack/sheet/mineral/platinum))
+ else if(istype(A, /obj/item/stack/sheet/mineral/platinum))
var/obj/item/stack/sheet/mineral/platinum/P = A
plat_count += P.amount
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index abd1f40f15a..ce1cde9640f 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -1025,7 +1025,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
M.equip_to_slot_or_del(new /obj/item/clothing/glasses/meson/cyber(M), slot_glasses)
M.equip_to_slot_or_del(new /obj/item/clothing/mask/breath(M), slot_wear_mask)
M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/singuloth(M), slot_head)
- M.equip_to_slot_or_del(new /obj/item/weapon/claymore(M), slot_belt)
+ M.equip_to_slot_or_del(new /obj/item/weapon/claymore/ceremonial(M), slot_belt)
M.equip_to_slot_or_del(new /obj/item/weapon/tank/oxygen(M), slot_s_store)
M.equip_to_slot_or_del(new /obj/item/weapon/twohanded/knighthammer(M), slot_back)
diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm
index c8d2c29e92c..d2d6225377f 100644
--- a/code/modules/assembly/bomb.dm
+++ b/code/modules/assembly/bomb.dm
@@ -45,7 +45,7 @@
if(!status)
status = 1
bombers += "[key_name(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]"
- message_admins("[key_name_admin(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]")
+ msg_admin_attack("[key_name_admin(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]")
user << "A pressure hole has been bored to [bombtank] valve. \The [bombtank] can now be ignited."
else
status = 0
diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm
index c4f86593d10..171353f7eb9 100644
--- a/code/modules/client/preferences_mysql.dm
+++ b/code/modules/client/preferences_mysql.dm
@@ -186,7 +186,7 @@
firstquery.Execute()
while(firstquery.NextRow())
if(text2num(firstquery.item[1]) == default_slot)
- var/DBQuery/query = dbcon.NewQuery("UPDATE characters SET OOC_Notes='[sql_sanitize_text(metadata)]',real_name='[sql_sanitize_text(real_name)]',name_is_always_random='[be_random_name]',gender='[gender]',age='[age]',species='[sql_sanitize_text(species)]',language='[sql_sanitize_text(language)]',hair_red='[r_hair]',hair_green='[g_hair]',hair_blue='[b_hair]',facial_red='[r_facial]',facial_green='[g_facial]',facial_blue='[b_facial]',skin_tone='[s_tone]',skin_red='[r_skin]',skin_green='[g_skin]',skin_blue='[b_skin]',hair_style_name='[sql_sanitize_text(h_style)]',facial_style_name='[sql_sanitize_text(f_style)]',eyes_red='[r_eyes]',eyes_green='[g_eyes]',eyes_blue='[b_eyes]',underwear='[underwear]',undershirt='[undershirt]',backbag='[backbag]',b_type='[b_type]',alternate_option='[alternate_option]',job_support_high='[job_support_high]',job_support_med='[job_support_med]',job_support_low='[job_support_low]',job_medsci_high='[job_medsci_high]',job_medsci_med='[job_medsci_med]',job_medsci_low='[job_medsci_low]',job_engsec_high='[job_engsec_high]',job_engsec_med='[job_engsec_med]',job_engsec_low='[job_engsec_low]',job_karma_high='[job_karma_high]',job_karma_med='[job_karma_med]',job_karma_low='[job_karma_low]',flavor_text='[sql_sanitize_text(flavor_text)]',med_record='[sql_sanitize_text(med_record)]',sec_record='[sql_sanitize_text(sec_record)]',gen_record='[sql_sanitize_text(gen_record)]',player_alt_titles='[sql_sanitize_text(playertitlelist)]',be_special='[be_special]',disabilities='[disabilities]',organ_data='[organlist]',nanotrasen_relation='[nanotrasen_relation]', speciesprefs='[speciesprefs]' WHERE ckey='[C.ckey]' AND slot='[default_slot]'")
+ var/DBQuery/query = dbcon.NewQuery("UPDATE characters SET OOC_Notes='[sql_sanitize_text(metadata)]',real_name='[sql_sanitize_text(real_name)]',name_is_always_random='[be_random_name]',gender='[gender]',age='[age]',species='[sql_sanitize_text(species)]',language='[sql_sanitize_text(language)]',hair_red='[r_hair]',hair_green='[g_hair]',hair_blue='[b_hair]',facial_red='[r_facial]',facial_green='[g_facial]',facial_blue='[b_facial]',skin_tone='[s_tone]',skin_red='[r_skin]',skin_green='[g_skin]',skin_blue='[b_skin]',hair_style_name='[sql_sanitize_text(h_style)]',facial_style_name='[sql_sanitize_text(f_style)]',eyes_red='[r_eyes]',eyes_green='[g_eyes]',eyes_blue='[b_eyes]',underwear='[underwear]',undershirt='[undershirt]',backbag='[backbag]',b_type='[b_type]',alternate_option='[alternate_option]',job_support_high='[job_support_high]',job_support_med='[job_support_med]',job_support_low='[job_support_low]',job_medsci_high='[job_medsci_high]',job_medsci_med='[job_medsci_med]',job_medsci_low='[job_medsci_low]',job_engsec_high='[job_engsec_high]',job_engsec_med='[job_engsec_med]',job_engsec_low='[job_engsec_low]',job_karma_high='[job_karma_high]',job_karma_med='[job_karma_med]',job_karma_low='[job_karma_low]',flavor_text='[sql_sanitize_text(flavor_text)]',med_record='[sql_sanitize_text(med_record)]',sec_record='[sql_sanitize_text(sec_record)]',gen_record='[sql_sanitize_text(gen_record)]',player_alt_titles='[playertitlelist]',be_special='[be_special]',disabilities='[disabilities]',organ_data='[organlist]',nanotrasen_relation='[nanotrasen_relation]', speciesprefs='[speciesprefs]' WHERE ckey='[C.ckey]' AND slot='[default_slot]'")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR during character slot saving. Error : \[[err]\]\n")
diff --git a/code/modules/clothing/suits/storage.dm b/code/modules/clothing/suits/storage.dm
index cb03feb5997..c3b5c6f616a 100644
--- a/code/modules/clothing/suits/storage.dm
+++ b/code/modules/clothing/suits/storage.dm
@@ -26,4 +26,18 @@
/obj/item/clothing/suit/storage/hear_talk(mob/M, var/msg)
pockets.hear_talk(M, msg)
- ..()
\ No newline at end of file
+ ..()
+
+/obj/item/clothing/suit/storage/proc/return_inv()
+
+ var/list/L = list( )
+
+ L += src.contents
+
+ for(var/obj/item/weapon/storage/S in src)
+ L += S.return_inv()
+ for(var/obj/item/weapon/gift/G in src)
+ L += G.gift
+ if (istype(G.gift, /obj/item/weapon/storage))
+ L += G.gift:return_inv()
+ return L
\ No newline at end of file
diff --git a/code/modules/clothing/under/accessories/storage.dm b/code/modules/clothing/under/accessories/storage.dm
index 8a215233b08..caa7638befd 100644
--- a/code/modules/clothing/under/accessories/storage.dm
+++ b/code/modules/clothing/under/accessories/storage.dm
@@ -40,6 +40,20 @@
hold.hear_talk(M, msg, verb, speaking)
..()
+/obj/item/clothing/accessory/storage/proc/return_inv()
+
+ var/list/L = list( )
+
+ L += src.contents
+
+ for(var/obj/item/weapon/storage/S in src)
+ L += S.return_inv()
+ for(var/obj/item/weapon/gift/G in src)
+ L += G.gift
+ if (istype(G.gift, /obj/item/weapon/storage))
+ L += G.gift:return_inv()
+ return L
+
/obj/item/clothing/accessory/storage/attack_self(mob/user as mob)
if (has_suit) //if we are part of a suit
hold.open(user)
diff --git a/code/modules/mob/living/simple_animal/friendly/Fox.dm b/code/modules/mob/living/simple_animal/friendly/fox.dm
similarity index 97%
rename from code/modules/mob/living/simple_animal/friendly/Fox.dm
rename to code/modules/mob/living/simple_animal/friendly/fox.dm
index 095445069ca..da38c222b42 100644
--- a/code/modules/mob/living/simple_animal/friendly/Fox.dm
+++ b/code/modules/mob/living/simple_animal/friendly/fox.dm
@@ -30,4 +30,4 @@
icon_living = "Syndifox"
icon_dead = "Syndifox_dead"
flags = IS_SYNTHETIC|NO_BREATHE
- faction = list("syndicate")
\ No newline at end of file
+ faction = list("syndicate")
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 27127a83e4e..39a1fb53631 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -57,18 +57,20 @@
client.verbs |= H.species.abilities
CallHook("Login", list("client" = src.client, "mob" = src))
-
+
//Update morgues on login/logout
if (stat == DEAD)
var/obj/structure/morgue/Morgue = null
var/mob/living/carbon/human/C = null
if (istype(src,/mob/dead/observer)) //We're a ghost, let's find our corpse
var/mob/dead/observer/G = src
+ if(!G.mind) //This'll probably break morgue sprites, but the line under the next If statement causes runtimes with Assume Direct Control.
+ return
if (G.can_reenter_corpse && G.mind.current)
C = G.mind.current
else if (istype(src,/mob/living/carbon/human))
C = src
-
+
if (C) //We found our corpse, is it inside a morgue?
if (istype(C.loc,/obj/structure/morgue))
Morgue = C.loc
@@ -78,4 +80,4 @@
Morgue = B.loc
if (Morgue)
Morgue.update()
-
+
diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm
index 45449c1e1c7..36df2619e38 100644
--- a/code/modules/mob/logout.dm
+++ b/code/modules/mob/logout.dm
@@ -10,18 +10,20 @@
if(admins_number == 0) //Apparently the admin logging out is no longer an admin at this point, so we have to check this towards 0 and not towards 1. Awell.
send2adminirc("[key_name(src)] logged out - no more admins online.")
..()
-
+
//Update morgues on login/logout
if (stat == DEAD)
var/obj/structure/morgue/Morgue = null
var/mob/living/carbon/human/C = null
if (istype(src,/mob/dead/observer)) //We're a ghost, let's find our corpse
var/mob/dead/observer/G = src
+ if(!G.mind) //This'll probably break morgue sprites, but the line under the next If statement causes runtimes with Assume Direct Control.
+ return 1
if (G.can_reenter_corpse && G.mind.current)
C = G.mind.current
else if (istype(src,/mob/living/carbon/human))
C = src
-
+
if (C) //We found our corpse, is it inside a morgue?
if (istype(C.loc,/obj/structure/morgue))
Morgue = C.loc
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 84c4be074f3..d865cb2dde5 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -899,6 +899,9 @@ var/list/slot_equipment_priority = list( \
continue
statpanel(listed_turf.name, null, A)
+ if(mind && mind.changeling)
+ add_stings_to_statpanel(mind.changeling.purchasedpowers)
+
if(spell_list && spell_list.len)
for(var/obj/effect/proc_holder/spell/wizard/S in spell_list)
switch(S.charge_type)
@@ -909,6 +912,11 @@ var/list/slot_equipment_priority = list( \
if("holdervar")
statpanel(S.panel,"[S.holder_var_type] [S.holder_var_amount]",S)
+
+/mob/proc/add_stings_to_statpanel(var/list/stings)
+ for(var/obj/effect/proc_holder/changeling/S in stings)
+ if(S.chemical_cost >=0 && S.can_be_used_by(src))
+ statpanel("[S.panel]",((S.chemical_cost > 0) ? "[S.chemical_cost]" : ""),S)
/* // Why have a duplicate set of turfs in the stat panel?
if(listed_turf)
if(get_dist(listed_turf,src) > 1)
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 4142778e1e3..601d7191f7b 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -40,7 +40,7 @@
src.directwired = 1
/obj/machinery/power/emitter/Destroy()
- message_admins("Emitter deleted at ([x],[y],[z] - JMP)",0,1)
+ msg_admin_attack("Emitter deleted at ([x],[y],[z] - JMP)",0,1)
log_game("Emitter deleted at ([x],[y],[z])")
investigate_log("deleted at ([x],[y],[z])","singulo")
..()
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index da470fbee52..72bbc3804ea 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -350,6 +350,6 @@ field_generator power level display
if(O.last_warning && temp)
if((world.time - O.last_warning) > 50) //to stop message-spam
temp = 0
- message_admins("A singulo exists and a containment field has failed.",1)
+ msg_admin_attack("A singulo exists and a containment field has failed.",1)
investigate_log("has failed whilst a singulo exists.","singulo")
O.last_warning = world.time
diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm
index 4f3a0990476..10ca1d5f5a6 100644
--- a/code/modules/reagents/Chemistry-Recipes.dm
+++ b/code/modules/reagents/Chemistry-Recipes.dm
@@ -730,7 +730,31 @@ datum
required_reagents = list("chlorine" = 1, "hydrogen" = 1, "nitrogen" = 1)
result_amount = 3
-
+///////Changeling Blood Test/////////////
+ changeling_test
+ name = "Changeling blood test"
+ id = "changelingblood"
+ result = "blood"
+ required_reagents = list("blood" = 5)
+ required_catalysts = list("fuel")
+ result_amount = 1 //Needs this in order to check the donor, as the data var in the reacted blood gets transferred.
+ on_reaction(var/datum/reagents/holder, var/created_volume)
+ if(!holder.reagent_list) //reagent_list is not null
+ return
+ var/datum/reagent/blood/B = locate() in holder.reagent_list
+ if(!B) //B is not null
+ return
+ var/mob/living/carbon/human/H = B.data["donor"]
+ if(!H) //H is not null.
+ return
+ if(H.mind && H.mind.changeling) //Checks if H, the blood donor is a ling.
+ for(var/mob/M in viewers(get_turf_loc(holder.my_atom), null))
+ M.show_message( "The blood writhes and wriggles and sizzles away from the container!", 1, "You hear bubbling and sizzling.", 2)
+ else
+ for(var/mob/M in viewers(get_turf_loc(holder.my_atom), null))
+ M.show_message( "The blood seems to break apart in the fuel.", 1)
+ holder.del_reagent("blood")
+ return
/////////////////////////////////////OLD SLIME CORE REACTIONS ///////////////////////////////
/*
slimepepper
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index a7332fc5b92..e24bcb4c90a 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -90,6 +90,23 @@
user << "\red You are unable to locate any blood."
return
+
+ var/time = 30 //Injecting through a hardsuit takes longer due to needing to find a port.
+ if(istype(target,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = T
+ if((H.species.bloodflags & BLOOD_SLIME) || (H.species.flags & NO_BLOOD))
+ usr << "You are unable to locate any blood."
+ return
+ if(H.wear_suit && istype(H.wear_suit,/obj/item/clothing/suit/space))
+ time = 60
+ if(target == user)
+ time = 0
+ else
+ for(var/mob/O in viewers(world.view, user))
+ O.show_message(text("\red [] is trying to take a blood sample from []!", user, target), 1)
+ if(!do_mob(user, target, time))
+ return
+
var/datum/reagent/B
if(istype(T,/mob/living/carbon/human))
var/mob/living/carbon/human/H = T
@@ -105,9 +122,10 @@
src.reagents.update_total()
src.on_reagent_change()
src.reagents.handle_reactions()
- user << "\blue You take a blood sample from [target]"
- for(var/mob/O in viewers(4, user))
- O.show_message("\red [user] takes a blood sample from [target].", 1)
+
+ user << "\blue You take a blood sample from [target]"
+ for(var/mob/O in viewers(4, user))
+ O.show_message("\red [user] takes a blood sample from [target].", 1)
else //if not mob
if(!target.reagents.total_volume)
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index b95ea0c97a9..1d69fd6fecd 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -144,7 +144,7 @@
var/obj/item/device/assembly_holder/H = W
if (istype(H.a_left,/obj/item/device/assembly/igniter) || istype(H.a_right,/obj/item/device/assembly/igniter))
- message_admins("[key_name_admin(user)] rigged fueltank at ([loc.x],[loc.y],[loc.z]) for explosion.")
+ msg_admin_attack("[key_name_admin(user)] rigged fueltank at ([loc.x],[loc.y],[loc.z]) for explosion.")
log_game("[key_name(user)] rigged fueltank at ([loc.x],[loc.y],[loc.z]) for explosion.")
rig = W
diff --git a/code/modules/surgery/braincore.dm b/code/modules/surgery/braincore.dm
index 3ce95d81553..92e2124b619 100644
--- a/code/modules/surgery/braincore.dm
+++ b/code/modules/surgery/braincore.dm
@@ -12,7 +12,8 @@
/datum/surgery_step/brain/saw_skull
allowed_tools = list(
/obj/item/weapon/circular_saw = 100, \
- /obj/item/weapon/hatchet = 75
+ /obj/item/weapon/hatchet = 75, \
+ /obj/item/weapon/melee/arm_blade = 60 // Dr. Chang E. Ling, MD
)
min_duration = 50
@@ -67,7 +68,8 @@
/datum/surgery_step/brain/saw_spine
allowed_tools = list(
/obj/item/weapon/circular_saw = 100, \
- /obj/item/weapon/hatchet = 75
+ /obj/item/weapon/hatchet = 75, \
+ /obj/item/weapon/melee/arm_blade = 60
)
min_duration = 50
diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm
index 17b926ae99a..37e465946bd 100644
--- a/code/modules/surgery/generic.dm
+++ b/code/modules/surgery/generic.dm
@@ -187,7 +187,8 @@
/datum/surgery_step/generic/cut_limb
allowed_tools = list(
/obj/item/weapon/circular_saw = 100, \
- /obj/item/weapon/hatchet = 75
+ /obj/item/weapon/hatchet = 75, \
+ /obj/item/weapon/melee/arm_blade = 60
)
min_duration = 110
diff --git a/code/modules/surgery/ribcage.dm b/code/modules/surgery/ribcage.dm
index cce3a13375b..e9707c1a181 100644
--- a/code/modules/surgery/ribcage.dm
+++ b/code/modules/surgery/ribcage.dm
@@ -12,7 +12,8 @@
/datum/surgery_step/ribcage/saw_ribcage
allowed_tools = list(
/obj/item/weapon/circular_saw = 100, \
- /obj/item/weapon/hatchet = 75
+ /obj/item/weapon/hatchet = 75, \
+ /obj/item/weapon/melee/arm_blade = 60
)
min_duration = 50
@@ -146,7 +147,7 @@
user.visible_message(msg, self_msg)
target.op_stage.ribcage = 0
-
+
//////////////////////////////////////////////////////////////////
// ALIEN EMBRYO SURGERY //
//////////////////////////////////////////////////////////////////
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index c3ac8ef0451..944bd928e1e 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/in-hand/changeling.dmi b/icons/mob/in-hand/changeling.dmi
new file mode 100644
index 00000000000..ab9e0857312
Binary files /dev/null and b/icons/mob/in-hand/changeling.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index bfcb7ce190f..f9244eace02 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/obj/foodcart.dmi b/icons/obj/foodcart.dmi
new file mode 100644
index 00000000000..334eb512993
Binary files /dev/null and b/icons/obj/foodcart.dmi differ
diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi
index e2f6452cdcd..f441c3d5ac4 100644
Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ
diff --git a/interface/interface.dm b/interface/interface.dm
index 54a26a29cf8..e4d6a082d8e 100644
--- a/interface/interface.dm
+++ b/interface/interface.dm
@@ -13,10 +13,10 @@
src << "The wiki URL is not set in the server configuration."
return
-#define CHANGELOG "http://nanotrasen.se/phpBB3/viewtopic.php?f=10&t=36"
+#define CHANGELOG "https://github.com/ParadiseSS13/Paradise/commits/master"
/client/verb/changes()
set name = "Changelog"
- set desc = "Visit the forum to check out the changelog."
+ set desc = "Visit Github to check out the commits."
set hidden = 1
if(alert("This will open the changelog in your browser. Are you sure?",,"Yes","No")=="No")
diff --git a/maps/cyberiad.dmm b/maps/cyberiad.dmm
index cbaf629896a..8d56da4d315 100644
--- a/maps/cyberiad.dmm
+++ b/maps/cyberiad.dmm
@@ -8991,6 +8991,7 @@
"dqU" = (/obj/structure/shuttle/engine/propulsion{tag = "icon-burst_r"; icon_state = "burst_r"},/turf/space,/area/supply/dock)
"dqV" = (/obj/machinery/iv_drip,/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/administration/centcom)
"dqW" = (/obj/structure/table,/obj/item/weapon/storage/box/handcuffs,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/administration/centcom)
+"dqX" = (/obj/structure/foodcart,/turf/simulated/floor{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/kitchen)
"dqY" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/administration/centcom)
"dqZ" = (/obj/structure/table,/obj/item/weapon/bonegel,/obj/item/weapon/bonesetter,/obj/item/weapon/hemostat,/obj/item/weapon/cautery,/obj/item/weapon/surgicaldrill,/obj/item/weapon/circular_saw,/obj/item/weapon/scalpel,/obj/item/weapon/retractor,/obj/item/weapon/FixOVein,/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/administration/centcom)
"dra" = (/obj/machinery/optable,/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/administration/centcom)
@@ -12671,7 +12672,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaGbayaaTzaAPaGdaUYaUZaVaaVbaGdaAPaVcaVdayaaVeaPTaTzaVfaVgaTCaTCaTDaySaVhaRHaDyaTGaRJaViaVjaVkaRLaRLaVlaVmaVnaRLaVoaVpaVqaVpaVraVsaVpaVpaVtaVpaVpaVuaVvaVpaVwaVpaVxaRLaRLaRLaVyaVzaVAaVBaVCaVDaVCaVEaVFaVEaVEaVEaVEaVEaVEaVGaVHaVIaVIaVIaVIaVJaVIaVKaVLaVIaVIaVMaVNaVOaVOaVOaVOaVOaVOaVOaVPaSEaSEaaqaVQaVRaVSaVTaVTaVUaVVaUuaSMaVWaaqaaqaaqaaqaaqaVXaaqaVYaVZaWaaWbaQVaWcaaqaWdaWeaWfaWgaWhaWiaWjaWkaaqaPvaJuaaqaWlaWmaNRaWnaWoaNRaWpaWpaaqaWqaWraWsaaqaWtaWuaWvaMvaMvaWwaWxaOeaWyaaqaWzaUQaURaWAaWBaUQaUQaWCaWDaaaaaaaaaaaaaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaySaDwaTuaPSaERaDyaDyaESaPSaTuaPSaWEaWFaWGaWHaDwaWIaWIaREaWIaRFaySaWJaRHaDyaySaPYaPYaWKaPYaPYaPYaPYaPYaPYaWLaWMaPYaPYaPYaPYaPYaPYaWNaWOaWNaPYaWPaPYaWQaVjaWRaWSaWTaWUaRLaWVaPYaWWaWWaWXaWXaWXaWYaQCaQCaQCaQCaQCaQCaQCaaiaWZaXaaXbaXaaXcaXcaXdaXeaXfaXgaXhaaiaXiaQCaQCaQCaQCaQCaQCaXjaXkaXkaXkaaqaXlaXmaXnaXnaXnaXnaXoaKyaXpaXqaXraXsaXtaXuaXvaXwaaqaaqaXxaXiaXyaQCaXzaaqaXAaXBaXCaXCaXCaXCaXDaXEaaqaXFaJuaaqaXGaNRaWnaWnaWoaWnaNRaXHaaqaXIaXJaXKaaqaMvaXLaXMaXNaXNaXOaXPaXQaXRabZaXSaXTaXUaXVaUSaUQaUQaXWaWDaaaaaaaaaaaaaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaCyaXXaDyaXYaXZaYaaYbaYcaYdaYbaYeaYfaYbaYbbcOaYhaYiaYjaYkaYkaYkaYlaYkaYmaYnaySaYoaYpaYqaYraYsaYtaYuaYvaYwaYxaYyaYzaYAaYBaYCaYDaYEaYFaYGaYHaYEaYIaPYaPYaYJaPYaPYaPYaPYaYKaYLaPYaYMaWWaYNaSeaSjaYOaaaaaaaaaaaaaaaaaaaaaaaiaYPaYQaYRaYSaYTaYUaYVaYWaYXaYYaYZaaiaaaaaaaaaaaaaaaaaaaaaaEFaZaaSEaZbaaqaZcaXmaXqaXqaXqaXqaXqaZdaZeaXqaXqaXqaXtaZfaZfaZgaZhaZiaZjaZkaZlaZmaZnaaqaZoaZpaZqaZraZraZqaZsaZtaaqaPvaZuaaqaZvaZwaNRaWnaWoaNRaZxaZxaaqaaqaZyaaqaaqaZzaWuaWxaZAaZAaZBaWxaOeaaqaaqaZCaUQaZDaZDaZEaZDaUQaZFaWDaaaaaaaaaaZGaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDwaZHaZIaZHaZHaZHaZHaZHaZHaZIaZHaZHaZJaDyaZKaZLaDyaDyaZMaDyaZNaZOaZPaZQaZRaySaYpaYpaZSaYraZTaYxaYxaYxaYxaYxaYyaZUaYxaYxaYxaYxaYEaZVaZWaZXaYEaYIaZYaZZbaababbacaYMbadbaebafbagbahbaiaYNaSeaSjaYOaaaaaaaaaaaaaaiaaiaaiaaibajbakbalbambanbaobapbaqbarbasbataaiaaiaaiaaiaaaaaaaaaaaaaEFaZaaSEaSEbauaXqbavbawbaxaXqbaybazaJabaAbaBbaCaXqaXtaZfaZfbaDbaEaZfbaFbaGbaHbaIaZfbaJbaKbaLaZqaZraZraZqbaMbaNaaqaPvbaOaaqaXGaNRaWnaWnaWoaWnaNRaNRbaPbaQaNRbaRaaqbaSbaTbaUaZAaZAbaVbaUbaWaaqbaXbaYaUQbaZbaZbbabaZaUQaXWbbbbbcbbdbbdbbeaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDwaZHaZIaZHaZHaZHaZHaZHaZHaZIaZHaZHaZJaDyaZKaZLaDyaDyaZMaDyaZNaZOaZPaZQaZRaySaYpaYpaZSaYraZTaYxaYxaYxaYxaYxaYyaZUaYxaYxaYxaYxaYEaZVaZWaZXaYEaYIaZYaZZbaababbacaYMbadbaebafbagbahbaiaYNaSeaSjaYOaaaaaaaaaaaaaaiaaiaaiaaibajbakbalbambanbaobapbaqbarbasbataaiaaiaaiaaiaaaaaaaaaaaaaEFaZaaSEaSEbauaXqbavbawbaxaXqbaybazaJabaAbaBbaCaXqaXtdqXaZfbaDbaEaZfbaFbaGbaHbaIaZfbaJbaKbaLaZqaZraZraZqbaMbaNaaqaPvbaOaaqaXGaNRaWnaWnaWoaWnaNRaNRbaPbaQaNRbaRaaqbaSbaTbaUaZAaZAbaVbaUbaWaaqbaXbaYaUQbaZbaZbbabaZaUQaXWbbbbbcbbdbbdbbeaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayaayabbfbbgbbgbbgbbgbbgbbgbbgaGjayaaySbbhbbiaySbbjbbjbbjbbjbbjbbkaySaySaySaySaYpbblbbmaYrbbnaYxaYxbbobbpbbqbbrbboaYxaYxaYxbbsaYEbbtbbubbvaYEaYIaZYbbwbbxbbybbzaYMbbAbbBbbCbbDbbEbbFbbGbbHaSjbbIaoJaaiaaiaaiaaibbJbbKbbLbbMbbNbbNbbObbPbbNbbQbbNbbRbbSbbTbbUbbVbbWaaiaaiaaiaaiaXibbXaZaaSEaSEaaqbbYbavbaBbaxaXqbbZbcaaXqbcbbccbaCaXqaXtaZfaZfbcdbcebcfbcgbchbcibcjaZfbckbaKbclaZqaZraZrbcmbcnbaNaaqaPvbcoaaqbcpbcqbcraWnaWobcsaNRaNRbctaNRbcubcvaaqbcwbcxbcyaZAaZAbczbcybcAaaqbcBbaYaUQaUQaUQaUSaUQaUQbcCbcDbcEbcFbcGbcHaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcIbcIbcIbcIbcIbcIbcIbcIbcIbcIbcIbcIaabbcJaGeaDAbcKbbjbcLbcMbcNbcRbcPbcQbhlbcSbbjbcTbcUbcVbcWaYrbcXaYxaYxbbobbqbcYbcZbboaYxaYxbdabdbaYEaYEaYEaYEaYEaYIaZYaZYaZYaZYaZYaYMbdcbbDbddbbDbdebbFaYNbdfaSjaSkaSkbdgbdhbdiaaibdjbalbdkbbNbbNbbNbdlbdmbdnbdmbdobdpbdqbdmbdrbdsbdtaaibdubdhbdvbdwbdxaZaaSEaSEbauaXqbdyaXqaXqaXqbdzbdAaXqbcbbdBbaCaXqaXtaZfaZfbdCbdDbdEbdFbdGbdHbcjbdIaaqbdJbclaZqaZraZraZqbcnbdKaaqbdLaaqaaqaaJaaqaaqbdMaWobdNbdOaNRbdPbdQaRlbdRabZbdSbdTbdUbdVbdVbdWbdXbdYabZbdZbeaaUQbebaUQaUSaUQaUQbecbedbbcbbdbbdbeeaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcIbcIbcIbcIbcIbcIbcIbcIbcIbcIbcIbcIbcIbefbegbehaERaZKbbjbcLbeibejbcLbekbelbembenbbjbeobepbeqberaYrbesbetbeubevbewbexbeybezbezbezbeAbeBaYrbeCbcUbeDbeEbeFbblbblbeGberbeHaYMbeIbeJbeKbeLbeMbeNaYNbdfaSeaSeaSebeObePbeQbeRbeSbeTbbNbeUbeVbeWbeXbeYbeZbfabfbbfcbfdbfebeSbffbfgbfhbfibfjbfkbflbfmbfnaSEbfoaaqaXqbfpbfqbaCaXqbfrbfsaXqbftbfubaCaXqaXtaZfaZfaZfaZgaZfbfvaZfbdHbcjbfwaaqbfxbclaZqaZraZraZqbcnbfyaaqbfzbfAbfAbfBbfCbfDbfEbfFbfGbfGbfGbfGbfGbfGbfHbfIbfJaZAaZAaZAaZAaZAaZAbfKbfLbfMbaYaUQaUQaUQaUSaUQaUQbfNaWDbfObfObfOaWDaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaKPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/paradise.dme b/paradise.dme
index a007a631b7d..9339ab8b631 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -291,9 +291,28 @@
#include "code\game\gamemodes\blob\blobs\shield.dm"
#include "code\game\gamemodes\borer\borer.dm"
#include "code\game\gamemodes\changeling\changeling.dm"
-#include "code\game\gamemodes\changeling\changeling_powers.dm"
-#include "code\game\gamemodes\changeling\modularchangling.dm"
+#include "code\game\gamemodes\changeling\changeling_power.dm"
+#include "code\game\gamemodes\changeling\evolution_menu.dm"
#include "code\game\gamemodes\changeling\traitor_chan.dm"
+#include "code\game\gamemodes\changeling\powers\absorb.dm"
+#include "code\game\gamemodes\changeling\powers\augmented_eyesight.dm"
+#include "code\game\gamemodes\changeling\powers\digitalcamo.dm"
+#include "code\game\gamemodes\changeling\powers\epinephrine.dm"
+#include "code\game\gamemodes\changeling\powers\fakedeath.dm"
+#include "code\game\gamemodes\changeling\powers\fleshmend.dm"
+#include "code\game\gamemodes\changeling\powers\glands.dm"
+#include "code\game\gamemodes\changeling\powers\hivemind.dm"
+#include "code\game\gamemodes\changeling\powers\humanform.dm"
+#include "code\game\gamemodes\changeling\powers\lesserform.dm"
+#include "code\game\gamemodes\changeling\powers\mimic_voice.dm"
+#include "code\game\gamemodes\changeling\powers\mutations.dm"
+#include "code\game\gamemodes\changeling\powers\panacea.dm"
+#include "code\game\gamemodes\changeling\powers\revive.dm"
+#include "code\game\gamemodes\changeling\powers\shriek.dm"
+#include "code\game\gamemodes\changeling\powers\spiders.dm"
+#include "code\game\gamemodes\changeling\powers\strained_muscles.dm"
+#include "code\game\gamemodes\changeling\powers\tiny_prick.dm"
+#include "code\game\gamemodes\changeling\powers\transform.dm"
#include "code\game\gamemodes\cult\cult.dm"
#include "code\game\gamemodes\cult\cult_items.dm"
#include "code\game\gamemodes\cult\cult_structures.dm"
@@ -748,6 +767,7 @@
#include "code\game\objects\structures\extinguisher.dm"
#include "code\game\objects\structures\false_walls.dm"
#include "code\game\objects\structures\flora.dm"
+#include "code\game\objects\structures\foodcart.dm"
#include "code\game\objects\structures\fullwindow.dm"
#include "code\game\objects\structures\girders.dm"
#include "code\game\objects\structures\grille.dm"