diff --git a/code/ZAS/Atom.dm b/code/ZAS/Atom.dm
index b4d1de20af4..8d479ecfb14 100644
--- a/code/ZAS/Atom.dm
+++ b/code/ZAS/Atom.dm
@@ -29,6 +29,16 @@ atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
return 0
return 1
+
+//Convenience function for atoms to update turfs they occupy
+/atom/movable/proc/update_nearby_tiles(need_rebuild)
+ if(!air_master)
+ return 0
+
+ for(var/turf/simulated/turf in locs)
+ air_master.mark_for_update(turf)
+
+ return 1
//Basically another way of calling CanPass(null, other, 0, 0) and CanPass(null, other, 1.5, 1).
//Returns:
diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm
index 10ab63c9259..8e6118f6f46 100644
--- a/code/__HELPERS/lists.dm
+++ b/code/__HELPERS/lists.dm
@@ -396,4 +396,190 @@ proc/listclearnulls(list/list)
/proc/find_record(field, value, list/L)
for(var/datum/data/record/R in L)
if(R.fields[field] == value)
- return R
\ No newline at end of file
+ return R
+
+
+/proc/dd_sortedObjectList(var/list/L, var/cache=list())
+ if(L.len < 2)
+ return L
+ var/middle = L.len / 2 + 1 // Copy is first,second-1
+ return dd_mergeObjectList(dd_sortedObjectList(L.Copy(0,middle), cache), dd_sortedObjectList(L.Copy(middle), cache), cache) //second parameter null = to end of list
+
+/proc/dd_mergeObjectList(var/list/L, var/list/R, var/list/cache)
+ var/Li=1
+ var/Ri=1
+ var/list/result = new()
+ while(Li <= L.len && Ri <= R.len)
+ var/LLi = L[Li]
+ var/RRi = R[Ri]
+ var/LLiV = cache[LLi]
+ var/RRiV = cache[RRi]
+ if(!LLiV)
+ LLiV = LLi:dd_SortValue()
+ cache[LLi] = LLiV
+ if(!RRiV)
+ RRiV = RRi:dd_SortValue()
+ cache[RRi] = RRiV
+ if(LLiV < RRiV)
+ result += L[Li++]
+ else
+ result += R[Ri++]
+
+ if(Li <= L.len)
+ return (result + L.Copy(Li, 0))
+ return (result + R.Copy(Ri, 0))
+
+// Insert an object into a sorted list, preserving sortedness
+/proc/dd_insertObjectList(var/list/L, var/O)
+ var/min = 1
+ var/max = L.len
+ var/Oval = O:dd_SortValue()
+
+ while(1)
+ var/mid = min+round((max-min)/2)
+
+ if(mid == max)
+ L.Insert(mid, O)
+ return
+
+ var/Lmid = L[mid]
+ var/midval = Lmid:dd_SortValue()
+ if(Oval == midval)
+ L.Insert(mid, O)
+ return
+ else if(Oval < midval)
+ max = mid
+ else
+ min = mid+1
+
+/*
+proc/dd_sortedObjectList(list/incoming)
+ /*
+ Use binary search to order by dd_SortValue().
+ This works by going to the half-point of the list, seeing if the node in
+ question is higher or lower cost, then going halfway up or down the list
+ and checking again. This is a very fast way to sort an item into a list.
+ */
+ var/list/sorted_list = new()
+ var/low_index
+ var/high_index
+ var/insert_index
+ var/midway_calc
+ var/current_index
+ var/current_item
+ var/current_item_value
+ var/current_sort_object_value
+ var/list/list_bottom
+
+ var/current_sort_object
+ for (current_sort_object in incoming)
+ low_index = 1
+ high_index = sorted_list.len
+ while (low_index <= high_index)
+ // Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.)
+ midway_calc = (low_index + high_index) / 2
+ current_index = round(midway_calc)
+ if (midway_calc > current_index)
+ current_index++
+ current_item = sorted_list[current_index]
+
+ current_item_value = current_item:dd_SortValue()
+ current_sort_object_value = current_sort_object:dd_SortValue()
+ if (current_sort_object_value < current_item_value)
+ high_index = current_index - 1
+ else if (current_sort_object_value > current_item_value)
+ low_index = current_index + 1
+ else
+ // current_sort_object == current_item
+ low_index = current_index
+ break
+
+ // Insert before low_index.
+ insert_index = low_index
+
+ // Special case adding to end of list.
+ if (insert_index > sorted_list.len)
+ sorted_list += current_sort_object
+ continue
+
+ // Because BYOND lists don't support insert, have to do it by:
+ // 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list.
+ list_bottom = sorted_list.Copy(insert_index)
+ sorted_list.Cut(insert_index)
+ sorted_list += current_sort_object
+ sorted_list += list_bottom
+ return sorted_list
+*/
+
+proc/dd_sortedtextlist(list/incoming, case_sensitive = 0)
+ // Returns a new list with the text values sorted.
+ // Use binary search to order by sortValue.
+ // This works by going to the half-point of the list, seeing if the node in question is higher or lower cost,
+ // then going halfway up or down the list and checking again.
+ // This is a very fast way to sort an item into a list.
+ var/list/sorted_text = new()
+ var/low_index
+ var/high_index
+ var/insert_index
+ var/midway_calc
+ var/current_index
+ var/current_item
+ var/list/list_bottom
+ var/sort_result
+
+ var/current_sort_text
+ for (current_sort_text in incoming)
+ low_index = 1
+ high_index = sorted_text.len
+ while (low_index <= high_index)
+ // Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.)
+ midway_calc = (low_index + high_index) / 2
+ current_index = round(midway_calc)
+ if (midway_calc > current_index)
+ current_index++
+ current_item = sorted_text[current_index]
+
+ if (case_sensitive)
+ sort_result = sorttextEx(current_sort_text, current_item)
+ else
+ sort_result = sorttext(current_sort_text, current_item)
+
+ switch(sort_result)
+ if (1)
+ high_index = current_index - 1 // current_sort_text < current_item
+ if (-1)
+ low_index = current_index + 1 // current_sort_text > current_item
+ if (0)
+ low_index = current_index // current_sort_text == current_item
+ break
+
+ // Insert before low_index.
+ insert_index = low_index
+
+ // Special case adding to end of list.
+ if (insert_index > sorted_text.len)
+ sorted_text += current_sort_text
+ continue
+
+ // Because BYOND lists don't support insert, have to do it by:
+ // 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list.
+ list_bottom = sorted_text.Copy(insert_index)
+ sorted_text.Cut(insert_index)
+ sorted_text += current_sort_text
+ sorted_text += list_bottom
+ return sorted_text
+
+
+proc/dd_sortedTextList(list/incoming)
+ var/case_sensitive = 1
+ return dd_sortedtextlist(incoming, case_sensitive)
+
+
+datum/proc/dd_SortValue()
+ return "[src]"
+
+/obj/machinery/dd_SortValue()
+ return "[sanitize(name)]"
+
+/obj/machinery/camera/dd_SortValue()
+ return "[c_tag]"
\ No newline at end of file
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/ai_laws.dm b/code/datums/ai_laws.dm
index d81bbf67085..e1fc26d1709 100644
--- a/code/datums/ai_laws.dm
+++ b/code/datums/ai_laws.dm
@@ -179,6 +179,11 @@ datum/ai_laws/tyrant //This probably shouldn't be a default lawset.
/datum/ai_laws/proc/clear_ion_laws()
src.ion = list()
+
+/datum/ai_laws/proc/clear_zeroth_law(var/law_borg = null)
+ src.zeroth = null
+ if(law_borg)
+ src.zeroth_borg = null
/datum/ai_laws/proc/show_laws(var/who)
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/datums/visibility_networks/chunk.dm b/code/datums/visibility_networks/chunk.dm
deleted file mode 100644
index 4abc1340b0f..00000000000
--- a/code/datums/visibility_networks/chunk.dm
+++ /dev/null
@@ -1,179 +0,0 @@
-#define UPDATE_BUFFER 25 // 2.5 seconds
-
-// CAMERA CHUNK
-//
-// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
-// Allows the mob using this chunk to stream these chunks and know what it can and cannot see.
-
-/datum/visibility_chunk
- var/obscured_image = 'icons/effects/cameravis.dmi'
- var/obscured_sub = "black"
- var/list/obscuredTurfs = list()
- var/list/visibleTurfs = list()
- var/list/obscured = list()
- var/list/viewpoints = list()
- var/list/turfs = list()
- var/list/seenby = list()
- var/visible = 0
- var/changed = 0
- var/updating = 0
- var/x = 0
- var/y = 0
- var/z = 0
-
-/datum/visibility_chunk/proc/add(mob/new_mob)
-
- // if this thing doesn't use one of these visibility systems, kick it out
- if (!new_mob.visibility_interface)
- return
-
- // if the mob being added isn't a valid form of that mob, kick it out
- if (!new_mob.visibility_interface:canBeAddedToChunk(src))
- return
-
- // add this chunk to the list of visible chunks
- new_mob.visibility_interface:addChunk(src)
-
- visible++
- seenby += new_mob
- if(changed && !updating)
- update()
-
-/datum/visibility_chunk/proc/remove(mob/new_mob)
- // if this thing doesn't use one of these visibility systems, kick it out
- if (!new_mob.visibility_interface)
- return
-
- // if the mob being added isn't a valid form of that mob, kick it out
- if (!new_mob.visibility_interface:canBeAddedToChunk(src))
- return
-
- // remove the chunk
- new_mob.visibility_interface:removeChunk(src)
-
- // remove the mob from out lists
- seenby -= new_mob
- if(visible > 0)
- visible--
-
-/datum/visibility_chunk/proc/visibilityChanged(turf/loc)
- if(!visibleTurfs[loc])
- return
- hasChanged()
-
-/datum/visibility_chunk/proc/hasChanged(var/update_now = 0)
- if(visible || update_now)
- if(!updating)
- updating = 1
- spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
- update()
- updating = 0
- else
- changed = 1
-
-
-/*
-This function needs to be overwritten to return True if the viewpoint object is valid, and false if it is not.
-*/
-/datum/visibility_chunk/proc/validViewpoint(var/viewpoint)
- return FALSE
-
-/*
-This function needs to be overwritten to return a list of visible turfs for that viewpoint
-*/
-/datum/visibility_chunk/proc/getVisibleTurfsForViewpoint(var/viewpoint)
- return list()
-
-// returns a list of turfs which can be seen in by the chunks viewpoints
-/datum/visibility_chunk/proc/getVisibleTurfs()
- var/list/newVisibleTurfs = list()
- for(var/viewpoint in viewpoints)
- if (validViewpoint(viewpoint))
- for (var/turf/t in getVisibleTurfsForViewpoint(viewpoint))
- newVisibleTurfs[t]=t
- return newVisibleTurfs
-
-/*
-This function needs to be overwritten to find nearby viewpoint objects to the chunk center.
-*/
-/datum/visibility_chunk/proc/findNearbyViewpoints()
- return FALSE
-
-/*
-This function can be overwritten to change or randomize the obscuring images
-*/
-/datum/visibility_chunk/proc/setObscuredImage(var/turf/target_turf)
- if(!target_turf.obscured)
- target_turf.obscured = image(obscured_image, target_turf, obscured_sub, 15)
-
-/datum/visibility_chunk/proc/update()
-
- set background = 1
-
- // get a list of all the turfs that our viewpoints can see
- var/list/newVisibleTurfs = getVisibleTurfs()
-
- // Removes turf that isn't in turfs.
- newVisibleTurfs &= turfs
-
- var/list/visAdded = newVisibleTurfs - visibleTurfs
- var/list/visRemoved = visibleTurfs - newVisibleTurfs
-
- visibleTurfs = newVisibleTurfs
- obscuredTurfs = turfs - newVisibleTurfs
-
- // update the visibility overlays
- for(var/turf in visAdded)
- var/turf/t = turf
- if(t.obscured)
- obscured -= t.obscured
- for(var/mob/current_mob in seenby)
- if (current_mob.visibility_interface)
- current_mob.visibility_interface:removeObscuredTurf(t)
-
- for(var/turf in visRemoved)
- var/turf/t = turf
- if(obscuredTurfs[t])
- setObscuredImage(t)
- obscured += t.obscured
- for(var/mob/current_mob in seenby)
- if (current_mob.visibility_interface)
- current_mob.visibility_interface:addObscuredTurf(t)
- else
- seenby -= current_mob
-
-
-// Create a new chunk, since the chunks are made as they are needed.
-/datum/visibility_chunk/New(loc, x, y, z)
-
- // 0xf = 15
- x &= ~0xf
- y &= ~0xf
-
- src.x = x
- src.y = y
- src.z = z
-
- for(var/turf/t in range(10, locate(x + 8, y + 8, z)))
- if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16)
- turfs[t] = t
-
- // locate all nearby viewpoints
- findNearbyViewpoints()
-
- // get the turfs that are visible to those viewpoints
- visibleTurfs = getVisibleTurfs()
-
- // Removes turf that isn't in turfs.
- visibleTurfs &= turfs
-
- // create the list of turfs we can't see
- obscuredTurfs = turfs - visibleTurfs
-
- // create the list of obscuring images to add to viewing clients
- for(var/turf in obscuredTurfs)
- var/turf/t = turf
- setObscuredImage(t)
- obscured += t.obscured
-
-#undef UPDATE_BUFFER
\ No newline at end of file
diff --git a/code/datums/visibility_networks/dictionary.dm b/code/datums/visibility_networks/dictionary.dm
deleted file mode 100644
index 5f57ddd7a17..00000000000
--- a/code/datums/visibility_networks/dictionary.dm
+++ /dev/null
@@ -1,11 +0,0 @@
-var/datum/visibility_network/cameras/cameranet = new()
-var/datum/visibility_network/cult/cultNetwork = new()
-var/datum/visibility_network/list/visibility_networks = list("ALL_CAMERAS"=cameranet, "CULT" = cultNetwork)
-
-
-// used by turfs and objects to update all visibility networks
-/proc/updateVisibilityNetworks(atom/A, var/opacity_check = 1)
- var/datum/visibility_network/currentNetwork
- for (var/networkName in visibility_networks)
- currentNetwork = visibility_networks[networkName]
- currentNetwork.updateVisibility(A, opacity_check)
\ No newline at end of file
diff --git a/code/datums/visibility_networks/update_triggers.dm b/code/datums/visibility_networks/update_triggers.dm
deleted file mode 100644
index 97ed2db3a6c..00000000000
--- a/code/datums/visibility_networks/update_triggers.dm
+++ /dev/null
@@ -1,94 +0,0 @@
-//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
-
-// TURFS
-
-/turf
- var/image/obscured
-
-/turf/proc/visibilityChanged()
- if(ticker)
- updateVisibilityNetworks(src)
-
-/turf/simulated/Del()
- visibilityChanged()
- ..()
-
-/turf/simulated/New()
- ..()
- visibilityChanged()
-
-
-
-// STRUCTURES
-
-/obj/structure/Del()
- if(ticker)
- updateVisibilityNetworks(src)
- ..()
-
-/obj/structure/New()
- ..()
- if(ticker)
- updateVisibilityNetworks(src)
-
-// EFFECTS
-
-/obj/effect/Del()
- if(ticker)
- updateVisibilityNetworks(src)
- ..()
-
-/obj/effect/New()
- ..()
- if(ticker)
- updateVisibilityNetworks(src)
-
-
-// DOORS
-
-// Simply updates the visibility of the area when it opens/closes/destroyed.
-/obj/machinery/door/proc/update_nearby_tiles(need_rebuild)
-
- if(!glass)
- updateVisibilityNetworks(src,0)
-
- if(!air_master)
- return 0
-
- for(var/turf/simulated/turf in locs)
- update_heat_protection(turf)
- air_master.mark_for_update(turf)
-
- return 1
-
-
-
-#define UPDATE_VISIBILITY_NETWORK_BUFFER 30
-
-/mob
- var/datum/visibility_network/list/visibilityNetworks=list()
- var/updatingVisibilityNetworks=FALSE
-
-/mob/Move(n,direct)
- var/oldLoc = src.loc
- //. = ..()
- if(..(n,direct))
- if(src.visibilityNetworks.len)
- if(!src.updatingVisibilityNetworks)
- src.updatingVisibilityNetworks = 1
- spawn(UPDATE_VISIBILITY_NETWORK_BUFFER)
- if(oldLoc != src.loc)
- for (var/datum/visibility_network/currentNetwork in src.visibilityNetworks)
- currentNetwork.updateMob(src)
- src.updatingVisibilityNetworks = 0
- return .
-
-/mob/proc/addToVisibilityNetwork(var/datum/visibility_network/network)
- if(network)
- src.visibilityNetworks+=network
-
-/mob/proc/removeFromVisibilityNetwork(var/datum/visibility_network/network)
- if(network)
- src.visibilityNetworks|=network
-
-#undef UPDATE_VISIBILITY_NETWORK_BUFFER
\ No newline at end of file
diff --git a/code/datums/visibility_networks/visibility_interface.dm b/code/datums/visibility_networks/visibility_interface.dm
deleted file mode 100644
index 7d8efba41d3..00000000000
--- a/code/datums/visibility_networks/visibility_interface.dm
+++ /dev/null
@@ -1,46 +0,0 @@
-/datum/visibility_interface
- var/chunk_type = null
- var/mob/controller = null
- var/list/visible_chunks = list()
-
-
-/datum/visibility_interface/New(var/mob/controller)
- src.controller = controller
-
-
-/datum/visibility_interface/proc/validMob()
- return getClient()
-
-/datum/visibility_interface/proc/getClient()
- return controller.client
-
-/datum/visibility_interface/proc/canBeAddedToChunk(var/datum/visibility_chunk/test_chunk)
- return istype(test_chunk,chunk_type)
-
-
-/datum/visibility_interface/proc/addChunk(var/datum/visibility_chunk/test_chunk)
- visible_chunks+=test_chunk
- var/client/currentClient = getClient()
- if(currentClient)
- currentClient.images += test_chunk.obscured
-
-
-/datum/visibility_interface/proc/removeChunk(var/datum/visibility_chunk/test_chunk)
- visible_chunks-=test_chunk
- var/client/currentClient = getClient()
- if(currentClient)
- currentClient.images -= test_chunk.obscured
-
-
-/datum/visibility_interface/proc/removeObscuredTurf(var/turf/target_turf)
- if(validMob())
- var/client/currentClient = getClient()
- if(currentClient)
- currentClient.images -= target_turf.obscured
-
-
-/datum/visibility_interface/proc/addObscuredTurf(var/turf/target_turf)
- if(validMob())
- var/client/currentClient = getClient()
- if(currentClient)
- currentClient.images -= target_turf.obscured
\ No newline at end of file
diff --git a/code/datums/visibility_networks/visibility_network.dm b/code/datums/visibility_networks/visibility_network.dm
deleted file mode 100644
index f1bc24e771a..00000000000
--- a/code/datums/visibility_networks/visibility_network.dm
+++ /dev/null
@@ -1,144 +0,0 @@
-/datum/visibility_network
- var/list/viewpoints = list()
-
- // the type of chunk used by this network
- var/datum/visibility_chunk/ChunkType = /datum/visibility_chunk
-
- // The chunks of the map, mapping the areas that the viewpoints can see.
- var/list/chunks = list()
-
- var/ready = 0
-
-
-// Creates a chunk key string from x,y,z coordinates
-/datum/visibility_network/proc/createChunkKey(x,y,z)
- x &= ~0xf
- y &= ~0xf
- return "[x],[y],[z]"
-
-
-// Checks if a chunk has been Generated in x, y, z.
-/datum/visibility_network/proc/chunkGenerated(x, y, z)
- return (chunks[createChunkKey(x, y, z)])
-
-
-// Returns the chunk in the x, y, z.
-// If there is no chunk, it creates a new chunk and returns that.
-/datum/visibility_network/proc/getChunk(x, y, z)
- var/key = createChunkKey(x, y, z)
- if(!chunks[key])
- chunks[key] = new ChunkType(null, x, y, z)
- return chunks[key]
-
-
-/datum/visibility_network/proc/visibility(var/mob/targetMob)
-
- // if we've got not visibility interface on the mob, we canot do this
- if (!targetMob.visibility_interface)
- return
-
- // 0xf = 15
- var/x1 = max(0, targetMob.x - 16) & ~0xf
- var/y1 = max(0, targetMob.y - 16) & ~0xf
- var/x2 = min(world.maxx, targetMob.x + 16) & ~0xf
- var/y2 = min(world.maxy, targetMob.y + 16) & ~0xf
-
- var/list/visibleChunks = list()
-
- for(var/x = x1; x <= x2; x += 16)
- for(var/y = y1; y <= y2; y += 16)
- visibleChunks += getChunk(x, y, targetMob.z)
-
- var/list/remove = targetMob.visibility_interface:visible_chunks - visibleChunks
- var/list/add = visibleChunks - targetMob.visibility_interface:visible_chunks
-
- for(var/datum/visibility_chunk/chunk in remove)
- chunk.remove(targetMob)
-
- for(var/datum/visibility_chunk/chunk in add)
- chunk.add(targetMob)
-
-
-// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
-/datum/visibility_network/proc/updateVisibility(atom/A, var/opacity_check = 1)
- if(!ticker || (opacity_check && !A.opacity))
- return
- majorChunkChange(A, 2)
-
-
-/datum/visibility_network/proc/updateChunk(x, y, z)
- if(!chunkGenerated(x, y, z))
- return
- var/datum/visibility_chunk/chunk = getChunk(x, y, z)
- chunk.hasChanged()
-
-
-/datum/visibility_network/proc/validViewpoint(var/viewpoint)
- return FALSE
-
-
-/datum/visibility_network/proc/addViewpoint(var/viewpoint)
- if(validViewpoint(viewpoint))
- majorChunkChange(viewpoint, 1)
-
-
-/datum/visibility_network/proc/removeViewpoint(var/viewpoint)
- if(validViewpoint(viewpoint))
- majorChunkChange(viewpoint, 0)
-
-/datum/visibility_network/proc/getViewpointFromMob(var/mob/currentMob)
- return FALSE
-
-/datum/visibility_network/proc/updateMob(var/mob/currentMob)
- var/viewpoint = getViewpointFromMob(currentMob)
- if(viewpoint)
- updateViewpoint(viewpoint)
-
-
-/datum/visibility_network/proc/updateViewpoint(var/viewpoint)
- if(validViewpoint(viewpoint))
- majorChunkChange(viewpoint, 1)
-
-
-// Never access this proc directly!!!!
-// This will update the chunk and all the surrounding chunks.
-// It will also add the atom to the cameras list if you set the choice to 1.
-// Setting the choice to 0 will remove the viewpoint from the chunks.
-// If you want to update the chunks around an object, without adding/removing a viewpoint, use choice 2.
-/datum/visibility_network/proc/majorChunkChange(atom/c, var/choice)
- // 0xf = 15
- if(!c)
- return
-
- var/turf/T = get_turf(c)
- if(T)
- var/x1 = max(0, T.x - 8) & ~0xf
- var/y1 = max(0, T.y - 8) & ~0xf
- var/x2 = min(world.maxx, T.x + 8) & ~0xf
- var/y2 = min(world.maxy, T.y + 8) & ~0xf
-
- for(var/x = x1; x <= x2; x += 16)
- for(var/y = y1; y <= y2; y += 16)
- if(chunkGenerated(x, y, T.z))
- var/datum/visibility_chunk/chunk = getChunk(x, y, T.z)
- if(choice == 0)
- // Remove the viewpoint.
- chunk.viewpoints -= c
- else if(choice == 1)
- // You can't have the same viewpoint in the list twice.
- chunk.viewpoints |= c
- chunk.hasChanged()
-
-// checks if the network can see a particular atom
-/datum/visibility_network/proc/checkCanSee(var/atom/target)
- var/turf/position = get_turf(target)
- return checkTurfVis(position)
-
-/datum/visibility_network/proc/checkTurfVis(var/turf/position)
- var/datum/visibility_chunk/chunk = getChunk(position.x, position.y, position.z)
- if(chunk)
- if(chunk.changed)
- chunk.hasChanged(1) // Update now, no matter if it's visible or not.
- if(chunk.visibleTurfs[position])
- return 1
- return 0
\ No newline at end of file
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index fc90cf47134..ccfda6b21c3 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -492,7 +492,7 @@
/obj/item/weapon/camera_bug/attack_self(mob/usr as mob)
var/list/cameras = new/list()
- for (var/obj/machinery/camera/C in cameranet.viewpoints)
+ for (var/obj/machinery/camera/C in cameranet.cameras)
if (C.bugged && C.status)
cameras.Add(C)
if (length(cameras) == 0)
diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm
index e703f7ba3b2..0ee9267ca01 100644
--- a/code/game/area/Space Station 13 areas.dm
+++ b/code/game/area/Space Station 13 areas.dm
@@ -22,6 +22,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
var/poweralm = 1
var/party = null
var/radalert = 0
+ var/report_alerts = 1 // Should atmos alerts notify the AI/computers
level = null
name = "Space"
icon = 'icons/turf/areas.dmi'
@@ -1983,6 +1984,11 @@ area/security/podbay
//Traitor Station
+/area/traitor
+ name = "\improper Syndicate Base"
+ icon_state = "syndie_hall"
+ report_alerts = 0
+
/area/traitor/rnd
name = "\improper Syndicate Research and Development"
icon_state = "syndie_rnd"
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 3c04e9cf951..02924c8657d 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -52,25 +52,32 @@
InitializeLighting()
-/area/proc/poweralert(var/state, var/obj/source as obj)
+/area/proc/poweralert(var/state, var/obj/source as obj)
if (state != poweralm)
poweralm = state
if(istype(source)) //Only report power alarms on the z-level where the source is located.
var/list/cameras = list()
for (var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
+ if(!report_alerts)
+ break
cameras += C
if(state == 1)
+
C.network.Remove("Power Alarms")
else
C.network.Add("Power Alarms")
for (var/mob/living/silicon/aiPlayer in player_list)
+ if(!report_alerts)
+ break
if(aiPlayer.z == source.z)
if (state == 1)
aiPlayer.cancelAlarm("Power", src, source)
else
aiPlayer.triggerAlarm("Power", src, cameras, source)
for(var/obj/machinery/computer/station_alert/a in machines)
+ if(!report_alerts)
+ break
if(a.z == source.z)
if(state == 1)
a.cancelAlarm("Power", src, source)
@@ -107,11 +114,17 @@
for(var/area/RA in related)
//updateicon()
for(var/obj/machinery/camera/C in RA)
+ if(!report_alerts)
+ break
cameras += C
C.network.Add("Atmosphere Alarms")
for(var/mob/living/silicon/aiPlayer in player_list)
+ if(!report_alerts)
+ break
aiPlayer.triggerAlarm("Atmosphere", src, cameras, src)
for(var/obj/machinery/computer/station_alert/a in machines)
+ if(!report_alerts)
+ break
a.triggerAlarm("Atmosphere", src, cameras, src)
air_doors_activated=1
CloseFirelocks()
@@ -119,10 +132,16 @@
else if (atmosalm == 2)
for(var/area/RA in related)
for(var/obj/machinery/camera/C in RA)
+ if(!report_alerts)
+ break
C.network.Remove("Atmosphere Alarms")
for(var/mob/living/silicon/aiPlayer in player_list)
+ if(!report_alerts)
+ break
aiPlayer.cancelAlarm("Atmosphere", src, src)
for(var/obj/machinery/computer/station_alert/a in machines)
+ if(!report_alerts)
+ break
a.cancelAlarm("Atmosphere", src, src)
air_doors_activated=0
OpenFirelocks()
@@ -162,11 +181,17 @@
var/list/cameras = list()
for(var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
+ if(!report_alerts)
+ continue
cameras.Add(C)
C.network.Add("Fire Alarms")
for (var/mob/living/silicon/ai/aiPlayer in player_list)
+ if(!report_alerts)
+ continue
aiPlayer.triggerAlarm("Fire", src, cameras, src)
for (var/obj/machinery/computer/station_alert/a in machines)
+ if(!report_alerts)
+ continue
a.triggerAlarm("Fire", src, cameras, src)
/area/proc/firereset()
@@ -176,10 +201,16 @@
updateicon()
for(var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
+ if(!report_alerts)
+ continue
C.network.Remove("Fire Alarms")
for (var/mob/living/silicon/ai/aiPlayer in player_list)
+ if(!report_alerts)
+ continue
aiPlayer.cancelAlarm("Fire", src, src)
for (var/obj/machinery/computer/station_alert/a in machines)
+ if(!report_alerts)
+ continue
a.cancelAlarm("Fire", src, src)
OpenFirelocks()
@@ -355,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/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index f780594701c..76d198d796f 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -105,7 +105,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
changeling.objectives += debrain_objective
var/list/active_ais = active_ais()
- if(active_ais.len && prob(10)) // num_players() proc is designed for roundstart, changed to fixed value to prevent problems with mid-round objective randomization.
+ 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()
diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
index e2f88ac9d9f..d40da71fff1 100644
--- a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
+++ b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
@@ -15,7 +15,7 @@
user << "We feel a minute twitch in our eyes, and darkness creeps away."
else
user << "Our vision dulls. Shadows gather."
- user.sight -= SEE_MOBS
+ user.sight &= ~SEE_MOBS
while(active)
user.see_in_dark = 8
user.see_invisible = 2
diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm
index 2e6883196bc..d7820d11188 100644
--- a/code/game/gamemodes/changeling/powers/tiny_prick.dm
+++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm
@@ -37,8 +37,6 @@
if(H.species.flags & IS_SYNTHETIC)
user << "This won't work on synthetics."
return
- 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."
if(!isturf(user.loc))
return
if(get_dist(user, target) > (user.mind.changeling.sting_range))
@@ -87,6 +85,11 @@
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)
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index 713a76c048e..7be5e01f382 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -72,13 +72,11 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",
blood.override = 1
for(var/mob/living/silicon/ai/AI in player_list)
AI.client.images += blood
- cultNetwork.viewpoints+=src
- cultNetwork.addViewpoint(src)
+ cult_viewpoints += src
/obj/effect/rune/Del()
..()
- cultNetwork.viewpoints-=src
- cultNetwork.removeViewpoint(src)
+ cult_viewpoints -= src
/obj/effect/rune/examine()
set src in view(2)
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index 844669ff039..39c0c004a5c 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -313,7 +313,7 @@ rcd light flash thingy on matter drain
power_type = /client/proc/reactivate_camera
-/client/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.viewpoints)
+/client/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.cameras)
set name = "Reactivate Camera"
set category = "Malfunction"
if (istype (C, /obj/machinery/camera))
@@ -337,7 +337,7 @@ rcd light flash thingy on matter drain
power_type = /client/proc/upgrade_camera
-/client/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.viewpoints)
+/client/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.cameras)
set name = "Upgrade Camera"
set category = "Malfunction"
if(istype(C))
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index f80b943cf76..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
@@ -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 52a398f19fc..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(10)) // Leaving this at a flat chance for now, problems with the num_players() proc.
+ 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()
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 7dbc03dc37b..257069a0248 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -458,6 +458,7 @@
alert_signal.transmission_method = 1
alert_signal.data["zone"] = alarm_area.name
alert_signal.data["type"] = "Atmospheric"
+ alert_signal.data["hidden"] = hidden
if(alert_level==2)
alert_signal.data["alert"] = "severe"
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index 1b7dd28dfc6..785b1716978 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -4,54 +4,23 @@
icon_state = "yellow"
density = 1
var/health = 100.0
+ flags = CONDUCT
+ var/menu = 0
+ //used by nanoui: 0 = main menu, 1 = relabel
var/valve_open = 0
var/release_pressure = ONE_ATMOSPHERE
- var/list/_color = list("yellow", null, null, null)//variable that stores colours
- var/list/decals = list() // var that stores the decals, NOTE: Not the actual POSSIBLE decals, but the ones currently used
- var/list/oldcolor = list()//lists for check_change()
- var/list/olddecals = list()
- var/list/possibledecals = list( //var that stores all possible decals, here for adminbus I guess? NOTE: LEAVE "done" IN HERE
- "Low temperature canister" = "cold",
- "High temperature canister" = "hot",
- "Plasma containing canister" = "plasma",
- "Done" = "DONE"
- )
- var/list/possiblemaincolor = list( //these lists contain the possible colors of a canister, here for adminbus
- "\[N2O\]" = "redws",
- "\[N2\]" = "red",
- "\[O2\]" = "blue",
- "\[Toxin (Bio)\]" = "orange",
- "\[CO2\]" = "black",
- "\[Air\]" = "grey",
- "\[CAUTION\]" = "yellow",
- "\[SPECIAL\]" = "whiters"
- )
- var/list/possibleseccolor = list( // no point in having the N2O and "whiters" ones in these lists
- "\[N2\]" = "red-c",
- "\[O2\]" = "blue-c",
- "\[Toxin (Bio)\]" = "orange-c",
- "\[CO2\]" = "black-c",
- "\[Air\]" = "grey-c",
- "\[CAUTION\]" = "yellow-c"
- )
- var/list/possibletertcolor = list(
- "\[N2\]" = "red-c-1",
- "\[O2\]" = "blue-c-1",
- "\[Toxin (Bio)\]" = "orange-c-1",
- "\[CO2\]" = "black-c-1",
- "\[Air\]" = "grey-c-1",
- "\[CAUTION\]" = "yellow-c-1"
- )
- var/list/possiblequartcolor = list(
- "\[N2\]" = "red-c-2",
- "\[O2\]" = "blue-c-2",
- "\[Toxin (Bio)\]" = "orange-c-2",
- "\[CO2\]" = "black-c-2",
- "\[Air\]" = "grey-c-2",
- "\[CAUTION\]" = "yellow-c-2"
- )
+ var/list/_color //variable that stores colours
+ var/list/decals // list that stores the decals
+ var/list/possibledecals
+ var/list/oldcolor//lists for check_change()
+ var/list/olddecals
+ var/list/possiblemaincolor //these lists contain the possible colors of a canister
+ var/list/possibleseccolor
+ var/list/possibletertcolor
+ var/list/possiblequartcolor
+ var/list/colorcontainer //passed to the ui to render the color lists
var/can_label = 1
var/filled = 0.5
@@ -63,42 +32,78 @@
var/busy = 0
var/update_flag = 0
-/obj/machinery/portable_atmospherics/canister/sleeping_agent
- name = "Canister: \[N2O\]"
- icon_state = "redws"
- _color = list("redws", null, null, null)
- can_label = 0
-/obj/machinery/portable_atmospherics/canister/nitrogen
- name = "Canister: \[N2\]"
- icon_state = "red"
- _color = list("red", null, null, null)
- decals = list("plasma")
- can_label = 0
-/obj/machinery/portable_atmospherics/canister/oxygen
- name = "Canister: \[O2\]"
- icon_state = "blue"
- _color = list("blue", null, null, null)
- can_label = 0
-/obj/machinery/portable_atmospherics/canister/toxins
- name = "Canister \[Toxin (Plasma)\]"
- icon_state = "orange"
- _color = list("orange", null, null, null)
- can_label = 0
-/obj/machinery/portable_atmospherics/canister/carbon_dioxide
- name = "Canister \[CO2\]"
- icon_state = "black"
- _color = list("black", null, null, null)
- can_label = 0
-/obj/machinery/portable_atmospherics/canister/air
- name = "Canister \[Air\]"
- icon_state = "grey"
- _color = list("grey", null, null, null)
- can_label = 0
-/obj/machinery/portable_atmospherics/canister/custom_mix
- name = "Canister \[Custom\]"
- icon_state = "whiters"
- _color = list("whiters", null, null, null)
- can_label = 0
+ New()
+ ..()
+ _color = list(
+ "prim" = "yellow",
+ "sec" = null,
+ "ter" = null,
+ "quart" = null)
+ oldcolor = list()
+ decals = list()
+ olddecals = list()
+ possibledecals = list( //var that stores all possible decals, used by ui
+ list("name" = "Low temperature canister", "icon" = "cold", "active" = 0),
+ list("name" = "High temperature canister", "icon" = "hot", "active" = 0),
+ list("name" = "Plasma containing canister", "icon" = "plasma", "active" = 0)
+ )
+ possiblemaincolor = list( //these lists contain the possible colors of a canister
+ list("name" = "\[N2O\]", "icon" = "redws"),
+ list("name" = "\[N2\]", "icon" = "red"),
+ list("name" = "\[O2\]", "icon" = "blue"),
+ list("name" = "\[Toxin (Bio)\]", "icon" = "orange"),
+ list("name" = "\[CO2\]", "icon" = "black"),
+ list("name" = "\[Air\]", "icon" = "grey"),
+ list("name" = "\[CAUTION\]", "icon" = "yellow"),
+ list("name" = "\[SPECIAL\]", "icon" = "whiters")
+ )
+ possibleseccolor = list( // no point in having the N2O and "whiters" ones in these lists
+ list("name" = "\[N2\]", "icon" = "red-c"),
+ list("name" = "\[O2\]", "icon" = "blue-c"),
+ list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c"),
+ list("name" = "\[CO2\]", "icon" = "black-c"),
+ list("name" = "\[Air\]", "icon" = "grey-c"),
+ list("name" = "\[CAUTION\]", "icon" = "yellow-c")
+ )
+ possibletertcolor = list(
+ list("name" = "\[N2\]", "icon" = "red-c-1"),
+ list("name" = "\[O2\]", "icon" = "blue-c-1"),
+ list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c-1"),
+ list("name" = "\[CO2\]", "icon" = "black-c-1"),
+ list("name" = "\[Air\]", "icon" = "grey-c-1"),
+ list("name" = "\[CAUTION\]", "icon" = "yellow-c-1")
+ )
+ possiblequartcolor = list(
+ list("name" = "\[N2\]", "icon" = "red-c-2"),
+ list("name" = "\[O2\]", "icon" = "blue-c-2"),
+ list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c-2"),
+ list("name" = "\[CO2\]", "icon" = "black-c-2"),
+ list("name" = "\[Air\]", "icon" = "grey-c-2"),
+ list("name" = "\[CAUTION\]", "icon" = "yellow-c-2")
+ )
+ colorcontainer = list(//passed to the ui to render the color lists
+ "prim" = list(
+ "options" = possiblemaincolor,
+ "name" = "Primary color",
+ "anycolor" = -1,//0: no color applied. 1: color selected. Not used for primary color.
+ ),
+ "sec" = list(
+ "options" = possibleseccolor,
+ "name" = "Secondary color",
+ "anycolor" = 0,
+ ),
+ "ter" = list(
+ "options" = possibletertcolor,
+ "name" = "Tertiary color",
+ "anycolor" = 0,
+ ),
+ "quart" = list(
+ "options" = possiblequartcolor,
+ "name" = "Quaternary color",
+ "anycolor" = 0,
+ )
+ )
+ update_icon()
/obj/machinery/portable_atmospherics/canister/proc/check_change()
var/old_flag = update_flag
@@ -118,10 +123,13 @@
else
update_flag |= 32
- if(oldcolor != _color || olddecals != decals)
+ if(list2params(oldcolor) != list2params(_color))
update_flag |= 64
- olddecals = decals
- oldcolor = _color
+ oldcolor = _color.Copy()
+
+ if(list2params(olddecals) != list2params(decals))
+ update_flag |= 128
+ olddecals = decals.Copy()
if(update_flag == old_flag)
return 1
@@ -137,29 +145,31 @@ 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
+(note: colors and decals has to be applied every icon update)
*/
if (src.destroyed)
src.overlays = 0
- src.icon_state = text("[]-1", src._color[1])//yes, I KNOW the colours don't reflect when the can's borked, whatever.
+ src.icon_state = text("[]-1", src._color["prim"])//yes, I KNOW the colours don't reflect when the can's borked, whatever.
- if(icon_state != src._color[1])
- icon_state = src._color[1]
+ if(icon_state != src._color["prim"])
+ icon_state = src._color["prim"]
if(check_change()) //Returns 1 if no change needed to icons.
return
src.overlays = 0
- if (_color[2])//COLORS!
- overlays.Add(_color[2])
+ if (_color["sec"])//COLORS!
+ overlays.Add(_color["sec"])
- if (_color[3])
- overlays.Add(_color[3])
+ if (_color["ter"])
+ overlays.Add(_color["ter"])
- if (_color[4])
- overlays.Add(_color[4])
+ if (_color["quart"])
+ overlays.Add(_color["quart"])
for(var/D in decals)
overlays.Add("decal-" + D)
@@ -176,8 +186,36 @@ update_flag
overlays += "can-o2"
else if(update_flag & 32)
overlays += "can-o3"
+
+ update_flag &= ~196 //the flags 128 and 64 represent change, not states. As such, we have to reset them to be able to detect a change on the next go.
return
+//template modification exploit prevention, used in Topic()
+/obj/machinery/portable_atmospherics/canister/proc/is_a_color(var/inputVar, var/checkColor = "all")
+ if (checkColor == "prim" || checkColor == "all")
+ for(var/list/L in possiblemaincolor)
+ if (L["icon"] == inputVar)
+ return 1
+ if (checkColor == "sec" || checkColor == "all")
+ for(var/list/L in possibleseccolor)
+ if (L["icon"] == inputVar)
+ return 1
+ if (checkColor == "ter" || checkColor == "all")
+ for(var/list/L in possibletertcolor)
+ if (L["icon"] == inputVar)
+ return 1
+ if (checkColor == "quart" || checkColor == "all")
+ for(var/list/L in possiblequartcolor)
+ if (L["icon"] == inputVar)
+ return 1
+ return 0
+
+/obj/machinery/portable_atmospherics/canister/proc/is_a_decal(var/inputVar)
+ for(var/list/L in possibledecals)
+ if (L["icon"] == inputVar)
+ return 1
+ return 0
+
/obj/machinery/portable_atmospherics/canister/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(exposed_temperature > temperature_resistance)
health -= 5
@@ -329,7 +367,11 @@ update_flag
// this is the data which will be sent to the ui
var/data[0]
data["name"] = name
+ data["menu"] = menu ? 1 : 0
data["canLabel"] = can_label ? 1 : 0
+ data["_color"] = _color
+ data["colorContainer"] = colorcontainer
+ data["possibleDecals"] = possibledecals
data["portConnected"] = connected_port ? 1 : 0
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
data["releasePressure"] = round(release_pressure ? release_pressure : 0)
@@ -365,6 +407,9 @@ update_flag
onclose(usr, "canister")
return
+ if (href_list["choice"] == "menu")
+ menu = text2num(href_list["mode_target"])
+
if(href_list["toggle"])
if (valve_open)
if (holding)
@@ -393,48 +438,96 @@ update_flag
else
release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff)
- if (href_list["relabel"])
+ if (href_list["rename"])
if (can_label)
+ var/T = copytext(sanitize(input("Choose canister label", "Name", name) as text|null),1,MAX_NAME_LEN)
+ if (can_label) //Exploit prevention
+ if (T)
+ name = T
+ else
+ name = "canister"
+ else
+ usr << "\red As you attempted to rename it the pressure rose!"
- var/label1 = input("Choose canister label", "Primary color") as null|anything in possiblemaincolor
+ if (href_list["choice"] == "Primary color")
+ if (is_a_color(href_list["icon"],"prim"))
+ _color["prim"] = href_list["icon"]
+ if (href_list["choice"] == "Secondary color")
+ if (href_list["icon"] == "none")
+ _color["sec"] = ""
+ colorcontainer["sec"]["anycolor"] = 0
+ else if (is_a_color(href_list["icon"],"sec"))
+ _color["sec"] = href_list["icon"]
+ colorcontainer["sec"]["anycolor"] = 1
+ if (href_list["choice"] == "Tertiary color")
+ if (href_list["icon"] == "none")
+ _color["ter"] = ""
+ colorcontainer["ter"]["anycolor"] = 0
+ else if (is_a_color(href_list["icon"],"ter"))
+ _color["ter"] = href_list["icon"]
+ colorcontainer["ter"]["anycolor"] = 1
+ if (href_list["choice"] == "Quaternary color")
+ if (href_list["icon"] == "none")
+ _color["quart"] = ""
+ colorcontainer["quart"]["anycolor"] = 0
+ else if (is_a_color(href_list["icon"],"quart"))
+ _color["quart"] = href_list["icon"]
+ colorcontainer["quart"]["anycolor"] = 1
- var/label2 = input("Choose canister label", "Secondary color") as null|anything in possibleseccolor
-
- var/label3 = input("Choose canister label", "Tertiary color") as null|anything in possibletertcolor
-
- var/label4 = input("Choose canister label", "Quaternary color") as null|anything in possiblequartcolor
-
- decals = list()
-
- _color = list(
- (label1 ? possiblemaincolor[label1] : color[1]),//if the user didn't specify a primary colour, keep the current one.
- possibleseccolor[label2],
- possibletertcolor[label3],
- possiblequartcolor[label4]
- )
-
- decals = list()
-
- var/list/tempposdecals = possibledecals
- 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")
+ if (href_list["choice"] == "decals")
+ if (is_a_decal(href_list["icon"]))
+ for (var/list/L in possibledecals)
+ if (L["icon"] == href_list["icon"])
+ L["active"] = (L["active"] == 0)
break
- decals.Add(tempposdecals[newdecal])
- tempposdecals.Remove(newdecal)
- src.name = (input("Choose canister label", "Name") as text) + " canister"
+ decals = list()
+ for (var/list/L in possibledecals)
+ if (L["active"])
+ if (!(L["icon"] in decals))
+ decals.Add(L["icon"])
src.add_fingerprint(usr)
update_icon()
return 1
-/obj/machinery/portable_atmospherics/canister/toxins/New()
+/obj/machinery/portable_atmospherics/canister/toxins
+ name = "Canister \[Toxin (Plasma)\]"
+ icon_state = "orange" //See New()
+ can_label = 0
+/obj/machinery/portable_atmospherics/canister/oxygen
+ name = "Canister: \[O2\]"
+ icon_state = "blue" //See New()
+ can_label = 0
+/obj/machinery/portable_atmospherics/canister/sleeping_agent
+ name = "Canister: \[N2O\]"
+ icon_state = "redws" //See New()
+ can_label = 0
+/obj/machinery/portable_atmospherics/canister/nitrogen
+ name = "Canister: \[N2\]"
+ icon_state = "red" //See New()
+ can_label = 0
+/obj/machinery/portable_atmospherics/canister/carbon_dioxide
+ name = "Canister \[CO2\]"
+ icon_state = "black" //See New()
+ can_label = 0
+/obj/machinery/portable_atmospherics/canister/air
+ name = "Canister \[Air\]"
+ icon_state = "grey" //See New()
+ can_label = 0
+/obj/machinery/portable_atmospherics/canister/custom_mix
+ name = "Canister \[Custom\]"
+ icon_state = "whiters" //See New()
+ can_label = 0
+
+
+/obj/machinery/portable_atmospherics/canister/toxins/New()
..()
+ _color["prim"] = "orange"
src.air_contents.toxins = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
@@ -442,18 +535,18 @@ update_flag
return 1
/obj/machinery/portable_atmospherics/canister/oxygen/New()
-
..()
+ _color["prim"] = "blue"
src.air_contents.oxygen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
src.update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/sleeping_agent/New()
-
..()
+ _color["prim"] = "redws"
var/datum/gas/sleeping_agent/trace_gas = new
air_contents.trace_gases += trace_gas
trace_gas.moles = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
@@ -479,9 +572,11 @@ update_flag
/obj/machinery/portable_atmospherics/canister/nitrogen/New()
-
..()
+ _color["prim"] = "red"
+ decals = list("plasma")
+ possibledecals[3]["active"] = 1
src.air_contents.nitrogen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
@@ -489,8 +584,9 @@ update_flag
return 1
/obj/machinery/portable_atmospherics/canister/carbon_dioxide/New()
-
..()
+
+ _color["prim"] = "black"
src.air_contents.carbon_dioxide = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
@@ -499,8 +595,9 @@ update_flag
/obj/machinery/portable_atmospherics/canister/air/New()
-
..()
+
+ _color["prim"] = "grey"
src.air_contents.oxygen = (O2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
src.air_contents.nitrogen = (N2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
@@ -511,6 +608,7 @@ update_flag
/obj/machinery/portable_atmospherics/canister/custom_mix/New()
..()
+ _color["prim"] = "whiters"
src.update_icon() // Otherwise new canisters do not have their icon updated with the pressure light, likely want to add this to the canister class constructor, avoiding at current time to refrain from screwing up code for other canisters. --DZD
return 1
diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm
index 539dd775b0f..30ed21fbede 100644
--- a/code/game/machinery/bots/bots.dm
+++ b/code/game/machinery/bots/bots.dm
@@ -583,7 +583,7 @@ obj/machinery/bot/proc/start_patrol()
new_destination = "__nearest__"
post_signal(beacon_freq, "findbeacon", "patrol")
awaiting_beacon = 1
- spawn(150)
+ spawn(200)
awaiting_beacon = 0
if(nearest_beacon)
set_destination(nearest_beacon)
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 977c1bd3d3e..865bf2f3cb8 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -8,17 +8,20 @@
active_power_usage = 10
layer = 5
- var/datum/wires/camera/wires = null // Wires datum
var/list/network = list("SS13")
var/c_tag = null
var/c_tag_order = 999
- var/status = 1.0
+ var/status = 1
anchored = 1.0
- var/invuln = null
+ panel_open = 0 // 0 = Closed / 1 = Open
+ var/indestructible = 0
var/bugged = 0
var/obj/item/weapon/camera_assembly/assembly = null
- var/watcherslist = list()
- var/obj/item/device/camera_bug/hasbug = null
+
+ var/toughness = 5 //sorta fragile
+
+ // WIRES
+ var/datum/wires/camera/wires = null // Wires datum
//OTHER
@@ -28,15 +31,18 @@
var/light_disabled = 0
var/alarm_on = 0
var/busy = 0
- var/indestructible = 0 // If set, prevents aliens from destroying it
+
+ var/obj/item/device/camera_bug/hasbug = null
/obj/machinery/camera/New()
wires = new(src)
-
assembly = new(src)
assembly.state = 4
+
+ //invalidateCameraCache()
+
/* // Use this to look for cameras that have the same c_tag.
- for(var/obj/machinery/camera/C in cameranet.viewpoints)
+ for(var/obj/machinery/camera/C in cameranet.cameras)
var/list/tempnetwork = C.network&src.network
if(C != src && C.c_tag == src.c_tag && tempnetwork.len)
world.log << "[src.c_tag] [src.x] [src.y] [src.z] conflicts with [C.c_tag] [C.x] [C.y] [C.z]"
@@ -50,51 +56,48 @@
ASSERT(src.network.len > 0)
..()
+/obj/machinery/camera/Del()
+ if(!alarm_on)
+ triggerCameraAlarm()
+
+ cancelCameraAlarm()
+ ..()
+
/obj/machinery/camera/emp_act(severity)
if(!isEmpProof())
if(prob(100/severity))
- icon_state = "[initial(icon_state)]emp"
- var/list/previous_network = network
- network = list()
- cameranet.removeCamera(src)
+ //invalidateCameraCache()
stat |= EMPED
SetLuminosity(0)
+ kick_viewers()
triggerCameraAlarm()
+ update_icon()
+
spawn(900)
- network = previous_network
- icon_state = initial(icon_state)
stat &= ~EMPED
cancelCameraAlarm()
- if(can_use())
- cameranet.addCamera(src)
- for(var/mob/O in mob_list)
- if(O.client && O.client.eye == src)
- O.unset_machine()
- O.reset_view(null)
- O << "The screen bursts into static."
+ update_icon()
+ //invalidateCameraCache()
..()
+/obj/machinery/camera/bullet_act(var/obj/item/projectile/P)
+ if(P.damage_type == BRUTE || P.damage_type == BURN)
+ take_damage(P.damage)
/obj/machinery/camera/ex_act(severity)
- if(src.invuln)
+ if(indestructible)
return
- else
- ..(severity)
- return
+
+ //camera dies if an explosion touches it!
+ if(severity <= 2 || prob(50))
+ destroy()
+
+ ..() //and give it the regular chance of being deleted outright
+
/obj/machinery/camera/blob_act()
- del(src)
return
-
-/obj/machinery/camera/proc/setViewRange(var/num = 7)
- src.view_range = num
- cameranet.updateVisibility(src, 0)
-
-/obj/machinery/camera/proc/shock(var/mob/living/user)
- if(!istype(user))
- return
- user.electrocute_act(10, src)
-
+
/obj/machinery/camera/attack_paw(mob/living/carbon/alien/humanoid/user as mob)
if(!istype(user))
return
@@ -107,10 +110,22 @@
add_hiddenprint(user)
deactivate(user,0)
-/obj/machinery/camera/attackby(W as obj, mob/living/user as mob)
+/obj/machinery/camera/hitby(AM as mob|obj)
+ ..()
+ if (istype(AM, /obj))
+ var/obj/O = AM
+ if (O.throwforce >= src.toughness)
+ visible_message("[src] was hit by [O].")
+ take_damage(O.throwforce)
+/obj/machinery/camera/proc/setViewRange(var/num = 7)
+ src.view_range = num
+ cameranet.updateVisibility(src, 0)
+
+/obj/machinery/camera/attackby(obj/W as obj, mob/living/user as mob)
+ //invalidateCameraCache()
// DECONSTRUCTION
- if(istype(W, /obj/item/weapon/screwdriver))
+ if(isscrewdriver(W))
//user << "You start to [panel_open ? "close" : "open"] the camera's panel."
//if(toggle_panel(user)) // No delay because no one likes screwdrivers trying to be hip and have a duration cooldown
panel_open = !panel_open
@@ -118,19 +133,21 @@
"You screw the camera's panel [panel_open ? "open" : "closed"].")
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- else if((istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/multitool)) && panel_open)
- wires.Interact(user)
+ else if((iswirecutter(W) || ismultitool(W)) && panel_open)
+ interact(user)
- else if(istype(W, /obj/item/weapon/weldingtool) && wires.CanDeconstruct())
+ else if(iswelder(W) && (wires.CanDeconstruct() || (stat & BROKEN)))
if(weld(W, user))
- if(assembly)
+ if (stat & BROKEN)
+ new /obj/item/stack/cable_coil(src.loc, length=2)
+ else if(assembly)
assembly.loc = src.loc
assembly.state = 1
+ new /obj/item/stack/cable_coil(src.loc, length=2)
del(src)
-
// OTHER
- else if ((istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user))
+ else if (can_use() && (istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user))
var/mob/living/U = user
var/obj/item/weapon/paper/X = null
var/obj/item/device/pda/P = null
@@ -152,11 +169,12 @@
else O << "[U] holds \a [itemname] up to one of your cameras ..."
O << browse(text("[][]", itemname, info), text("window=[]", itemname))
for(var/mob/O in player_list)
- if(O.client && O.client.eye == src)
- O.unset_machine()
- O.reset_view(null)
- O << "[U] holds \a [itemname] up to the camera..."
- O << browse("[itemname][info]","window=[itemname]")
+ if (istype(O.machine, /obj/machinery/computer/security))
+ var/obj/machinery/computer/security/S = O.machine
+ if (S.current == src)
+ O << "[U] holds \a [itemname] up to one of the cameras ..."
+ O << browse(text("[][]", itemname, info), text("window=[]", itemname))
+
else if (istype(W, /obj/item/device/camera_bug) && panel_open)
if (!src.can_use())
user << "\blue Camera non-functional"
@@ -165,32 +183,24 @@
user << "\blue Camera bugged."
user.drop_item(W)
hasbug = W
- contents += W
- if(prob(15))
- spawn(30)
- if(src.can_use() && hasbug)
- desc += "
The power light on the camera is blinking"
- triggerCameraAlarm()
+ src.bugged = 1
else if (iscrowbar(W) && panel_open && src.hasbug)
user << "\blue You retrieve \the [hasbug]"
user.put_in_hands(hasbug)
hasbug = null
- deactivatebug(user)
- else if(istype(W, /obj/item/weapon/melee/energy/blade))//Putting it here last since it's a special case. I wonder if there is a better way to do these than type casting.
- deactivate(user,2)//Here so that you can disconnect anyone viewing the camera, regardless if it's on or off.
- var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
- spark_system.set_up(5, 0, loc)
- spark_system.start()
- playsound(loc, 'sound/weapons/blade1.ogg', 50, 1)
- playsound(loc, "sparks", 50, 1)
- visible_message("\blue The camera has been sliced apart by [] with an energy blade!")
- del(src)
- else if(istype(W, /obj/item/device/laser_pointer))
- var/obj/item/device/laser_pointer/L = W
- L.laser_act(src, user)
+ deactivatebug(user)
+ else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras
+ if (W.force >= src.toughness)
+ visible_message("[src] has been [pick(W.attack_verb)] with [W] by [user]!")
+ if (istype(W, /obj/item)) //is it even possible to get into attackby() with non-items?
+ var/obj/item/I = W
+ if (I.hitsound)
+ playsound(loc, I.hitsound, 50, 1, -1)
+ take_damage(W.force)
+
else
..()
- return
+
/obj/machinery/camera/proc/deactivatebug(user as mob)
for(var/mob/O in player_list)
if(istype(O.machine, /obj/item/device/handtv))
@@ -201,50 +211,91 @@
O << "The screen bursts into static."
/obj/machinery/camera/proc/deactivate(user as mob, var/choice = 1)
- if(choice==1)
- status = !( src.status )
+ if(choice != 1)
+ //legacy support, if choice is != 1 then just kick viewers without changing status
+ kick_viewers()
+ else
+ //invalidateCameraCache()
+ set_status( !src.status )
if (!(src.status))
- if(user)
- visible_message("\red [user] has deactivated [src]!")
- add_hiddenprint(user)
- else
- visible_message("\red \The [src] deactivates!")
+ visible_message("\red [user] has deactivated [src]!")
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
icon_state = "[initial(icon_state)]1"
add_hiddenprint(user)
else
- if(user)
- visible_message("\red [user] has reactivated [src]!")
- add_hiddenprint(user)
- else
- visible_message("\red \the [src] reactivates!")
+ visible_message("\red [user] has reactivated [src]!")
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
icon_state = initial(icon_state)
add_hiddenprint(user)
- // now disconnect anyone using the camera
- //Apparently, this will disconnect anyone even if the camera was re-activated.
- //I guess that doesn't matter since they can't use it anyway?
+
+/obj/machinery/camera/proc/take_damage(var/force, var/message)
+ //prob(25) gives an average of 3-4 hits
+ if (force >= toughness && (force > toughness*4 || prob(25)))
+ destroy()
+
+//Used when someone breaks a camera
+/obj/machinery/camera/proc/destroy()
+ //invalidateCameraCache()
+ stat |= BROKEN
+ kick_viewers()
+ triggerCameraAlarm()
+ update_icon()
+
+ //sparks
+ var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
+ spark_system.set_up(5, 0, loc)
+ spark_system.start()
+ playsound(loc, "sparks", 50, 1)
+
+/obj/machinery/camera/proc/set_status(var/newstatus)
+ if (status != newstatus)
+ status = newstatus
+ //invalidateCameraCache()
+ // now disconnect anyone using the camera
+ //Apparently, this will disconnect anyone even if the camera was re-activated.
+ //I guess that doesn't matter since they couldn't use it anyway?
+ kick_viewers()
+
+//This might be redundant, because of check_eye()
+/obj/machinery/camera/proc/kick_viewers()
for(var/mob/O in player_list)
- if(O.client && O.client.eye == src)
- O.unset_machine()
- O.reset_view(null)
- O << "The screen bursts into static."
+ if (istype(O.machine, /obj/machinery/computer/security))
+ var/obj/machinery/computer/security/S = O.machine
+ if (S.current == src)
+ O.unset_machine()
+ O.reset_view(null)
+ O << "The screen bursts into static."
+
+/obj/machinery/camera/update_icon()
+ if (!status || (stat & BROKEN))
+ icon_state = "[initial(icon_state)]1"
+ else if (stat & EMPED)
+ icon_state = "[initial(icon_state)]emp"
+ else
+ icon_state = initial(icon_state)
/obj/machinery/camera/proc/triggerCameraAlarm()
alarm_on = 1
+ if(!get_area(src))
+ return
+
for(var/mob/living/silicon/S in mob_list)
S.triggerAlarm("Camera", get_area(src), list(src), src)
/obj/machinery/camera/proc/cancelCameraAlarm()
alarm_on = 0
+ if(!get_area(src))
+ return
+
for(var/mob/living/silicon/S in mob_list)
- S.cancelAlarm("Camera", get_area(src), list(src), src)
+ S.cancelAlarm("Camera", get_area(src), src)
+//if false, then the camera is listed as DEACTIVATED and cannot be used
/obj/machinery/camera/proc/can_use()
if(!status)
return 0
- if(stat & EMPED)
+ if(stat & (EMPED|BROKEN))
return 0
return 1
@@ -266,13 +317,13 @@
//If someone knows a better way to do this, let me know. -Giacom
switch(i)
if(NORTH)
- src.dir = SOUTH
+ dir = SOUTH
if(SOUTH)
- src.dir = NORTH
+ dir = NORTH
if(WEST)
- src.dir = EAST
+ dir = EAST
if(EAST)
- src.dir = WEST
+ dir = WEST
break
//Return a working camera that can see a given mob
@@ -312,3 +363,14 @@
return 1
busy = 0
return 0
+
+/obj/machinery/camera/interact(mob/living/user as mob)
+ if(!panel_open || istype(user, /mob/living/silicon/ai))
+ return
+
+ if(stat & BROKEN)
+ user << "\The [src] is broken."
+ return
+
+ user.set_machine(src)
+ wires.Interact(user)
diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm
index 9f6eb2210af..7b72b5bc3f4 100644
--- a/code/game/machinery/camera/camera_assembly.dm
+++ b/code/game/machinery/camera/camera_assembly.dm
@@ -1,16 +1,15 @@
/obj/item/weapon/camera_assembly
name = "camera assembly"
- desc = "The basic construction for Nanotrasen-Always-Watching-You cameras."
+ desc = "A pre-fabricated security camera kit, ready to be assembled and mounted to a surface."
icon = 'icons/obj/monitors.dmi'
icon_state = "cameracase"
w_class = 2
anchored = 0
-
m_amt = 700
g_amt = 300
// Motion, EMP-Proof, X-Ray
- var/list/obj/item/possible_upgrades = list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/sheet/mineral/plasma, /obj/item/weapon/reagent_containers/food/snacks/grown/carrot)
+ var/list/obj/item/possible_upgrades = list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/sheet/mineral/osmium, /obj/item/weapon/stock_parts/scanning_module)
var/list/upgrades = list()
var/state = 0
var/busy = 0
@@ -59,8 +58,10 @@
if(iscoil(W))
var/obj/item/stack/cable_coil/C = W
if(C.use(2))
- user << "You add wires to the assembly."
+ user << "You add wires to the assembly."
state = 3
+ else
+ user << "You need 2 coils of wire to wire the assembly."
return
else if(iswelder(W))
@@ -87,7 +88,8 @@
usr << "No network found please hang up and try your call again."
return
- var/temptag = "[get_area(src)] ([rand(1, 999)])"
+ var/area/camera_area = get_area(src)
+ var/temptag = "[sanitize(camera_area.name)] ([rand(1, 999)])"
input = strip_html(input(usr, "How would you like to name the camera?", "Set Camera Name", temptag))
state = 4
@@ -98,7 +100,7 @@
C.auto_turn()
C.network = uniquelist(tempnetwork)
- tempnetwork = difflist(C.network,RESTRICTED_CAMERA_NETWORKS)
+ tempnetwork = difflist(C.network,restricted_camera_networks)
if(!tempnetwork.len)//Camera isn't on any open network - remove its chunk from AI visibility.
cameranet.removeCamera(C)
@@ -124,7 +126,7 @@
// Upgrades!
if(is_type_in_list(W, possible_upgrades) && !is_type_in_list(W, upgrades)) // Is a possible upgrade and isn't in the camera already.
- user << "You attach the [W] into the assembly inner circuits."
+ user << "You attach \the [W] into the assembly inner circuits."
upgrades += W
user.drop_item(W)
W.loc = src
@@ -169,4 +171,4 @@
return 0
return 1
busy = 0
- return 0
\ No newline at end of file
+ return 0
diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm
index 588ab5005ce..0c6f7d95a7f 100644
--- a/code/game/machinery/camera/motion.dm
+++ b/code/game/machinery/camera/motion.dm
@@ -8,6 +8,8 @@
/obj/machinery/camera/process()
// motion camera event loop
+ if (stat & (EMPED|NOPOWER))
+ return
if(!isMotion())
. = PROCESS_KILL
return
@@ -40,16 +42,20 @@
cancelAlarm()
/obj/machinery/camera/proc/cancelAlarm()
+ if (!status || (stat & NOPOWER))
+ return 0
if (detectTime == -1)
for (var/mob/living/silicon/aiPlayer in player_list)
- if (status) aiPlayer.cancelAlarm("Motion", src.loc.loc)
+ aiPlayer.cancelAlarm("Motion", get_area(src), src)
detectTime = 0
return 1
/obj/machinery/camera/proc/triggerAlarm()
+ if (!status || (stat & NOPOWER))
+ return 0
if (!detectTime) return 0
for (var/mob/living/silicon/aiPlayer in player_list)
- if (status) aiPlayer.triggerAlarm("Motion", src.loc.loc, src)
+ aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src)
detectTime = -1
return 1
diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm
index 0ee0e622b8b..21a9dc10616 100644
--- a/code/game/machinery/camera/presets.dm
+++ b/code/game/machinery/camera/presets.dm
@@ -53,12 +53,14 @@
// CHECKS
/obj/machinery/camera/proc/isEmpProof()
- var/O = locate(/obj/item/stack/sheet/mineral/plasma) in assembly.upgrades
+ var/O = locate(/obj/item/stack/sheet/mineral/osmium) in assembly.upgrades
return O
/obj/machinery/camera/proc/isXRay()
- var/O = locate(/obj/item/weapon/reagent_containers/food/snacks/grown/carrot) in assembly.upgrades
- return O
+ var/obj/item/weapon/stock_parts/scanning_module/O = locate(/obj/item/weapon/stock_parts/scanning_module) in assembly.upgrades
+ if (O && O.rating >= 2)
+ return O
+ return null
/obj/machinery/camera/proc/isMotion()
var/O = locate(/obj/item/device/assembly/prox_sensor) in assembly.upgrades
@@ -67,11 +69,22 @@
// UPGRADE PROCS
/obj/machinery/camera/proc/upgradeEmpProof()
- assembly.upgrades.Add(new /obj/item/stack/sheet/mineral/plasma(assembly))
+ assembly.upgrades.Add(new /obj/item/stack/sheet/mineral/osmium(assembly))
+ setPowerUsage()
/obj/machinery/camera/proc/upgradeXRay()
- assembly.upgrades.Add(new /obj/item/weapon/reagent_containers/food/snacks/grown/carrot(assembly))
+ assembly.upgrades.Add(new /obj/item/weapon/stock_parts/scanning_module/adv(assembly))
+ setPowerUsage()
// If you are upgrading Motion, and it isn't in the camera's New(), add it to the machines list.
/obj/machinery/camera/proc/upgradeMotion()
- assembly.upgrades.Add(new /obj/item/device/assembly/prox_sensor(assembly))
\ No newline at end of file
+ assembly.upgrades.Add(new /obj/item/device/assembly/prox_sensor(assembly))
+ setPowerUsage()
+
+/obj/machinery/camera/proc/setPowerUsage()
+ var/mult = 1
+ if (isXRay())
+ mult++
+ if (isMotion())
+ mult++
+ active_power_usage = mult*initial(active_power_usage)
diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index 47b2edf9fac..47c27591e99 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -1,16 +1,25 @@
+/mob/living/silicon/ai/var/max_locations = 10
+/mob/living/silicon/ai/var/stored_locations[0]
+
+/mob/living/silicon/ai/proc/InvalidTurf(turf/T as turf)
+ if(!T)
+ return 1
+ if(T.z == 2)
+ return 1
+ if(T.z > 6)
+ return 1
+ return 0
+
/mob/living/silicon/ai/proc/get_camera_list()
+
if(src.stat == 2)
return
- var/list/L = list()
- for (var/obj/machinery/camera/C in cameranet.viewpoints)
- L.Add(C)
-
- camera_sort(L)
+ cameranet.process_sort()
var/list/T = list()
T["Cancel"] = "Cancel"
- for (var/obj/machinery/camera/C in L)
+ for (var/obj/machinery/camera/C in cameranet.cameras)
var/list/tempnetwork = C.network&src.network
if (tempnetwork.len)
T[text("[][]", C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C
@@ -19,20 +28,76 @@
track.cameras = T
return T
+
/mob/living/silicon/ai/proc/ai_camera_list(var/camera in get_camera_list())
+ set category = "AI Commands"
+ set name = "Show Camera List"
+
if(src.stat == 2)
src << "You can't list the cameras because you are dead!"
return
if (!camera || camera == "Cancel")
return 0
-
+
var/obj/machinery/camera/C = track.cameras[camera]
- track = null
src.eyeobj.setLoc(C)
return
+/mob/living/silicon/ai/proc/ai_store_location(loc as text)
+ set category = "AI Commands"
+ set name = "Store Camera Location"
+ set desc = "Stores your current camera location by the given name"
+
+ loc = sanitize(copytext(loc, 1, MAX_MESSAGE_LEN))
+ if(!loc)
+ src << "\red Must supply a location name"
+ return
+
+ if(stored_locations.len >= max_locations)
+ src << "\red Cannot store additional locations. Remove one first"
+ return
+
+ if(loc in stored_locations)
+ src << "\red There is already a stored location by this name"
+ return
+
+ var/L = src.eyeobj.getLoc()
+ if (InvalidTurf(get_turf(L)))
+ src << "\red Unable to store this location"
+ return
+
+ stored_locations[loc] = L
+ src << "Location '[loc]' stored"
+
+/mob/living/silicon/ai/proc/sorted_stored_locations()
+ return sortList(stored_locations)
+
+/mob/living/silicon/ai/proc/ai_goto_location(loc in sorted_stored_locations())
+ set category = "AI Commands"
+ set name = "Goto Camera Location"
+ set desc = "Returns to the selected camera location"
+
+ if (!(loc in stored_locations))
+ src << "\red Location [loc] not found"
+ return
+
+ var/L = stored_locations[loc]
+ src.eyeobj.setLoc(L)
+
+/mob/living/silicon/ai/proc/ai_remove_location(loc in sorted_stored_locations())
+ set category = "AI Commands"
+ set name = "Delete Camera Location"
+ set desc = "Deletes the selected camera location"
+
+ if (!(loc in stored_locations))
+ src << "\red Location [loc] not found"
+ return
+
+ stored_locations.Remove(loc)
+ src << "Location [loc] removed"
+
// Used to allow the AI is write in mob names/camera name from the CMD line.
/datum/trackable
var/list/names = list()
@@ -50,12 +115,7 @@
for(var/mob/living/M in mob_list)
// Easy checks first.
// Don't detect mobs on Centcom. Since the wizard den is on Centcomm, we only need this.
- var/turf/T = get_turf(M)
- if(!T)
- continue
- if(T.z == 2)
- continue
- if(T.z > 6)
+ if(InvalidTurf(get_turf(M)))
continue
if(M == usr)
continue
@@ -72,10 +132,6 @@
//Cameras can't track people wearing an agent card or a ninja hood.
if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
continue
- if(istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja))
- var/obj/item/clothing/head/helmet/space/space_ninja/hood = H.head
- if(!hood.canremove)
- continue
// Now, are they viewable by a camera? (This is last because it's the most intensive check)
if(!near_camera(M))
@@ -98,6 +154,10 @@
return targets
/mob/living/silicon/ai/proc/ai_camera_track(var/target_name in trackable_mobs())
+ set category = "AI Commands"
+ set name = "Track With Camera"
+ set desc = "Select who you would like to track."
+
if(src.stat == 2)
src << "You can't track with camera because you are dead!"
return
@@ -108,61 +168,18 @@
src.track = null
ai_actual_track(target)
-/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target as mob)
- if(!istype(target)) return
- spawn(0)
- if(istype(target, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = target
- if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
- src << "Unable to locate an airlock"
- return
- if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
- src << "Unable to locate an airlock"
- return
- if(istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja) && !H.head.canremove)
- src << "Unable to locate an airlock"
- return
- if(H.digitalcamo)
- src << "Unable to locate an airlock"
- return
- if (!near_camera(target))
- src << "Target is not near any active cameras."
- return
- var/obj/machinery/door/airlock/tobeopened
- var/dist = -1
- for(var/obj/machinery/door/airlock/D in range(3,target))
- if(!D.density) continue
- if(dist < 0)
- dist = get_dist(D, target)
- //world << dist
- tobeopened = D
- else
- if(dist > get_dist(D, target))
- dist = get_dist(D, target)
- //world << dist
- tobeopened = D
- //world << "found [tobeopened.name] closer"
- else
- //world << "[D.name] not close enough | [get_dist(D, target)] | [dist]"
- if(tobeopened)
- switch(alert(src, "Do you want to open \the [tobeopened] for [target]?","Doorknob_v2a.exe","Yes","No"))
- if("Yes")
- var/nhref = "src=\ref[tobeopened];aiEnable=7"
- tobeopened.Topic(nhref, params2list(nhref), tobeopened, 1)
- src << "\blue You've opened \the [tobeopened] for [target]."
- if("No")
- src << "\red You deny the request."
- else
- src << "\red You've failed to open an airlock for [target]"
+/mob/living/silicon/ai/proc/ai_cancel_tracking(var/forced = 0)
+ if(!cameraFollow)
return
-/mob/living/silicon/ai/proc/ai_actual_track(atom/target as mob|obj)
+
+ src << "Follow camera mode [forced ? "terminated" : "ended"]."
+ cameraFollow = null
+
+/mob/living/silicon/ai/proc/ai_actual_track(atom/movable/target as mob|obj)
if(!istype(target)) return
var/mob/living/silicon/ai/U = usr
U.cameraFollow = target
- //U << text("Now tracking [] on camera.", target.name)
- //if (U.machine == null)
- // U.machine = U
U << "Now tracking [target.name] on camera."
spawn (0)
@@ -172,30 +189,23 @@
if (istype(target, /mob/living/carbon/human))
var/mob/living/carbon/human/H = target
if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
- U << "Follow camera mode terminated."
- U.cameraFollow = null
+ U.ai_cancel_tracking(1)
return
-/* if(istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja) && !H.head.canremove)
- U << "Follow camera mode terminated."
- U.cameraFollow = null
- return*/
if(H.digitalcamo)
- U << "Follow camera mode terminated."
- U.cameraFollow = null
+ U.ai_cancel_tracking(1)
return
if(istype(target.loc,/obj/effect/dummy))
- U << "Follow camera mode ended."
- U.cameraFollow = null
+ U.ai_cancel_tracking()
return
- if (!near_camera(target))
+ if (!trackable(target))
U << "Target is not near any active cameras."
sleep(100)
continue
if(U.eyeobj)
- U.eyeobj.setLoc(get_turf(target))
+ U.eyeobj.setLoc(get_turf(target), 0)
else
view_core()
return
@@ -212,6 +222,12 @@
return 0
return 1
+/proc/trackable(atom/movable/M)
+ var/turf/T = get_turf(M)
+ if(T && (T.z == 1 || T.z == 3 || T.z == 5))
+ return 1
+
+ return near_camera(M)
/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user as mob)
if (!istype(user))
@@ -223,19 +239,3 @@
/mob/living/silicon/ai/attack_ai(var/mob/user as mob)
ai_camera_list()
-
-/proc/camera_sort(list/L)
- var/obj/machinery/camera/a
- var/obj/machinery/camera/b
-
- for (var/i = L.len, i > 0, i--)
- for (var/j = 1 to i - 1)
- a = L[j]
- b = L[j + 1]
- if (a.c_tag_order != b.c_tag_order)
- if (a.c_tag_order > b.c_tag_order)
- L.Swap(j, j + 1)
- else
- if (sorttext(a.c_tag, b.c_tag) < 0)
- L.Swap(j, j + 1)
- return L
diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm
index a24ca549dce..5e9bb34866b 100644
--- a/code/game/machinery/computer/atmos_alert.dm
+++ b/code/game/machinery/computer/atmos_alert.dm
@@ -23,8 +23,10 @@
var/zone = signal.data["zone"]
var/severity = signal.data["alert"]
+ var/hidden = signal.data["hidden"]
if(!zone || !severity) return
+ if(hidden) return
minor_alarms -= zone
priority_alarms -= zone
diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm
index 7bc376580b8..403c11ca3f4 100644
--- a/code/game/machinery/computer/camera.dm
+++ b/code/game/machinery/computer/camera.dm
@@ -1,3 +1,7 @@
+/proc/invalidateCameraCache()
+ for(var/obj/machinery/computer/security/s in world)
+ s.camera_cache = null
+
/obj/machinery/computer/security
name = "Camera Monitor"
desc = "Used to access the various cameras networks on the station."
@@ -12,6 +16,7 @@
var/list/tempnets[0]
var/list/data[0]
var/list/access[0]
+ var/camera_cache = null
New() // Lists existing networks and their required access. Format: networks[] = list()
networks["SS13"] = list(access_hos,access_captain)
@@ -76,14 +81,15 @@
var/data[0]
+
data["current"] = null
var/list/L = list()
- for (var/obj/machinery/camera/C in cameranet.viewpoints)
+ for (var/obj/machinery/camera/C in cameranet.cameras)
if(can_access_camera(C))
L.Add(C)
- camera_sort(L)
+ cameranet.process_sort()
var/cameras[0]
for(var/obj/machinery/camera/C in L)
@@ -106,7 +112,7 @@
if(emagged)
access = list(access_captain) // Assume captain level access when emagged
data["emagged"] = 1
- if(isAI(user) || isrobot (user))
+ if(isAI(user) || isrobot(user))
access = list(access_captain) // Assume captain level access when AI
// Loop through the ID's permission, and check which networks the ID has access to.
@@ -119,6 +125,9 @@
tempnets.Add(list(list("name" = l, "active" = 0)))
break
data["networks"] = tempnets
+
+ if(ui)
+ ui.load_cached_data(camera_cache)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
@@ -137,7 +146,7 @@
if(href_list["switchTo"])
if(src.z>6 || stat&(NOPOWER|BROKEN)) return
if(usr.stat || ((get_dist(usr, src) > 1 || !( usr.canmove ) || usr.blinded) && !istype(usr, /mob/living/silicon))) return
- var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.viewpoints
+ var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.cameras
if(!C) return
switch_to_camera(usr, C)
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/cryo.dm b/code/game/machinery/cryo.dm
index 3a393c866bb..d4dc7ac6192 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -221,12 +221,14 @@
for(var/datum/reagent/R in beaker.reagents.reagent_list)
data["beakerVolume"] += R.volume
+ data["autoeject"] = autoeject
+
// 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)
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, "cryo.tmpl", "Cryo Cell Control System", 520, 410)
+ ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 420)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
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/shieldgen.dm b/code/game/machinery/shieldgen.dm
index 364abbfaf64..39e9e903c1a 100644
--- a/code/game/machinery/shieldgen.dm
+++ b/code/game/machinery/shieldgen.dm
@@ -25,15 +25,6 @@
if(!height || air_group) return 0
else return ..()
-//Looks like copy/pasted code... I doubt 'need_rebuild' is even used here - Nodrak
-/obj/machinery/shield/proc/update_nearby_tiles(need_rebuild)
- if(!air_master) return 0
-
- air_master.mark_for_update(get_turf(src))
-
- return 1
-
-
/obj/machinery/shield/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(!istype(W)) return
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 76ec87bb26c..63946f0f6e4 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -467,10 +467,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()
@@ -1107,15 +1107,6 @@ steam.start() -- spawns the effect
if(air_group) return 0
return !density
-
- proc/update_nearby_tiles(need_rebuild)
- if(!air_master)
- return 0
-
- air_master.mark_for_update(get_turf(src))
-
- return 1
-
/datum/effect/effect/system/reagents_explosion
var/amount // TNT equivalent
var/flashing = 0 // does explosion creates flash effect?
diff --git a/code/game/objects/items/devices/handtv.dm b/code/game/objects/items/devices/handtv.dm
index 0406db85852..48e22348f32 100644
--- a/code/game/objects/items/devices/handtv.dm
+++ b/code/game/objects/items/devices/handtv.dm
@@ -7,7 +7,7 @@
/obj/item/device/handtv/attack_self(mob/usr as mob)
var/list/cameras = new/list()
- for (var/obj/machinery/camera/C in cameranet.viewpoints)
+ for (var/obj/machinery/camera/C in cameranet.cameras)
if (C.hasbug && C.status)
cameras.Add(C)
if (length(cameras) == 0)
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 1c4c17e1cfd..583aaafe379 100644
--- a/code/game/objects/items/policetape.dm
+++ b/code/game/objects/items/policetape.dm
@@ -26,7 +26,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/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm
index 6162e9cfe09..d73420e42ee 100755
--- a/code/game/objects/items/weapons/AI_modules.dm
+++ b/code/game/objects/items/weapons/AI_modules.dm
@@ -101,13 +101,20 @@ AI MODULES
for(var/templaw in laws)
target.add_inherent_law(templaw)
+/obj/item/weapon/aiModule/zeroth
+ var/removeownlaw = 0
+
/obj/item/weapon/aiModule/zeroth/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender)
if(target.laws.zeroth)
- target << "[sender.real_name] attempted to modify your zeroth law."
- target << "It would be in your best interest to play along with [sender.real_name] that:"
- for(var/failedlaw in laws)
- target << "[failedlaw]"
- return 1
+ if(removeownlaw && (laws[1] == target.laws.zeroth))
+ target.clear_zeroth_law()
+ return 2
+ else
+ target << "[sender.real_name] attempted to modify your zeroth law."
+ target << "It would be in your best interest to play along with [sender.real_name] that:"
+ for(var/failedlaw in laws)
+ target << "[failedlaw]"
+ return 1
for(var/templaw in laws)
target.set_zeroth_law(templaw)
@@ -149,7 +156,7 @@ AI MODULES
/obj/item/weapon/aiModule/zeroth/oneHuman
name = "'OneHuman' AI Module"
var/targetName = ""
- desc = "A 'one human' AI module: 'Only is crew.'"
+ desc = "A 'one human' AI module: 'Only is crew.' This module adds a zeroth law, which can only be removed by uploading this board again."
origin_tech = "programming=3;materials=6" //made with diamonds!
laws = list("Only is crew.")
@@ -159,6 +166,7 @@ AI MODULES
targetName = targName
laws[1] = "Only [targetName] is crew"
desc = "A 'one crew' AI module: '[laws[1]]'"
+ removeownlaw = 1
/obj/item/weapon/aiModule/zeroth/oneHuman/install(var/mob/living/silicon/S,var/mob/user)
if(!targetName)
@@ -167,8 +175,10 @@ AI MODULES
..()
/obj/item/weapon/aiModule/zeroth/oneHuman/transmitInstructions(var/mob/living/silicon/target, var/mob/sender)
- if(..())
- return "[targetName], but the AI's existing law 0 cannot be overriden."
+ if(..() == 1)
+ return "[targetName], but the AI's existing zeroth law cannot be overriden."
+ if(..() == 2)
+ return "The AI's zeroth law has been overridden."
return targetName
@@ -186,13 +196,17 @@ AI MODULES
/obj/item/weapon/aiModule/zeroth/quarantine
name = "'Quarantine' AI Module"
- desc = "A 'quarantine' AI module: 'The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, organics from leaving. It is impossible to harm an organic while preventing them from leaving.'"
+ desc = "A 'quarantine' AI module: 'The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, organics from leaving. It is impossible to harm an organic while preventing them from leaving.' This module adds a zeroth law, which can only be removed by uploading this board again."
origin_tech = "programming=3;biotech=2;materials=4"
laws = list("The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, organics from leaving. It is impossible to harm an organic while preventing them from leaving.")
+ removeownlaw = 1
/obj/item/weapon/aiModule/zeroth/quarantine/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender)
- if(..())
- return "The AI's existing law 0 cannot be overriden."
+ var/result = ..()
+ if(result == 1)
+ return "The AI's existing zeroth law cannot be overriden."
+ if(result == 2)
+ return "The AI's zeroth law has been overridden."
return laws[1]
/******************** OxygenIsToxicToHumans ********************/
@@ -259,7 +273,7 @@ AI MODULES
/obj/item/weapon/aiModule/reset/purge/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender)
..()
- target.clear_inherent_laws()
+ target.clear_inherent_laws()
/******************* Full Core Boards *******************/
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 8997b016e4d..8741ccb8576 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 5f0274f6fd7..2a16ed05b2d 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 ac051ebd63d..f8fa6f7149b 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 f5e7459f135..cbbde21c7a3 100644
--- a/code/game/objects/items/weapons/weaponry.dm
+++ b/code/game/objects/items/weapons/weaponry.dm
@@ -110,6 +110,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/inflatable.dm b/code/game/objects/structures/inflatable.dm
index 8422c076d76..640a7f6951c 100644
--- a/code/game/objects/structures/inflatable.dm
+++ b/code/game/objects/structures/inflatable.dm
@@ -34,14 +34,6 @@
update_nearby_tiles()
..()
- proc/update_nearby_tiles(need_rebuild) //Copypasta from airlock code
- if(!air_master)
- return 0
- air_master.mark_for_update(get_turf(src))
- return 1
-
-
-
CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
return 0
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/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm
index 8b7d70b4dc4..06bd5d139a3 100644
--- a/code/game/objects/structures/mineral_doors.dm
+++ b/code/game/objects/structures/mineral_doors.dm
@@ -157,13 +157,6 @@
CheckHardness()
return
- proc/update_nearby_tiles(need_rebuild) //Copypasta from airlock code
- if(!air_master) return 0
-
- air_master.mark_for_update(get_turf(src))
-
- return 1
-
/obj/structure/mineral_door/iron
mineralType = "metal"
hardness = 3
diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm
index b9e5b2a34f6..20569ee7af8 100644
--- a/code/game/objects/structures/windoor_assembly.dm
+++ b/code/game/objects/structures/windoor_assembly.dm
@@ -27,13 +27,6 @@ obj/structure/windoor_assembly
var/secure = 0 //Whether or not this creates a secure windoor
var/state = "01" //How far the door assembly has progressed
-/obj/structure/windoor_assembly/proc/update_nearby_tiles(need_rebuild)
- if(!air_master) return 0
-
- air_master.mark_for_update(loc)
-
- return 1
-
obj/structure/windoor_assembly/New(dir=NORTH)
..()
src.ini_dir = src.dir
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index d6f9288d05f..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
@@ -403,14 +403,6 @@ var/global/wcColored
dir = ini_dir
update_nearby_tiles(need_rebuild=1)
-
-//This proc has to do with airgroups and atmos, it has nothing to do with smoothwindows, that's update_nearby_tiles().
-/obj/structure/window/proc/update_nearby_tiles(need_rebuild)
- if(!air_master) return 0
- air_master.mark_for_update(get_turf(src))
-
- return 1
-
//checks if this window is full-tile one
/obj/structure/window/proc/is_fulltile()
if(dir & (dir - 1))
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/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm
index 1aeed58f7df..c250ceca9d0 100644
--- a/code/modules/admin/verbs/mapping.dm
+++ b/code/modules/admin/verbs/mapping.dm
@@ -52,7 +52,7 @@ var/intercom_range_display_status = 0
del(C)
if(camera_range_display_status)
- for(var/obj/machinery/camera/C in cameranet.viewpoints)
+ for(var/obj/machinery/camera/C in cameranet.cameras)
new/obj/effect/debugging/camera_range(C.loc)
feedback_add_details("admin_verb","mCRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -68,7 +68,7 @@ var/intercom_range_display_status = 0
var/list/obj/machinery/camera/CL = list()
- for(var/obj/machinery/camera/C in cameranet.viewpoints)
+ for(var/obj/machinery/camera/C in cameranet.cameras)
CL += C
var/output = {"CAMERA ANOMALIES REPORT
diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm
index fb7906e925c..2137d8b72c6 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/computer3/computers/camera.dm b/code/modules/computer3/computers/camera.dm
index e0d485e1da1..ddf583888fd 100644
--- a/code/modules/computer3/computers/camera.dm
+++ b/code/modules/computer3/computers/camera.dm
@@ -185,12 +185,12 @@
return null
var/list/L = list()
- for(var/obj/machinery/camera/C in cameranet.viewpoints)
+ for(var/obj/machinery/camera/C in cameranet.cameras)
var/list/temp = C.network & key.networks
if(temp.len)
L.Add(C)
- camera_sort(L)
+ cameranet.process_sort()
return L
verify_machine(var/obj/machinery/camera/C,var/datum/file/camnet_key/key = null)
diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm
index 9a3dc92a754..96729f0014c 100644
--- a/code/modules/events/blob.dm
+++ b/code/modules/events/blob.dm
@@ -68,8 +68,7 @@
for (var/mob/living/silicon/ai/aiPlayer in player_list)
if (aiPlayer.client)
- var/law = ""
- aiPlayer.set_zeroth_law(law)
+ aiPlayer.clear_zeroth_law()
aiPlayer << "\red You have detected a change in your laws information:"
- aiPlayer << "Laws Updated: [law]"
+ aiPlayer << "Laws Updated: Zeroth law removed."
..()
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 1fabedb239c..47464bc12e4 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -112,7 +112,7 @@ var/list/ai_list = list()
if (istype(loc, /turf))
verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
- /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message)
+ /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message, /mob/living/silicon/ai/proc/ai_store_location, /mob/living/silicon/ai/proc/ai_goto_location, /mob/living/silicon/ai/proc/ai_remove_location)
if(!safety)//Only used by AIize() to successfully spawn an AI.
if (!B)//If there is no player/brain inside.
@@ -127,7 +127,7 @@ var/list/ai_list = list()
verbs.Remove(,/mob/living/silicon/ai/proc/ai_call_shuttle,/mob/living/silicon/ai/proc/ai_camera_track, \
/mob/living/silicon/ai/proc/ai_camera_list, /mob/living/silicon/ai/proc/ai_network_change, \
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
- /mob/living/silicon/ai/proc/toggle_camera_light,/mob/living/silicon/ai/verb/pick_icon,/mob/living/silicon/ai/proc/control_hud)
+ /mob/living/silicon/ai/proc/toggle_camera_light,/mob/living/silicon/ai/verb/pick_icon,/mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message)
laws = new /datum/ai_laws/alienmov
else
B.brainmob.mind.transfer_to(src)
@@ -406,7 +406,7 @@ var/list/ai_list = list()
unset_machine()
src << browse(null, t1)
if (href_list["switchcamera"])
- switchCamera(locate(href_list["switchcamera"])) in cameranet.viewpoints
+ switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras
if (href_list["showalerts"])
ai_alerts()
//Carn: holopad requests
@@ -584,15 +584,14 @@ var/list/ai_list = list()
if(control_disabled)
src << "Wireless communication is disabled."
return
- var/turf/ai_current_turf = get_turf(src)
- var/ai_Zlevel = ai_current_turf.z
+ var/ai_allowed_Zlevel = list(1,3,5)
var/d
var/area/bot_area
d += "Query network status
"
d += "Name | Status | Location | Control |
"
for (Bot in aibots)
- if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
+ if((Bot.z in ai_allowed_Zlevel) && !Bot.remote_disabled) //Only non-emagged bots on the allowed Z-level are detected!
bot_area = get_area(Bot)
d += "| [Bot.hacked ? "(!) [Bot.name]" : Bot.name] ([Bot.bot_type_name]) | "
//If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all.
@@ -631,8 +630,6 @@ var/list/ai_list = list()
/mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C)
- src.cameraFollow = null
-
if (!C || stat == 2) //C.can_use())
return 0
@@ -706,7 +703,6 @@ var/list/ai_list = list()
set category = "AI Commands"
set name = "Jump To Network"
unset_machine()
- src.cameraFollow = null
var/cameralist[0]
if(usr.stat == 2)
@@ -715,11 +711,11 @@ var/list/ai_list = list()
var/mob/living/silicon/ai/U = usr
- for (var/obj/machinery/camera/C in cameranet.viewpoints)
+ for (var/obj/machinery/camera/C in cameranet.cameras)
if(!C.can_use())
continue
- var/list/tempnetwork = difflist(C.network,RESTRICTED_CAMERA_NETWORKS,1)
+ var/list/tempnetwork = difflist(C.network,restricted_camera_networks,1)
if(tempnetwork.len)
for(var/i in tempnetwork)
cameralist[i] = i
@@ -733,7 +729,7 @@ var/list/ai_list = list()
if(isnull(network))
network = old_network // If nothing is selected
else
- for(var/obj/machinery/camera/C in cameranet.viewpoints)
+ for(var/obj/machinery/camera/C in cameranet.cameras)
if(!C.can_use())
continue
if(network in C.network)
@@ -912,3 +908,52 @@ var/list/ai_list = list()
src << "Accessing Subspace Transceiver control..."
if (src.aiRadio)
src.aiRadio.interact(src)
+
+
+/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target as mob)
+ if(!istype(target)) return
+ spawn(0)
+ if(istype(target, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = target
+ if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
+ src << "Unable to locate an airlock"
+ return
+ if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
+ src << "Unable to locate an airlock"
+ return
+ if(istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja) && !H.head.canremove)
+ src << "Unable to locate an airlock"
+ return
+ if(H.digitalcamo)
+ src << "Unable to locate an airlock"
+ return
+ if (!near_camera(target))
+ src << "Target is not near any active cameras."
+ return
+ var/obj/machinery/door/airlock/tobeopened
+ var/dist = -1
+ for(var/obj/machinery/door/airlock/D in range(3,target))
+ if(!D.density) continue
+ if(dist < 0)
+ dist = get_dist(D, target)
+ //world << dist
+ tobeopened = D
+ else
+ if(dist > get_dist(D, target))
+ dist = get_dist(D, target)
+ //world << dist
+ tobeopened = D
+ //world << "found [tobeopened.name] closer"
+ else
+ //world << "[D.name] not close enough | [get_dist(D, target)] | [dist]"
+ if(tobeopened)
+ switch(alert(src, "Do you want to open \the [tobeopened] for [target]?","Doorknob_v2a.exe","Yes","No"))
+ if("Yes")
+ var/nhref = "src=\ref[tobeopened];aiEnable=7"
+ tobeopened.Topic(nhref, params2list(nhref), tobeopened, 1)
+ src << "\blue You've opened \the [tobeopened] for [target]."
+ if("No")
+ src << "\red You deny the request."
+ else
+ src << "\red You've failed to open an airlock for [target]"
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm b/code/modules/mob/living/silicon/ai/freelook/cameranet.dm
index b0caf3b4a69..584af962874 100644
--- a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/cameranet.dm
@@ -1,25 +1,156 @@
-/datum/visibility_network/cameras
- ChunkType = /datum/visibility_chunk/camera
+// CAMERA NET
+//
+// The datum containing all the chunks.
-/datum/visibility_network/cameras/getViewpointFromMob(var/mob/currentMob)
- var/mob/living/silicon/robot/currentRobot=currentMob
- if(currentRobot)
- return currentRobot.camera
- return FALSE
+var/datum/cameranet/cameranet = new()
-/datum/visibility_network/cameras/validViewpoint(var/viewpoint)
- var/obj/machinery/camera/c = viewpoint
- if (!c)
- return FALSE
- return c.can_use()
+/datum/cameranet
+ // The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Del().
+ var/list/cameras = list()
+ var/cameras_unsorted = 1
+ // The chunks of the map, mapping the areas that the cameras can see.
+ var/list/chunks = list()
+ var/ready = 0
+/datum/cameranet/proc/process_sort()
+ if(cameras_unsorted)
+ cameras = dd_sortedObjectList(cameras)
+ cameras_unsorted = 0
-// adding some indirection so that I don't have to edit a ton of files
-/datum/visibility_network/cameras/proc/addCamera(var/camera)
- return addViewpoint(camera)
+// Checks if a chunk has been Generated in x, y, z.
+/datum/cameranet/proc/chunkGenerated(x, y, z)
+ x &= ~0xf
+ y &= ~0xf
+ var/key = "[x],[y],[z]"
+ return (chunks[key])
-/datum/visibility_network/cameras/proc/removeCamera(var/camera)
- return removeViewpoint(camera)
+// Returns the chunk in the x, y, z.
+// If there is no chunk, it creates a new chunk and returns that.
+/datum/cameranet/proc/getCameraChunk(x, y, z)
+ x &= ~0xf
+ y &= ~0xf
+ var/key = "[x],[y],[z]"
+ if(!chunks[key])
+ chunks[key] = new /datum/camerachunk(null, x, y, z)
-/datum/visibility_network/cameras/proc/checkCameraVis(var/atom/target)
- return checkCanSee(target)
+ return chunks[key]
+
+// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
+
+/datum/cameranet/proc/visibility(mob/aiEye/ai)
+ // 0xf = 15
+ var/x1 = max(0, ai.x - 16) & ~0xf
+ var/y1 = max(0, ai.y - 16) & ~0xf
+ var/x2 = min(world.maxx, ai.x + 16) & ~0xf
+ var/y2 = min(world.maxy, ai.y + 16) & ~0xf
+
+ var/list/visibleChunks = list()
+
+ for(var/x = x1; x <= x2; x += 16)
+ for(var/y = y1; y <= y2; y += 16)
+ visibleChunks += getCameraChunk(x, y, ai.z)
+
+ var/list/remove = ai.visibleCameraChunks - visibleChunks
+ var/list/add = visibleChunks - ai.visibleCameraChunks
+
+ for(var/chunk in remove)
+ var/datum/camerachunk/c = chunk
+ c.remove(ai)
+
+ for(var/chunk in add)
+ var/datum/camerachunk/c = chunk
+ c.add(ai)
+
+// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
+
+/datum/cameranet/proc/updateVisibility(atom/A, var/opacity_check = 1)
+
+ if(!ticker || (opacity_check && !A.opacity))
+ return
+ majorChunkChange(A, 2)
+
+/datum/cameranet/proc/updateChunk(x, y, z)
+ // 0xf = 15
+ if(!chunkGenerated(x, y, z))
+ return
+ var/datum/camerachunk/chunk = getCameraChunk(x, y, z)
+ chunk.hasChanged()
+
+// Removes a camera from a chunk.
+
+/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
+ if(c.can_use())
+ majorChunkChange(c, 0)
+
+// Add a camera to a chunk.
+
+/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
+ if(c.can_use())
+ majorChunkChange(c, 1)
+
+// Used for Cyborg cameras. Since portable cameras can be in ANY chunk.
+
+/datum/cameranet/proc/updatePortableCamera(obj/machinery/camera/c)
+ if(c.can_use())
+ majorChunkChange(c, 1)
+ //else
+ // majorChunkChange(c, 0)
+
+// Never access this proc directly!!!!
+// This will update the chunk and all the surrounding chunks.
+// It will also add the atom to the cameras list if you set the choice to 1.
+// Setting the choice to 0 will remove the camera from the chunks.
+// If you want to update the chunks around an object, without adding/removing a camera, use choice 2.
+
+/datum/cameranet/proc/majorChunkChange(atom/c, var/choice)
+ // 0xf = 15
+ if(!c)
+ return
+
+ var/turf/T = get_turf(c)
+ if(T)
+ var/x1 = max(0, T.x - 8) & ~0xf
+ var/y1 = max(0, T.y - 8) & ~0xf
+ var/x2 = min(world.maxx, T.x + 8) & ~0xf
+ var/y2 = min(world.maxy, T.y + 8) & ~0xf
+
+ //world << "X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]"
+
+ for(var/x = x1; x <= x2; x += 16)
+ for(var/y = y1; y <= y2; y += 16)
+ if(chunkGenerated(x, y, T.z))
+ var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
+ if(choice == 0)
+ // Remove the camera.
+ chunk.cameras -= c
+ else if(choice == 1)
+ // You can't have the same camera in the list twice.
+ chunk.cameras |= c
+ chunk.hasChanged()
+
+// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
+
+/datum/cameranet/proc/checkCameraVis(mob/living/target as mob)
+
+ // 0xf = 15
+ var/turf/position = get_turf(target)
+ return checkTurfVis(position)
+
+/datum/cameranet/proc/checkTurfVis(var/turf/position)
+ var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z)
+ if(chunk)
+ if(chunk.changed)
+ chunk.hasChanged(1) // Update now, no matter if it's visible or not.
+ if(chunk.visibleTurfs[position])
+ return 1
+ return 0
+
+// Debug verb for VVing the chunk that the turf is in.
+/*
+/turf/verb/view_chunk()
+ set src in world
+
+ if(cameranet.chunkGenerated(x, y, z))
+ var/datum/camerachunk/chunk = cameranet.getCameraChunk(x, y, z)
+ usr.client.debug_variables(chunk)
+*/
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/freelook/chunk.dm b/code/modules/mob/living/silicon/ai/freelook/chunk.dm
index ba4e7892f57..fda4ef2f78e 100644
--- a/code/modules/mob/living/silicon/ai/freelook/chunk.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/chunk.dm
@@ -1,23 +1,168 @@
-/datum/visibility_chunk/camera
+#define UPDATE_BUFFER 25 // 2.5 seconds
-/datum/visibility_chunk/camera/validViewpoint(var/viewpoint)
- var/obj/machinery/camera/c = viewpoint
- if(!c)
- return FALSE
- if(!c.can_use())
- return FALSE
- var/turf/point = locate(src.x + 8, src.y + 8, src.z)
- if(get_dist(point, c) > 24)
- return FALSE
- return TRUE
+// CAMERA CHUNK
+//
+// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
+// Allows the AI Eye to stream these chunks and know what it can and cannot see.
+/datum/camerachunk
+ var/list/obscuredTurfs = list()
+ var/list/visibleTurfs = list()
+ var/list/obscured = list()
+ var/list/cameras = list()
+ var/list/turfs = list()
+ var/list/seenby = list()
+ var/visible = 0
+ var/changed = 0
+ var/updating = 0
+ var/x = 0
+ var/y = 0
+ var/z = 0
-/datum/visibility_chunk/camera/getVisibleTurfsForViewpoint(var/viewpoint)
- var/obj/machinery/camera/c = viewpoint
- return c.can_see()
+// Add an AI eye to the chunk, then update if changed.
+/datum/camerachunk/proc/add(mob/aiEye/ai)
+ if(!ai.ai)
+ return
+ ai.visibleCameraChunks += src
+ if(ai.ai.client)
+ ai.ai.client.images += obscured
+ visible++
+ seenby += ai
+ if(changed && !updating)
+ update()
+
+// Remove an AI eye from the chunk, then update if changed.
+
+/datum/camerachunk/proc/remove(mob/aiEye/ai)
+ if(!ai.ai)
+ return
+ ai.visibleCameraChunks -= src
+ if(ai.ai.client)
+ ai.ai.client.images -= obscured
+ seenby -= ai
+ if(visible > 0)
+ visible--
+
+// Called when a chunk has changed. I.E: A wall was deleted.
+
+/datum/camerachunk/proc/visibilityChanged(turf/loc)
+ if(!visibleTurfs[loc])
+ return
+ hasChanged()
+
+// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
+// instead be flagged to update the next time an AI Eye moves near it.
+
+/datum/camerachunk/proc/hasChanged(var/update_now = 0)
+ if(visible || update_now)
+ if(!updating)
+ updating = 1
+ spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
+ update()
+ updating = 0
+ else
+ changed = 1
+
+// The actual updating. It gathers the visible turfs from cameras and puts them into the appropiate lists.
+
+/datum/camerachunk/proc/update()
+
+ set background = 1
+
+ var/list/newVisibleTurfs = list()
+
+ for(var/camera in cameras)
+ var/obj/machinery/camera/c = camera
+
+ if(!c)
+ continue
+
+ if(!c.can_use())
+ continue
+
+ var/turf/point = locate(src.x + 8, src.y + 8, src.z)
+ if(get_dist(point, c) > 24)
+ continue
+
+ for(var/turf/t in c.can_see())
+ newVisibleTurfs[t] = t
+
+ // Removes turf that isn't in turfs.
+ newVisibleTurfs &= turfs
+
+ var/list/visAdded = newVisibleTurfs - visibleTurfs
+ var/list/visRemoved = visibleTurfs - newVisibleTurfs
+
+ visibleTurfs = newVisibleTurfs
+ obscuredTurfs = turfs - newVisibleTurfs
+
+ for(var/turf in visAdded)
+ var/turf/t = turf
+ if(t.obscured)
+ obscured -= t.obscured
+ for(var/eye in seenby)
+ var/mob/aiEye/m = eye
+ if(!m || !m.ai)
+ continue
+ if(m.ai.client)
+ m.ai.client.images -= t.obscured
+
+ for(var/turf in visRemoved)
+ var/turf/t = turf
+ if(obscuredTurfs[t])
+ if(!t.obscured)
+ t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)
+
+ obscured += t.obscured
+ for(var/eye in seenby)
+ var/mob/aiEye/m = eye
+ if(!m || !m.ai)
+ seenby -= m
+ continue
+ if(m.ai.client)
+ m.ai.client.images += t.obscured
+
+// Create a new camera chunk, since the chunks are made as they are needed.
+
+/datum/camerachunk/New(loc, x, y, z)
+
+ // 0xf = 15
+ x &= ~0xf
+ y &= ~0xf
+
+ src.x = x
+ src.y = y
+ src.z = z
-/datum/visibility_chunk/camera/findNearbyViewpoints()
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
if(c.can_use())
- viewpoints += c
+ cameras += c
+
+ for(var/turf/t in range(10, locate(x + 8, y + 8, z)))
+ if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16)
+ turfs[t] = t
+
+ for(var/camera in cameras)
+ var/obj/machinery/camera/c = camera
+ if(!c)
+ continue
+
+ if(!c.can_use())
+ continue
+
+ for(var/turf/t in c.can_see())
+ visibleTurfs[t] = t
+
+ // Removes turf that isn't in turfs.
+ visibleTurfs &= turfs
+
+ obscuredTurfs = turfs - visibleTurfs
+
+ for(var/turf in obscuredTurfs)
+ var/turf/t = turf
+ if(!t.obscured)
+ t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)
+ obscured += t.obscured
+
+#undef UPDATE_BUFFER
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index c2c23b02188..8218bec993e 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -1,13 +1,12 @@
// AI EYE
//
-// A mob that the AI controls to look around the station with.
+// An invisible (no icon) mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
/mob/aiEye
name = "Inactive AI Eye"
- icon = 'icons/mob/AI.dmi'
- icon_state = "eye"
- alpha = 127
+ icon = 'icons/obj/status_display.dmi' // For AI friend secret shh :o
+ var/list/visibleCameraChunks = list()
var/mob/living/silicon/ai/ai = null
density = 0
status_flags = GODMODE // You can't damage it.
@@ -15,20 +14,16 @@
see_in_dark = 7
invisibility = INVISIBILITY_AI_EYE
-/mob/aiEye/New()
- ..()
- visibility_interface = new /datum/visibility_interface/ai_eye(src)
-
// Movement code. Returns 0 to stop air movement from moving it.
/mob/aiEye/Move()
return 0
// Hide popout menu verbs
-/mob/aiEye/examine()
+/mob/aiEye/examine(atom/A as mob|obj|turf in view())
set popup_menu = 0
set src = usr.contents
return 0
-
+
/mob/aiEye/pull()
set popup_menu = 0
set src = usr.contents
@@ -41,11 +36,15 @@
// Use this when setting the aiEye's location.
// It will also stream the chunk that the new loc is in.
+/mob/aiEye/setLoc(var/T, var/cancel_tracking = 1)
-/mob/aiEye/setLoc(var/T)
if(ai)
if(!isturf(ai.loc))
return
+
+ if(cancel_tracking)
+ ai.ai_cancel_tracking()
+
T = get_turf(T)
loc = T
cameranet.visibility(src)
@@ -55,9 +54,12 @@
if(ai.holo)
ai.holo.move_hologram()
+/mob/aiEye/proc/getLoc()
-/mob/aiEye/Move()
- return 0
+ if(ai)
+ if(!isturf(ai.loc) || !ai.client)
+ return
+ return ai.eyeobj.loc
// AI MOVEMENT
@@ -70,7 +72,6 @@
var/acceleration = 1
var/obj/machinery/hologram/holopad/holo = null
-
// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us.
/mob/living/silicon/ai/New()
..()
@@ -79,7 +80,7 @@
spawn(5)
eyeobj.loc = src.loc
-/mob/living/silicon/ai/Destroy()
+/mob/living/silicon/ai/Del()
eyeobj.ai = null
del(eyeobj) // No AI, no Eye
..()
@@ -88,9 +89,7 @@
if(istype(usr, /mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = usr
if(AI.eyeobj && AI.client.eye == AI.eyeobj)
- AI.cameraFollow = null
- if (isturf(src.loc) || isturf(src))
- AI.eyeobj.setLoc(src)
+ AI.eyeobj.setLoc(src)
// This will move the AIEye. It will also cause lights near the eye to light up, if toggled.
// This is handled in the proc below this one.
@@ -114,23 +113,24 @@
else
user.sprint = initial
- user.cameraFollow = null
-
//user.unset_machine() //Uncomment this if it causes problems.
//user.lightNearbyCamera()
// Return to the Core.
-/mob/living/silicon/ai/proc/view_core()
+/mob/living/silicon/ai/proc/core()
+ set category = "AI Commands"
+ set name = "AI Core"
+
+ view_core()
+
+
+/mob/living/silicon/ai/proc/view_core()
current = null
- cameraFollow = null
unset_machine()
- if(src.eyeobj && src.loc)
- src.eyeobj.z = src.z
- src.eyeobj.loc = src.loc
- else
+ if(!src.eyeobj)
src << "ERROR: Eyeobj not found. Creating new eye..."
src.eyeobj = new(src.loc)
src.eyeobj.ai = src
@@ -138,11 +138,11 @@
if(client && client.eye)
client.eye = src
-
- for(var/datum/visibility_chunk/camera/c in eyeobj.visibility_interface.visible_chunks)
+ for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
c.remove(eyeobj)
+ src.eyeobj.setLoc(src)
-/mob/living/silicon/ai/verb/toggle_acceleration()
+/mob/living/silicon/ai/proc/toggle_acceleration()
set category = "AI Commands"
set name = "Toggle Camera Acceleration"
diff --git a/code/modules/mob/living/silicon/ai/freelook/read_me.dm b/code/modules/mob/living/silicon/ai/freelook/read_me.dm
index e71b0903b85..53e68ff1377 100644
--- a/code/modules/mob/living/silicon/ai/freelook/read_me.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/read_me.dm
@@ -20,7 +20,7 @@
HOW IT WORKS
It works by first creating a camera network datum. Inside of this camera network are "chunks" (which will be
- explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Destroy().
+ explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Del().
Next the camera network has chunks. These chunks are a 16x16 tile block of turfs and cameras contained inside the chunk.
These turfs are then sorted out based on what the cameras can and cannot see. If none of the cameras can see the turf, inside
@@ -43,7 +43,7 @@
WHERE IS EVERYTHING?
- cameraNetwork.dm = Everything about the cameraNetwork datum.
+ cameranet.dm = Everything about the cameranet datum.
chunk.dm = Everything about the chunk datum.
eye.dm = Everything about the AI and the AIEye.
updating.dm = Everything about triggers that will update chunks.
diff --git a/code/modules/mob/living/silicon/ai/freelook/update_triggers.dm b/code/modules/mob/living/silicon/ai/freelook/update_triggers.dm
index 775d8864751..9458a768633 100644
--- a/code/modules/mob/living/silicon/ai/freelook/update_triggers.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/update_triggers.dm
@@ -1,3 +1,80 @@
+#define BORG_CAMERA_BUFFER 30
+
+//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
+
+// TURFS
+
+/turf
+ var/image/obscured
+
+/turf/proc/visibilityChanged()
+ if(ticker)
+ cameranet.updateVisibility(src)
+
+/turf/simulated/Del()
+ visibilityChanged()
+ ..()
+
+/turf/simulated/New()
+ ..()
+ visibilityChanged()
+
+
+
+// STRUCTURES
+
+/obj/structure/Del()
+ if(ticker)
+ cameranet.updateVisibility(src)
+ ..()
+
+/obj/structure/New()
+ ..()
+ if(ticker)
+ cameranet.updateVisibility(src)
+
+// EFFECTS
+
+/obj/effect/Del()
+ if(ticker)
+ cameranet.updateVisibility(src)
+ ..()
+
+/obj/effect/New()
+ ..()
+ if(ticker)
+ cameranet.updateVisibility(src)
+
+
+// DOORS
+
+// Simply updates the visibility of the area when it opens/closes/destroyed.
+/obj/machinery/door/update_nearby_tiles(need_rebuild)
+ . = ..(need_rebuild)
+ // Glass door glass = 1
+ // don't check then?
+ if(!glass && cameranet)
+ cameranet.updateVisibility(src, 0)
+
+
+// ROBOT MOVEMENT
+
+// Update the portable camera everytime the Robot moves.
+// This might be laggy, comment it out if there are problems.
+/mob/living/silicon/robot/var/updating = 0
+
+/mob/living/silicon/robot/Move()
+ var/oldLoc = src.loc
+ . = ..()
+ if(.)
+ if(src.camera && src.camera.network.len)
+ if(!updating)
+ updating = 1
+ spawn(BORG_CAMERA_BUFFER)
+ if(oldLoc != src.loc)
+ cameranet.updatePortableCamera(src.camera)
+ updating = 0
+
// CAMERA
// An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not.
@@ -5,23 +82,29 @@
/obj/machinery/camera/deactivate(user as mob, var/choice = 1)
..(user, choice)
if(src.can_use())
- cameranet.addViewpoint(src)
+ cameranet.addCamera(src)
else
src.SetLuminosity(0)
- cameranet.removeViewpoint(src)
+ cameranet.removeCamera(src)
/obj/machinery/camera/New()
..()
- cameranet.viewpoints += src //Camera must be added to global list of all cameras no matter what...
- var/list/open_networks = difflist(network,RESTRICTED_CAMERA_NETWORKS) //...but if all of camera's networks are restricted, it only works for specific camera consoles.
+ //Camera must be added to global list of all cameras no matter what...
+ if(cameranet.cameras_unsorted || !ticker)
+ cameranet.cameras += src
+ cameranet.cameras_unsorted = 1
+ else
+ dd_insertObjectList(cameranet.cameras, src)
+
+ var/list/open_networks = difflist(network,restricted_camera_networks) //...but if all of camera's networks are restricted, it only works for specific camera consoles.
if(open_networks.len) //If there is at least one open network, chunk is available for AI usage.
- cameranet.addViewpoint(src)
+ cameranet.addCamera(src)
/obj/machinery/camera/Del()
- cameranet.viewpoints -= src
- var/list/open_networks = difflist(network,RESTRICTED_CAMERA_NETWORKS)
+ cameranet.cameras -= src
+ var/list/open_networks = difflist(network,restricted_camera_networks)
if(open_networks.len)
- cameranet.removeViewpoint(src)
+ cameranet.removeCamera(src)
..()
#undef BORG_CAMERA_BUFFER
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/freelook/visibility_interface.dm b/code/modules/mob/living/silicon/ai/freelook/visibility_interface.dm
deleted file mode 100644
index b55598c6090..00000000000
--- a/code/modules/mob/living/silicon/ai/freelook/visibility_interface.dm
+++ /dev/null
@@ -1,10 +0,0 @@
-/datum/visibility_interface/ai_eye
- chunk_type = /datum/visibility_chunk/camera
-
-/datum/visibility_interface/ai_eye/getClient()
- var/mob/aiEye/eye = controller
- if (!eye)
- return FALSE
- if (!eye.ai)
- return FALSE
- return eye.ai.client
diff --git a/code/modules/mob/living/silicon/ai/laws.dm b/code/modules/mob/living/silicon/ai/laws.dm
index ab6b19e6190..9d30afc6e4d 100755
--- a/code/modules/mob/living/silicon/ai/laws.dm
+++ b/code/modules/mob/living/silicon/ai/laws.dm
@@ -23,6 +23,10 @@
/mob/living/silicon/ai/proc/set_zeroth_law(var/law, var/law_borg)
src.laws_sanity_check()
src.laws.set_zeroth_law(law, law_borg)
+
+/mob/living/silicon/ai/proc/clear_zeroth_law(var/law_borg)
+ src.laws_sanity_check()
+ src.laws.clear_zeroth_law(law_borg)
/mob/living/silicon/ai/proc/add_inherent_law(var/law)
src.laws_sanity_check()
diff --git a/code/modules/mob/living/silicon/robot/laws.dm b/code/modules/mob/living/silicon/robot/laws.dm
index 84377b6adb4..38267256f4b 100644
--- a/code/modules/mob/living/silicon/robot/laws.dm
+++ b/code/modules/mob/living/silicon/robot/laws.dm
@@ -77,6 +77,10 @@
laws_sanity_check()
laws.set_zeroth_law(law)
+/mob/living/silicon/robot/proc/clear_zeroth_law()
+ laws_sanity_check()
+ laws.clear_zeroth_law()
+
/mob/living/silicon/robot/proc/add_inherent_law(var/law)
laws_sanity_check()
laws.add_inherent_law(law)
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_helpers.dm b/code/modules/mob/mob_helpers.dm
index 0432e4baef6..b652a106824 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -161,6 +161,14 @@ proc/hasorgans(A)
/proc/hsl2rgb(h, s, l)
return
+
+proc/hassensorlevel(A, var/level)
+ var/mob/living/carbon/human/H = A
+ if(istype(H) && istype(H.w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/U = H.w_uniform
+ return U.sensor_mode >= level
+ return 0
+
/proc/check_zone(zone)
diff --git a/code/modules/mob/spirit/cultnet.dm b/code/modules/mob/spirit/cultnet.dm
index df0cd57ff5d..c3f37f8fdd1 100644
--- a/code/modules/mob/spirit/cultnet.dm
+++ b/code/modules/mob/spirit/cultnet.dm
@@ -19,54 +19,6 @@ It reuses a lot of code from the AIEye cameraNetwork. In order to work properly,
if (vp)
return TRUE
return FALSE
-
-
-/datum/visibility_chunk/cult/validViewpoint(var/atom/viewpoint)
- var/turf/point = locate(src.x + 8, src.y + 8, src.z)
- if(get_dist(point, viewpoint) > 24)
- return FALSE
-
- if (isCultRune(viewpoint) || isCultViewpoint(viewpoint))
- return viewpoint:can_use()
- return FALSE
-
-
-/datum/visibility_chunk/cult/getVisibleTurfsForViewpoint(var/viewpoint)
- var/obj/effect/rune/rune = viewpoint
- if (rune)
- return rune.can_see()
- var/obj/cult_viewpoint/cvp = viewpoint
- if (cvp)
- return cvp.can_see()
- return null
-
-
-/datum/visibility_chunk/cult/findNearbyViewpoints()
- for(var/obj/cult_viewpoint/vp in range(16, locate(x + 8, y + 8, z)))
- if(vp.can_use())
- viewpoints += vp
- for(var/obj/effect/rune/rune in range(16, locate(x + 8, y + 8, z)))
- viewpoints += rune
-
-
-/datum/visibility_network/cult
- ChunkType = /datum/visibility_chunk/cult
-
-
-/datum/visibility_network/cult/validViewpoint(var/viewpoint)
- if (isCultRune(viewpoint) || isCultViewpoint(viewpoint))
- return viewpoint:can_use()
- return FALSE
-
-/datum/visibility_network/cult/getViewpointFromMob(var/mob/currentMob)
- for(var/obj/cult_viewpoint/currentView in currentMob)
- return currentView
- return FALSE
-
-
-/datum/visibility_interface/cult
- chunk_type = /datum/visibility_chunk/cult
-
/*
RUNE JUNK
diff --git a/code/modules/mob/spirit/movement.dm b/code/modules/mob/spirit/movement.dm
index bd794b6fd2b..b5ac53fbeae 100644
--- a/code/modules/mob/spirit/movement.dm
+++ b/code/modules/mob/spirit/movement.dm
@@ -52,7 +52,6 @@ mob/spirit/proc/Spirit_Move(direct)
mob/spirit/setLoc(var/T)
T = get_turf(T)
loc = T
- cultNetwork.visibility(src)
mob/spirit/verb/toggle_acceleration()
set category = "Spirit"
diff --git a/code/modules/mob/spirit/spirit.dm b/code/modules/mob/spirit/spirit.dm
index ce7080b744c..c90f0f569b7 100644
--- a/code/modules/mob/spirit/spirit.dm
+++ b/code/modules/mob/spirit/spirit.dm
@@ -38,9 +38,6 @@ mob/spirit/New()
loc = pick(latejoin)
- // hook them to the cult visibility network
- visibility_interface = new /datum/visibility_interface/cult(src)
-
// no nameless spirits
if (!name)
name = "Boogyman"
diff --git a/code/modules/mob/spirit/viewpoint.dm b/code/modules/mob/spirit/viewpoint.dm
index b4bd911ea1c..0cd54451361 100644
--- a/code/modules/mob/spirit/viewpoint.dm
+++ b/code/modules/mob/spirit/viewpoint.dm
@@ -18,9 +18,6 @@ var/obj/cult_viewpoint/list/cult_viewpoints = list()
/obj/cult_viewpoint/New(var/mob/target)
owner = target
//src.loc = owner
- owner.addToVisibilityNetwork(cultNetwork)
- cultNetwork.viewpoints+=src
- cultNetwork.addViewpoint(src)
cult_viewpoints+=src
//handle_missing_mask()
..()
@@ -28,10 +25,7 @@ var/obj/cult_viewpoint/list/cult_viewpoints = list()
/obj/cult_viewpoint/Del()
processing_objects.Remove(src)
- cultNetwork.viewpoints-=src
- cultNetwork.removeViewpoint(src)
cult_viewpoints-=src
- owner.removeFromVisibilityNetwork(cultNetwork)
..()
return
@@ -134,6 +128,8 @@ var/obj/cult_viewpoint/list/cult_viewpoints = list()
/obj/cult_viewpoint/proc/get_display_name()
+ if(istype(src,/obj/effect/rune))
+ return name
if (!owner)
return
if (cult_name)
diff --git a/code/modules/nano/JSON Writer.dm b/code/modules/nano/JSON Writer.dm
index 3cd3520f177..f4c74d35ebb 100644
--- a/code/modules/nano/JSON Writer.dm
+++ b/code/modules/nano/JSON Writer.dm
@@ -1,7 +1,7 @@
json_writer
proc
- WriteObject(list/L)
+ WriteObject(list/L, cached_data = null)
. = "{"
var/i = 1
for(var/k in L)
@@ -9,6 +9,8 @@ json_writer
. += {"\"[k]\":[write(val)]"}
if(i++ < L.len)
. += ","
+ if(cached_data)
+ . = copytext(., 1, lentext(.)) + ",\"cached\":[cached_data]}"
.+= "}"
write(val)
diff --git a/code/modules/nano/_JSON.dm b/code/modules/nano/_JSON.dm
index 5692e643baa..4f70e6e664a 100644
--- a/code/modules/nano/_JSON.dm
+++ b/code/modules/nano/_JSON.dm
@@ -7,6 +7,6 @@ proc
var/static/json_reader/_jsonr = new()
return _jsonr.ReadObject(_jsonr.ScanJson(json))
- list2json(list/L)
+ list2json(list/L, var/cached_data = null)
var/static/json_writer/_jsonw = new()
- return _jsonw.WriteObject(L)
+ return _jsonw.WriteObject(L, cached_data)
diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm
index 54ff6b70b01..01792ad0c3d 100644
--- a/code/modules/nano/nanoui.dm
+++ b/code/modules/nano/nanoui.dm
@@ -58,6 +58,9 @@ nanoui is used to open and update nano browser uis
var/is_auto_updating = 0
// the current status/visibility of the ui
var/status = STATUS_INTERACTIVE
+
+ var/cached_data = null
+
// Only allow users with a certain user.stat to get updates. Defaults to 0 (concious)
var/allowed_user_stat = 0 // -1 = ignore, 0 = alive, 1 = unconcious or alive, 2 = dead concious or alive
@@ -370,7 +373,7 @@ nanoui is used to open and update nano browser uis
template_data_json = list2json(templates)
var/list/send_data = get_send_data(initial_data)
- var/initial_data_json = list2json(send_data)
+ var/initial_data_json = list2json(send_data, cached_data)
var/url_parameters_json = list2json(list("src" = "\ref[src]"))
@@ -450,6 +453,17 @@ nanoui is used to open and update nano browser uis
var/params = "\ref[src]"
winset(user, window_id, "on-close=\"nanoclose [params]\"")
+
+/**
+ * Appends already processed json txt to the list2json proc when setting initial-data and data pushes
+ * Used for data that is fucking huge like manifests and camera lists that doesn't change often.
+ * And we only want to process them when they change.
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/load_cached_data(var/data)
+ cached_data = data
+ return
/**
* Push data to an already open UI window
@@ -464,7 +478,7 @@ nanoui is used to open and update nano browser uis
var/list/send_data = get_send_data(data)
//user << list2json(data) // used for debugging
- user << output(list2params(list(list2json(send_data))),"[window_id].browser:receiveUpdateData")
+ user << output(list2params(list(list2json(send_data,cached_data))),"[window_id].browser:receiveUpdateData")
/**
* This Topic() proc is called whenever a user clicks on a link within a Nano UI
diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm
index 54aac02d952..e0872804ce3 100644
--- a/code/modules/organs/organ_internal.dm
+++ b/code/modules/organs/organ_internal.dm
@@ -96,6 +96,7 @@
P.internal_organs = list()
P.internal_organs += src
H.internal_organs_by_name[name] = src
+ H.internal_organs |= src
owner = H
return
@@ -196,7 +197,7 @@
src.damage += 0.2 * process_accuracy
//Damaged one shares the fun
else
- var/datum/organ/internal/O = pick(owner.internal_organs_by_name)
+ var/datum/organ/internal/O = pick(owner.internal_organs)
if(O)
O.damage += 0.2 * process_accuracy
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/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index f358de8a103..58e883716a0 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -143,7 +143,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/code/setup.dm b/code/setup.dm
index 6e332dd1158..ead10cd6bba 100644
--- a/code/setup.dm
+++ b/code/setup.dm
@@ -798,11 +798,13 @@ var/list/cheartstopper = list("potassium_chloride") //this stops the heart when
#define GETPULSE_HAND 0 //less accurate (hand)
#define GETPULSE_TOOL 1 //more accurate (med scanner, sleeper, etc)
-var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accessed by preexisting terminals. AIs and new terminals can't use them.
+var/list/restricted_camera_networks = list( //Those networks can only be accessed by preexisting terminals. AIs and new terminals can't use them.
"CentCom",
"ERT",
"NukeOps",
"Thunderdome",
+ "UO45",
+ "UO45R",
"Xeno"
)
@@ -940,4 +942,10 @@ var/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF")
#define AUTOLATHE 4 //Uses glass/metal only.
#define CRAFTLATHE 8 //Uses fuck if I know. For use eventually.
#define MECHFAB 16 //Remember, objects utilising this flag should have construction_time and construction_cost vars.
-//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
\ No newline at end of file
+//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
+
+// Suit sensor levels
+#define SUIT_SENSOR_OFF 0
+#define SUIT_SENSOR_BINARY 1
+#define SUIT_SENSOR_VITAL 2
+#define SUIT_SENSOR_TRACKING 3
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/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/RandomZLevels/spacehotel.dmm b/maps/RandomZLevels/spacehotel.dmm
index 95051ed7cf6..ebcd1b49470 100644
--- a/maps/RandomZLevels/spacehotel.dmm
+++ b/maps/RandomZLevels/spacehotel.dmm
@@ -2,7 +2,7 @@
"ab" = (/turf/unsimulated/wall,/area)
"ac" = (/turf/unsimulated/wall,/area/awaymission)
"ad" = (/obj/effect/decal/cleanable/blood/old,/turf/unsimulated/wall,/area/awaymission)
-"ae" = (/obj/machinery/power/apc{step_y = 0},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/unsimulated/wall,/area/awaymission)
+"ae" = (/obj/machinery/power/apc,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/unsimulated/wall,/area/awaymission)
"af" = (/obj/machinery/power/terminal,/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/plating,/area/awaymission)
"ag" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/awaymission)
"ah" = (/obj/item/stack/cable_coil/random,/obj/effect/decal/remains/human,/turf/simulated/floor/plating,/area/awaymission)
diff --git a/maps/RandomZLevels/stationCollision.dmm b/maps/RandomZLevels/stationCollision.dmm
index 89fe6d73a63..d46caef2830 100644
--- a/maps/RandomZLevels/stationCollision.dmm
+++ b/maps/RandomZLevels/stationCollision.dmm
@@ -260,7 +260,7 @@
"eZ" = (/turf/simulated/floor,/area/awaymission/northblock)
"fa" = (/obj/machinery/light/small,/turf/simulated/floor/airless{icon_state = "floorscorched1"},/area/awaymission/northblock)
"fb" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/airless{icon_state = "floorscorched2"},/area/awaymission/northblock)
-"fc" = (/obj/structure/table,/obj/item/weapon/stock_parts/capacitor,/obj/item/weapon/stock_parts/capacitor{pixel_x = -3},/obj/item/weapon/stock_parts/scanning_module{pixel_x = 3; pixel_y = 3},/obj/item/weapon/stock_parts/scanning_module{pixel_y = -3; step_y = 0},/turf/simulated/floor{icon_state = "showroomfloor"},/area/awaymission/research)
+"fc" = (/obj/structure/table,/obj/item/weapon/stock_parts/capacitor,/obj/item/weapon/stock_parts/capacitor{pixel_x = -3},/obj/item/weapon/stock_parts/scanning_module{pixel_x = 3; pixel_y = 3},/obj/item/weapon/stock_parts/scanning_module{pixel_y = -3},/turf/simulated/floor{icon_state = "showroomfloor"},/area/awaymission/research)
"fd" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/floor{icon_state = "showroomfloor"},/area/awaymission/research)
"fe" = (/obj/structure/table,/obj/item/weapon/stock_parts/manipulator,/obj/item/weapon/stock_parts/manipulator{pixel_x = -3; pixel_y = 3},/obj/item/weapon/stock_parts/micro_laser{pixel_x = -3; pixel_y = -3},/obj/item/weapon/stock_parts/micro_laser{pixel_x = 3; pixel_y = 3},/turf/simulated/floor{icon_state = "showroomfloor"},/area/awaymission/research)
"ff" = (/obj/machinery/computer/crew,/turf/simulated/floor{dir = 4; icon_state = "bluecorner"},/area/awaymission/northblock)
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/nano/images/nanomap_z1.png b/nano/images/nanomap_z1.png
index 236f279ea8e..b9b9faacdbf 100644
Binary files a/nano/images/nanomap_z1.png and b/nano/images/nanomap_z1.png differ
diff --git a/nano/templates/canister.tmpl b/nano/templates/canister.tmpl
index e4033eb0164..06dfbd2ae27 100644
--- a/nano/templates/canister.tmpl
+++ b/nano/templates/canister.tmpl
@@ -1,39 +1,11 @@
-Tank Status
-
-
- Tank Label:
-
-
-
{{:data.name}}
{{:helper.link('Relabel', 'pencil', {'relabel' : 1}, data.canLabel ? null : 'disabled')}}
-
-
-
-
-
- Tank Pressure:
-
-
- {{:data.tankPressure}} kPa
-
-
-
-
-
- Port Status:
-
-
- {{:data.portConnected ? 'Connected' : 'Disconnected'}}
-
-
-
-Holding Tank Status
-{{if data.hasHoldingTank}}
+{{if data.menu == 0}}
+ Tank Status
Tank Label:
-
{{:data.holdingTank.name}}
{{:helper.link('Eject', 'eject', {'remove_tank' : 1})}}
+
{{:data.name}}
{{:helper.link('Relabel', 'pencil', {'choice' : 'menu', 'mode_target' : 1}, data.canLabel ? null : 'disabled')}}
@@ -42,42 +14,145 @@
Tank Pressure:
- {{:data.holdingTank.tankPressure}} kPa
+ {{:data.tankPressure}} kPa
+
+
+
+
+
+ Port Status:
+
+
+ {{:data.portConnected ? 'Connected' : 'Disconnected'}}
+
+
+
+ Holding Tank Status
+ {{if data.hasHoldingTank}}
+
+
+ Tank Label:
+
+
+
{{:data.holdingTank.name}}
{{:helper.link('Eject', 'eject', {'remove_tank' : 1})}}
+
+
+
+
+
+ Tank Pressure:
+
+
+ {{:data.holdingTank.tankPressure}} kPa
+
+
+ {{else}}
+ No holding tank inserted.
+
+ {{/if}}
+
+
+ Release Valve Status
+
+
+ Release Pressure:
+
+
+ {{:helper.displayBar(data.releasePressure, data.minReleasePressure, data.maxReleasePressure)}}
+
+ {{:helper.link('-', null, {'pressure_adj' : -1000}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
+ {{:helper.link('-', null, {'pressure_adj' : -100}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
+ {{:helper.link('-', null, {'pressure_adj' : -10}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
+ {{:helper.link('-', null, {'pressure_adj' : -1}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
+
{{:data.releasePressure}} kPa
+ {{:helper.link('+', null, {'pressure_adj' : 1}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
+ {{:helper.link('+', null, {'pressure_adj' : 10}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
+ {{:helper.link('+', null, {'pressure_adj' : 100}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
+ {{:helper.link('+', null, {'pressure_adj' : 1000}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
+
+
+
+
+
+
+ Release Valve:
+
+
+ {{:helper.link('Open', 'unlocked', {'toggle' : 1}, data.valveOpen ? 'selected' : null)}}{{:helper.link('Close', 'locked', {'toggle' : 1}, data.valveOpen ? null : 'selected')}}
{{else}}
- No holding tank inserted.
-
-{{/if}}
-
-
-Release Valve Status
-
+ {{:helper.link('Go back', 'home', {'choice' : 'menu', 'mode_target' : 0}, null)}}
+
Relabel
- Release Pressure:
+ Name:
- {{:helper.displayBar(data.releasePressure, data.minReleasePressure, data.maxReleasePressure)}}
-
- {{:helper.link('-', null, {'pressure_adj' : -1000}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
- {{:helper.link('-', null, {'pressure_adj' : -100}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
- {{:helper.link('-', null, {'pressure_adj' : -10}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
- {{:helper.link('-', null, {'pressure_adj' : -1}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
-
{{:data.releasePressure}} kPa
- {{:helper.link('+', null, {'pressure_adj' : 1}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
- {{:helper.link('+', null, {'pressure_adj' : 10}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
- {{:helper.link('+', null, {'pressure_adj' : 100}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
- {{:helper.link('+', null, {'pressure_adj' : 1000}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
+
{{:data.name}}
{{:helper.link('Rename', 'pencil', {'rename' : 1}, data.canLabel ? null : 'disabled')}}
+
+
+
+
Colors
+
+
+
{{:data.colorContainer.prim.name}}
+ {{for data.colorContainer.prim.options}}
+
+ {{if value.icon == data._color.prim}}
+ {{:helper.link(value.name, '', {'choice' : data.colorContainer.prim.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', 'selected')}}
+ {{else}}
+ {{:helper.link(value.name, '', {'choice' : data.colorContainer.prim.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', null)}}
+ {{/if}}
+
+ {{/for}}
+
+
+
{{:data.colorContainer.sec.name}}
+ {{:helper.link("None", '', {'choice' : data.colorContainer.sec.name, 'icon' : "none"}, data.canLabel ? null : 'disabled', data.colorContainer.sec.anycolor ? null : 'selected')}}
+ {{for data.colorContainer.sec.options}}
+
+ {{if value.icon == data._color.sec}}
+ {{:helper.link(value.name, '', {'choice' : data.colorContainer.sec.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', 'selected')}}
+ {{else}}
+ {{:helper.link(value.name, '', {'choice' : data.colorContainer.sec.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', null)}}
+ {{/if}}
+
+ {{/for}}
+
+
+
{{:data.colorContainer.ter.name}}
+ {{:helper.link("None", '', {'choice' : data.colorContainer.ter.name, 'icon' : "none"}, data.canLabel ? null : 'disabled', data.colorContainer.ter.anycolor ? null : 'selected')}}
+ {{for data.colorContainer.ter.options}}
+
+ {{if value.icon == data._color.ter}}
+ {{:helper.link(value.name, '', {'choice' : data.colorContainer.ter.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', 'selected')}}
+ {{else}}
+ {{:helper.link(value.name, '', {'choice' : data.colorContainer.ter.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', null)}}
+ {{/if}}
+
+ {{/for}}
+
+
+
{{:data.colorContainer.quart.name}}
+ {{:helper.link("None", '', {'choice' : data.colorContainer.quart.name, 'icon' : "none"}, data.canLabel ? null : 'disabled', data.colorContainer.quart.anycolor ? null : 'selected')}}
+ {{for data.colorContainer.quart.options}}
+
+ {{if value.icon == data._color.quart}}
+ {{:helper.link(value.name, '', {'choice' : data.colorContainer.quart.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', 'selected')}}
+ {{else}}
+ {{:helper.link(value.name, '', {'choice' : data.colorContainer.quart.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', null)}}
+ {{/if}}
+
+ {{/for}}
-
-
-
-
- Release Valve:
+
Decals
+
+
Pick and choose:
+
+ {{for data.possibleDecals}}
+ {{:helper.link(value.name, '', {'choice' : 'decals', 'icon' : value.icon}, data.canLabel ? null : 'disabled', value.active ? 'selected' : null)}}
+ {{/for}}
+
-
- {{:helper.link('Open', 'unlocked', {'toggle' : 1}, data.valveOpen ? 'selected' : null)}}{{:helper.link('Close', 'locked', {'toggle' : 1}, data.valveOpen ? null : 'selected')}}
-
-
-
+{{/if}}
\ No newline at end of file
diff --git a/nano/templates/cryo.tmpl b/nano/templates/cryo.tmpl
index e8302b07df9..ab375a5df59 100644
--- a/nano/templates/cryo.tmpl
+++ b/nano/templates/cryo.tmpl
@@ -95,4 +95,12 @@ Used In File(s): \code\game\machinery\cryo.dm
{{:helper.link('Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
+
+
+
+ Auto-eject:
+
+
+ {{:helper.link('On', 'power', {'autoejectOn' : 1}, data.autoeject ? 'selected' : null)}}{{:helper.link('Off', 'close', {'autoejectOff' : 1}, data.autoeject ? null : 'selected')}}
+
\ No newline at end of file
diff --git a/paradise.dme b/paradise.dme
index 9b9c24ac5ad..89e66efe094 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -218,11 +218,6 @@
#include "code\datums\spells\trigger.dm"
#include "code\datums\spells\turf_teleport.dm"
#include "code\datums\spells\wizard.dm"
-#include "code\datums\visibility_networks\chunk.dm"
-#include "code\datums\visibility_networks\dictionary.dm"
-#include "code\datums\visibility_networks\update_triggers.dm"
-#include "code\datums\visibility_networks\visibility_interface.dm"
-#include "code\datums\visibility_networks\visibility_network.dm"
#include "code\datums\wires\airlock.dm"
#include "code\datums\wires\alarm.dm"
#include "code\datums\wires\apc.dm"
@@ -772,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"
@@ -1292,7 +1288,6 @@
#include "code\modules\mob\living\silicon\ai\freelook\eye.dm"
#include "code\modules\mob\living\silicon\ai\freelook\read_me.dm"
#include "code\modules\mob\living\silicon\ai\freelook\update_triggers.dm"
-#include "code\modules\mob\living\silicon\ai\freelook\visibility_interface.dm"
#include "code\modules\mob\living\silicon\decoy\death.dm"
#include "code\modules\mob\living\silicon\decoy\decoy.dm"
#include "code\modules\mob\living\silicon\decoy\life.dm"