diff --git a/code/__defines/map.dm b/code/__defines/map.dm
index be86ee58d6..b6b182d14b 100644
--- a/code/__defines/map.dm
+++ b/code/__defines/map.dm
@@ -7,7 +7,12 @@
#define MAP_LEVEL_EMPTY 0x020 // Empty Z-levels that may be used for various things (currently used by bluespace jump)
#define MAP_LEVEL_CONSOLES 0x040 // Z-levels available to various consoles, such as the crew monitor (when that gets coded in). Defaults to station_levels if unset.
#define MAP_LEVEL_XENOARCH_EXEMPT 0x080 // Z-levels exempt from xenoarch digsite generation.
+<<<<<<< HEAD
#define MAP_LEVEL_VORESPAWN 0x100 // Z-levels players are allowed to late join to via vorish means. Usually non-dangerous locations.
+||||||| parent of ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
+=======
+#define MAP_LEVEL_PERSIST 0x100 // Z-levels where SSpersistence should persist between rounds
+>>>>>>> ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
// Misc map defines.
#define SUBMAP_MAP_EDGE_PAD 8 // Automatically created submaps are forbidden from being this close to the main map's edge. //VOREStation Edit
\ No newline at end of file
diff --git a/code/controllers/subsystems/persistence.dm b/code/controllers/subsystems/persistence.dm
index 8ea9e0b582..1667aa8320 100644
--- a/code/controllers/subsystems/persistence.dm
+++ b/code/controllers/subsystems/persistence.dm
@@ -32,8 +32,7 @@ SUBSYSTEM_DEF(persistence)
if(!A || (A.flags & AREA_FLAG_IS_NOT_PERSISTENT))
return
-// if((!T.z in GLOB.using_map.station_levels) || !initialized)
- if(!(T.z in using_map.station_levels))
+ if(!(T.z in using_map.persist_levels))
return
if(!tracking_values[track_type])
diff --git a/code/modules/food/kitchen/smartfridge.dm b/code/modules/food/kitchen/smartfridge.dm
new file mode 100644
index 0000000000..a6def6bd2b
--- /dev/null
+++ b/code/modules/food/kitchen/smartfridge.dm
@@ -0,0 +1,423 @@
+/* SmartFridge. Much todo
+*/
+/obj/machinery/smartfridge
+ name = "\improper SmartFridge"
+ desc = "For storing all sorts of perishable foods!"
+ icon = 'icons/obj/vending.dmi'
+ icon_state = "fridge_food"
+ var/icon_base = "fridge_food" //Iconstate to base all the broken/deny/etc on
+ var/icon_contents = "food" //Overlay to put on glass to show contents
+ density = 1
+ anchored = 1
+ use_power = USE_POWER_IDLE
+ idle_power_usage = 5
+ active_power_usage = 100
+ flags = NOREACT
+ var/max_n_of_items = 999 // Sorry but the BYOND infinite loop detector doesn't look things over 1000. //VOREStation Edit - Non-global
+ //var/global/max_n_of_items = 999 // Sorry but the BYOND infinite loop detector doesn't look things over 1000.
+ var/list/item_records = list()
+ var/datum/stored_item/currently_vending = null //What we're putting out of the machine.
+ var/seconds_electrified = 0;
+ var/shoot_inventory = 0
+ var/locked = 0
+ var/scan_id = 1
+ var/is_secure = 0
+ var/wrenchable = 0
+ var/datum/wires/smartfridge/wires = null
+
+/obj/machinery/smartfridge/secure
+ is_secure = 1
+ icon_state = "fridge_sci"
+ icon_base = "fridge_sci"
+ icon_contents = "chem"
+
+/obj/machinery/smartfridge/New()
+ ..()
+ if(is_secure)
+ wires = new/datum/wires/smartfridge/secure(src)
+ else
+ wires = new/datum/wires/smartfridge(src)
+
+/obj/machinery/smartfridge/Destroy()
+ qdel(wires)
+ for(var/A in item_records) //Get rid of item records.
+ qdel(A)
+ wires = null
+ return ..()
+
+/obj/machinery/smartfridge/proc/accept_check(var/obj/item/O as obj)
+ if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown/) || istype(O,/obj/item/seeds/))
+ return 1
+ return 0
+
+/obj/machinery/smartfridge/seeds
+ name = "\improper MegaSeed Servitor"
+ desc = "When you need seeds fast!"
+ icon_contents = "chem"
+
+/obj/machinery/smartfridge/seeds/accept_check(var/obj/item/O as obj)
+ if(istype(O,/obj/item/seeds/))
+ return 1
+ return 0
+
+/obj/machinery/smartfridge/secure/extract
+ name = "\improper Biological Sample Storage"
+ desc = "A refrigerated storage unit for xenobiological samples."
+ icon_contents = "slime"
+ req_access = list(access_research)
+
+/obj/machinery/smartfridge/secure/extract/accept_check(var/obj/item/O as obj)
+ if(istype(O, /obj/item/slime_extract))
+ return TRUE
+ if(istype(O, /obj/item/slimepotion))
+ return TRUE
+ return FALSE
+
+/obj/machinery/smartfridge/secure/medbay
+ name = "\improper Refrigerated Medicine Storage"
+ desc = "A refrigerated storage unit for storing medicine and chemicals."
+ req_one_access = list(access_medical,access_chemistry)
+
+/obj/machinery/smartfridge/secure/medbay/accept_check(var/obj/item/O as obj)
+ if(istype(O,/obj/item/weapon/reagent_containers/glass/))
+ return 1
+ if(istype(O,/obj/item/weapon/storage/pill_bottle/))
+ return 1
+ if(istype(O,/obj/item/weapon/reagent_containers/pill/))
+ return 1
+ return 0
+
+/obj/machinery/smartfridge/secure/virology
+ name = "\improper Refrigerated Virus Storage"
+ desc = "A refrigerated storage unit for storing viral material."
+ icon_contents = "drink"
+ req_access = list(access_virology)
+
+/obj/machinery/smartfridge/secure/virology/accept_check(var/obj/item/O as obj)
+ if(istype(O,/obj/item/weapon/reagent_containers/glass/beaker/vial/))
+ return 1
+ if(istype(O,/obj/item/weapon/virusdish/))
+ return 1
+ return 0
+
+/obj/machinery/smartfridge/chemistry //Is this used anywhere? It's not secure.
+ name = "\improper Smart Chemical Storage"
+ desc = "A refrigerated storage unit for medicine and chemical storage."
+ icon_contents = "chem"
+
+/obj/machinery/smartfridge/chemistry/accept_check(var/obj/item/O as obj)
+ if(istype(O,/obj/item/weapon/storage/pill_bottle) || istype(O,/obj/item/weapon/reagent_containers))
+ return 1
+ return 0
+
+/obj/machinery/smartfridge/chemistry/virology //Same
+ name = "\improper Smart Virus Storage"
+ desc = "A refrigerated storage unit for volatile sample storage."
+
+/obj/machinery/smartfridge/drinks
+ name = "\improper Drink Showcase"
+ desc = "A refrigerated storage unit for tasty tasty alcohol."
+ icon_state = "fridge_drinks"
+ icon_base = "fridge_drinks"
+ icon_contents = "drink"
+
+/obj/machinery/smartfridge/drinks/accept_check(var/obj/item/O as obj)
+ if(istype(O,/obj/item/weapon/reagent_containers/glass) || istype(O,/obj/item/weapon/reagent_containers/food/drinks) || istype(O,/obj/item/weapon/reagent_containers/food/condiment))
+ return 1
+
+/obj/machinery/smartfridge/drying_rack
+ name = "\improper Drying Rack"
+ desc = "A machine for drying plants."
+ wrenchable = 1
+ icon_state = "drying_rack"
+ icon_base = "drying_rack"
+
+/obj/machinery/smartfridge/drying_rack/accept_check(var/obj/item/O as obj)
+ if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/))
+ var/obj/item/weapon/reagent_containers/food/snacks/S = O
+ if (S.dried_type)
+ return 1
+
+ if(istype(O, /obj/item/stack/wetleather))
+ return 1
+
+ return 0
+
+/obj/machinery/smartfridge/drying_rack/process()
+ ..()
+ if(stat & (BROKEN|NOPOWER))
+ return
+ if(contents.len)
+ dry()
+ update_icon()
+
+/obj/machinery/smartfridge/drying_rack/update_icon()
+ var/not_working = stat & (BROKEN|NOPOWER)
+ var/hasItems
+ for(var/datum/stored_item/I in item_records)
+ if(I.get_amount())
+ hasItems = 1
+ break
+ if(hasItems)
+ if(not_working)
+ icon_state = "[icon_base]-plant-off"
+ else
+ icon_state = "[icon_base]-plant"
+ else
+ if(not_working)
+ icon_state = "[icon_base]-off"
+ else
+ icon_state = "[icon_base]"
+
+/obj/machinery/smartfridge/drying_rack/proc/dry()
+ for(var/datum/stored_item/I in item_records)
+ for(var/obj/item/weapon/reagent_containers/food/snacks/S in I.instances)
+ if(S.dry) continue
+ if(S.dried_type == S.type)
+ S.dry = 1
+ S.name = "dried [S.name]"
+ S.color = "#AAAAAA"
+ I.instances -= S
+ S.forceMove(get_turf(src))
+ else
+ var/D = S.dried_type
+ new D(get_turf(src))
+ qdel(S)
+ return
+
+ for(var/obj/item/stack/wetleather/WL in I.instances)
+ if(!WL.wetness)
+ if(WL.amount)
+ WL.forceMove(get_turf(src))
+ WL.dry()
+ I.instances -= WL
+ break
+
+ WL.wetness = max(0, WL.wetness - rand(1, 3))
+
+ return
+
+/obj/machinery/smartfridge/process()
+ if(stat & (BROKEN|NOPOWER))
+ return
+ if(src.seconds_electrified > 0)
+ src.seconds_electrified--
+ if(src.shoot_inventory && prob(2))
+ src.throw_item()
+
+/obj/machinery/smartfridge/power_change()
+ var/old_stat = stat
+ ..()
+ if(old_stat != stat)
+ update_icon()
+
+/obj/machinery/smartfridge/update_icon()
+ cut_overlays()
+ if(stat & (BROKEN|NOPOWER))
+ icon_state = "[icon_base]-off"
+ else
+ icon_state = icon_base
+
+ if(is_secure)
+ add_overlay("[icon_base]-sidepanel")
+
+ if(panel_open)
+ add_overlay("[icon_base]-panel")
+
+ var/is_off = ""
+ if(inoperable())
+ is_off = "-off"
+
+ // Fridge contents
+ if(contents) //VOREStation Edit - Some fridges do not have visible contents
+ switch(contents.len)
+ if(0)
+ add_overlay("empty[is_off]")
+ if(1 to 2)
+ add_overlay("[icon_contents]-1[is_off]")
+ if(3 to 5)
+ add_overlay("[icon_contents]-2[is_off]")
+ if(6 to 8)
+ add_overlay("[icon_contents]-3[is_off]")
+ else
+ add_overlay("[icon_contents]-4[is_off]")
+
+ // Fridge top
+ var/image/top = image(icon, "[icon_base]-top")
+ top.pixel_z = 32
+ top.layer = ABOVE_WINDOW_LAYER
+ add_overlay(top)
+
+/*******************
+* Item Adding
+********************/
+
+/obj/machinery/smartfridge/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(O.is_screwdriver())
+ panel_open = !panel_open
+ user.visible_message("[user] [panel_open ? "opens" : "closes"] the maintenance panel of \the [src].", "You [panel_open ? "open" : "close"] the maintenance panel of \the [src].")
+ playsound(src, O.usesound, 50, 1)
+ update_icon()
+ return
+
+ if(wrenchable && default_unfasten_wrench(user, O, 20))
+ return
+
+ if(istype(O, /obj/item/device/multitool) || O.is_wirecutter())
+ if(panel_open)
+ attack_hand(user)
+ return
+
+ if(stat & NOPOWER)
+ to_chat(user, "\The [src] is unpowered and useless.")
+ return
+
+ if(accept_check(O))
+ user.remove_from_mob(O)
+ stock(O)
+ user.visible_message("[user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].")
+
+ else if(istype(O, /obj/item/weapon/storage/bag))
+ var/obj/item/weapon/storage/bag/P = O
+ var/plants_loaded = 0
+ for(var/obj/G in P.contents)
+ if(accept_check(G))
+ P.remove_from_storage(G) //fixes ui bug - Pull Request 5515
+ stock(G)
+ plants_loaded = 1
+ if(plants_loaded)
+ user.visible_message("[user] loads \the [src] with \the [P].", "You load \the [src] with \the [P].")
+ if(P.contents.len > 0)
+ to_chat(user, "Some items are refused.")
+
+ else if(istype(O, /obj/item/weapon/gripper)) // Grippers. ~Mechoid.
+ var/obj/item/weapon/gripper/B = O //B, for Borg.
+ if(!B.wrapped)
+ to_chat(user, "\The [B] is not holding anything.")
+ return
+ else
+ var/B_held = B.wrapped
+ to_chat(user, "You use \the [B] to put \the [B_held] into \the [src].")
+ return
+
+ else
+ to_chat(user, "\The [src] smartly refuses [O].")
+ return 1
+
+/obj/machinery/smartfridge/secure/emag_act(var/remaining_charges, var/mob/user)
+ if(!emagged)
+ emagged = 1
+ locked = -1
+ to_chat(user, "You short out the product lock on [src].")
+ return 1
+
+/obj/machinery/smartfridge/proc/stock(obj/item/O)
+ var/hasRecord = FALSE //Check to see if this passes or not.
+ for(var/datum/stored_item/I in item_records)
+ if((O.type == I.item_path) && (O.name == I.item_name))
+ I.add_product(O)
+ hasRecord = TRUE
+ break
+ if(!hasRecord)
+ var/datum/stored_item/item = new/datum/stored_item(src, O.type, O.name)
+ item.add_product(O)
+ item_records.Add(item)
+ SStgui.update_uis(src)
+
+/obj/machinery/smartfridge/proc/vend(datum/stored_item/I)
+ I.get_product(get_turf(src))
+ SStgui.update_uis(src)
+
+/obj/machinery/smartfridge/attack_ai(mob/user as mob)
+ attack_hand(user)
+
+/obj/machinery/smartfridge/attack_hand(mob/user as mob)
+ if(stat & (NOPOWER|BROKEN))
+ return
+ wires.Interact(user)
+ tgui_interact(user)
+
+/obj/machinery/smartfridge/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "SmartVend", name)
+ ui.set_autoupdate(FALSE)
+ ui.open()
+
+/obj/machinery/smartfridge/tgui_data(mob/user)
+ . = list()
+
+ var/list/items = list()
+ for(var/i=1 to length(item_records))
+ var/datum/stored_item/I = item_records[i]
+ var/count = I.get_amount()
+ if(count > 0)
+ items.Add(list(list("name" = html_encode(capitalize(I.item_name)), "index" = i, "amount" = count)))
+
+ .["contents"] = items
+ .["name"] = name
+ .["locked"] = locked
+ .["secure"] = is_secure
+
+/obj/machinery/smartfridge/tgui_act(action, params)
+ if(..())
+ return TRUE
+
+ add_fingerprint(usr)
+ switch(action)
+ if("Release")
+ var/amount = 0
+ if(params["amount"])
+ amount = params["amount"]
+ else
+ amount = input("How many items?", "How many items would you like to take out?", 1) as num|null
+
+ if(QDELETED(src) || QDELETED(usr) || !usr.Adjacent(src))
+ return FALSE
+
+ var/index = text2num(params["index"])
+ var/datum/stored_item/I = item_records[index]
+ var/count = I.get_amount()
+
+ // Sanity check, there are probably ways to press the button when it shouldn't be possible.
+ if(count > 0)
+ if((count - amount) < 0)
+ amount = count
+ for(var/i = 1 to amount)
+ vend(I)
+
+ return TRUE
+ return FALSE
+
+/obj/machinery/smartfridge/proc/throw_item()
+ var/obj/throw_item = null
+ var/mob/living/target = locate() in view(7,src)
+ if(!target)
+ return 0
+
+ for(var/datum/stored_item/I in item_records)
+ throw_item = I.get_product(get_turf(src))
+ if (!throw_item)
+ continue
+ break
+
+ if(!throw_item)
+ return 0
+ spawn(0)
+ throw_item.throw_at(target,16,3,src)
+ src.visible_message("[src] launches [throw_item.name] at [target.name]!")
+ SStgui.update_uis(src)
+ return 1
+
+/************************
+* Secure SmartFridges
+*************************/
+
+/obj/machinery/smartfridge/secure/tgui_act(action, params)
+ if(stat & (NOPOWER|BROKEN))
+ return TRUE
+ if(usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf)))
+ if(!allowed(usr) && !emagged && locked != -1 && action == "Release")
+ to_chat(usr, "Access denied.")
+ return TRUE
+ return ..()
diff --git a/code/modules/food/kitchen/smartfridge/engineering.dm b/code/modules/food/kitchen/smartfridge/engineering.dm
index 22983611f0..8141ca496d 100644
--- a/code/modules/food/kitchen/smartfridge/engineering.dm
+++ b/code/modules/food/kitchen/smartfridge/engineering.dm
@@ -9,6 +9,9 @@
/obj/machinery/smartfridge/sheets/persistent
persistent = /datum/persistent/storage/smartfridge/sheet_storage
+/obj/machinery/smartfridge/sheets/persistent_lossy
+ persistent = /datum/persistent/storage/smartfridge/sheet_storage/lossy
+
/obj/machinery/smartfridge/sheets/accept_check(var/obj/item/O)
return istype(O, /obj/item/stack/material)
diff --git a/code/modules/food/kitchen/smartfridge/hydroponics.dm b/code/modules/food/kitchen/smartfridge/hydroponics.dm
index ebf706c25e..9b50136d79 100644
--- a/code/modules/food/kitchen/smartfridge/hydroponics.dm
+++ b/code/modules/food/kitchen/smartfridge/hydroponics.dm
@@ -1,5 +1,5 @@
/obj/machinery/smartfridge/produce
- name = "\improper SmartFridge"
+ name = "\improper Smart Produce Storage"
desc = "For storing all sorts of perishable foods!"
icon = 'icons/obj/vending.dmi'
icon_state = "fridge_food"
@@ -9,6 +9,9 @@
/obj/machinery/smartfridge/produce/persistent
persistent = /datum/persistent/storage/smartfridge/produce
+/obj/machinery/smartfridge/produce/persistent_lossy
+ persistent = /datum/persistent/storage/smartfridge/produce/lossy
+
/obj/machinery/smartfridge/produce/accept_check(var/obj/item/O as obj)
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown/) || istype(O,/obj/item/seeds/))
return TRUE
diff --git a/code/modules/persistence/datum/persistence_datum.dm b/code/modules/persistence/datum/persistence_datum.dm
index 8499caef0b..9dc2d7c17c 100644
--- a/code/modules/persistence/datum/persistence_datum.dm
+++ b/code/modules/persistence/datum/persistence_datum.dm
@@ -5,13 +5,9 @@
/datum/persistent
var/name = null
var/filename
- var/tokens_per_line
var/entries_expire_at // Set in rounds, this controls when the item is finally removed permanently regardless if cleaned or not.
var/entries_decay_at // Set in rounds. This controls when item messages start getting scrambled.
var/entry_decay_weight = 0.5
- var/file_entry_split_character = "\t"
- var/file_entry_substitute_character = " "
- var/file_line_split_character = "\n"
var/has_admin_data
/datum/persistent/New()
@@ -20,10 +16,22 @@
/datum/persistent/proc/SetFilename()
if(name)
- filename = "data/persistent/[lowertext(using_map.name)]-[lowertext(name)].txt"
+ filename = "data/persistent/[lowertext(using_map.name)]-[lowertext(name)].json"
if(!isnull(entries_decay_at) && !isnull(entries_expire_at))
entries_decay_at = round(entries_expire_at * entries_decay_at)
+<<<<<<< HEAD
+/datum/persistent/proc/LabelTokens(var/list/tokens)
+ var/list/labelled_tokens = list()
+ labelled_tokens["x"] = text2num(tokens[1])
+ labelled_tokens["y"] = text2num(tokens[2])
+ labelled_tokens["z"] = text2num(tokens[3])
+ labelled_tokens["age"] = text2num(tokens[4])
+ return labelled_tokens
+
+/datum/persistent/proc/GetValidTurf(var/turf/T, var/list/tokens)
+ if(T && CheckTurfContents(T, tokens))
+||||||| parent of ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
// Reads in list of text tokens taken from file, generates labelled list of actual token values
/datum/persistent/proc/LabelTokens(var/list/tokens)
var/list/labelled_tokens = list()
@@ -35,50 +43,62 @@
/datum/persistent/proc/GetValidTurf(var/turf/T, var/list/tokens)
if(T && CheckTurfContents(T, tokens))
+=======
+/datum/persistent/proc/GetValidTurf(var/turf/T, var/list/token)
+ if(T && CheckTurfContents(T, token))
+>>>>>>> ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
return T
-/datum/persistent/proc/CheckTurfContents(var/turf/T, var/list/tokens)
+/datum/persistent/proc/CheckTurfContents(var/turf/T, var/list/token)
return TRUE
-/datum/persistent/proc/CheckTokenSanity(var/list/tokens)
+/datum/persistent/proc/CheckTokenSanity(var/list/token)
return ( \
- !isnull(tokens["x"]) && \
- !isnull(tokens["y"]) && \
- !isnull(tokens["z"]) && \
- !isnull(tokens["age"]) && \
- tokens["age"] <= entries_expire_at \
+ !isnull(token["x"]) && \
+ !isnull(token["y"]) && \
+ !isnull(token["z"]) && \
+ !isnull(token["age"]) && \
+ token["age"] <= entries_expire_at \
)
+<<<<<<< HEAD
+/datum/persistent/proc/CreateEntryInstance(var/turf/creating, var/list/tokens)
+||||||| parent of ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
// Restores saved data to world
/datum/persistent/proc/CreateEntryInstance(var/turf/creating, var/list/tokens)
+=======
+// Restores saved data to world
+/datum/persistent/proc/CreateEntryInstance(var/turf/creating, var/list/token)
+>>>>>>> ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
return
/datum/persistent/proc/ProcessAndApplyTokens(var/list/tokens)
// If it's old enough we start to trim down any textual information and scramble strings.
- if(tokens["message"] && !isnull(entries_decay_at) && !isnull(entry_decay_weight))
- var/_n = tokens["age"]
- var/_message = tokens["message"]
- if(_n >= entries_decay_at)
- var/decayed_message = ""
- for(var/i = 1 to length(_message))
- var/char = copytext(_message, i, i + 1)
- if(prob(round(_n * entry_decay_weight)))
- if(prob(99))
- decayed_message += pick(".",",","-","'","\\","/","\"",":",";")
- else
- decayed_message += char
- _message = decayed_message
- if(length(_message))
- tokens["message"] = _message
- else
- return
+ for(var/list/token in tokens)
+ if(token["message"] && !isnull(entries_decay_at) && !isnull(entry_decay_weight))
+ var/_n = token["age"]
+ var/_message = token["message"]
+ if(_n >= entries_decay_at)
+ var/decayed_message = ""
+ for(var/i = 1 to length(_message))
+ var/char = copytext(_message, i, i + 1)
+ if(prob(round(_n * entry_decay_weight)))
+ if(prob(99))
+ decayed_message += pick(".",",","-","'","\\","/","\"",":",";")
+ else
+ decayed_message += char
+ _message = decayed_message
+ if(length(_message))
+ token["message"] = _message
+ else
+ return
- var/_z = tokens["z"]
- if(_z in using_map.station_levels)
- . = GetValidTurf(locate(tokens["x"], tokens["y"], _z), tokens)
- if(.)
- CreateEntryInstance(., tokens)
+ var/_z = token["z"]
+ if(_z in using_map.station_levels)
+ . = GetValidTurf(locate(token["x"], token["y"], _z), token)
+ if(.)
+ CreateEntryInstance(., token)
/datum/persistent/proc/IsValidEntry(var/atom/entry)
if(!istype(entry))
@@ -98,31 +118,42 @@
/datum/persistent/proc/CompileEntry(var/atom/entry)
var/turf/T = get_turf(entry)
+<<<<<<< HEAD
+ . = list(
+ T.x,
+ T.y,
+ T.z,
+ GetEntryAge(entry)
+||||||| parent of ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
return list(
T.x,
T.y,
T.z,
GetEntryAge(entry)
+=======
+ return list(
+ "x" = T.x,
+ "y" = T.y,
+ "z" = T.z,
+ "age" = GetEntryAge(entry)
+>>>>>>> ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
)
/datum/persistent/proc/Initialize()
if(fexists(filename))
- for(var/entry_line in file2list(filename, file_line_split_character))
- if(!entry_line)
- continue
- var/list/tokens = splittext(entry_line, file_entry_split_character)
- if(LAZYLEN(tokens) < tokens_per_line)
- continue
- tokens = LabelTokens(tokens)
- if(!CheckTokenSanity(tokens))
- continue
- ProcessAndApplyTokens(tokens)
+ var/list/tokens = json_decode(file2text(filename))
+ for(var/list/token in tokens)
+ if(!CheckTokenSanity(token))
+ tokens -= token
+ ProcessAndApplyTokens(tokens)
/datum/persistent/proc/Shutdown()
if(fexists(filename))
fdel(filename)
- var/write_file = file(filename)
+
+ var/list/to_store = list()
for(var/thing in SSpersistence.tracking_values[type])
+<<<<<<< HEAD
if(IsValidEntry(thing))
var/list/entry = CompileEntry(thing)
if(tokens_per_line == PERSISTENCE_VARIABLE_TOKEN_LENGTH || \
@@ -131,14 +162,36 @@
if(istext(entry[i]))
entry[i] = replacetext(entry[i], file_entry_split_character, file_entry_substitute_character)
to_file(write_file, jointext(entry, file_entry_split_character))
+||||||| parent of ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
+ if(IsValidEntry(thing))
+ var/list/entry = CompileEntry(thing)
+ if(tokens_per_line == PERSISTENCE_VARIABLE_TOKEN_LENGTH || \
+ LAZYLEN(entry) == tokens_per_line)
+ for(var/i = 1 to LAZYLEN(entry))
+ if(istext(entry[i]))
+ entry[i] = replacetext(entry[i], file_entry_split_character, file_entry_substitute_character)
+ to_file(write_file, jointext(entry, file_entry_split_character))
+=======
+ if(!IsValidEntry(thing))
+ continue
+ to_store[++to_store.len] = CompileEntry(thing)
+
+ if(to_store.len)
+ to_file(file(filename), json_encode(to_store))
+>>>>>>> ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
/datum/persistent/proc/RemoveValue(var/atom/value)
qdel(value)
/datum/persistent/proc/GetAdminSummary(var/mob/user, var/can_modify)
+ var/list/my_tracks = SSpersistence.tracking_values[type]
+ if(!my_tracks?.len)
+ return
+
. = list("
| [capitalize(name)] |
")
. += "
|
"
- for(var/thing in SSpersistence.tracking_values[type])
+
+ for(var/thing in my_tracks)
. += "[GetAdminDataStringFor(thing, can_modify, user)]
"
. += "
|
"
diff --git a/code/modules/persistence/effects/filth.dm b/code/modules/persistence/effects/filth.dm
index 10b304e18e..166c374c02 100644
--- a/code/modules/persistence/effects/filth.dm
+++ b/code/modules/persistence/effects/filth.dm
@@ -1,26 +1,22 @@
/datum/persistent/filth
name = "filth"
- tokens_per_line = 5
entries_expire_at = 4 // 4 rounds, 24 hours.
-/datum/persistent/filth/LabelTokens(var/list/tokens)
- var/list/labelled_tokens = ..()
- labelled_tokens["path"] = text2path(tokens[LAZYLEN(labelled_tokens)+1])
- return labelled_tokens
-
/datum/persistent/filth/IsValidEntry(var/atom/entry)
. = ..() && entry.invisibility == 0
-/datum/persistent/filth/CheckTokenSanity(var/list/tokens)
- return ..() && ispath(tokens["path"])
+/datum/persistent/filth/CheckTokenSanity(var/list/token)
+ // byond's json implementation is "questionable", and uses types as keys and values without quotes sometimes even though they aren't valid json
+ token["path"] = istext(token["path"]) ? text2path(token["path"]) : token["path"]
+ return ..() && ispath(token["path"])
-/datum/persistent/filth/CheckTurfContents(var/turf/T, var/list/tokens)
- var/_path = tokens["path"]
+/datum/persistent/filth/CheckTurfContents(var/turf/T, var/list/token)
+ var/_path = token["path"]
return (locate(_path) in T) ? FALSE : TRUE
-/datum/persistent/filth/CreateEntryInstance(var/turf/creating, var/list/tokens)
- var/_path = tokens["path"]
- new _path(creating, tokens["age"]+1)
+/datum/persistent/filth/CreateEntryInstance(var/turf/creating, var/list/token)
+ var/_path = token["path"]
+ new _path(creating, token["age"]+1)
/datum/persistent/filth/GetEntryAge(var/atom/entry)
var/obj/effect/decal/cleanable/filth = entry
@@ -32,4 +28,4 @@
/datum/persistent/filth/CompileEntry(var/atom/entry)
. = ..()
- LAZYADD(., "[GetEntryPath(entry)]")
\ No newline at end of file
+ LAZYADDASSOC(., "path", "[GetEntryPath(entry)]")
\ No newline at end of file
diff --git a/code/modules/persistence/effects/graffiti.dm b/code/modules/persistence/effects/graffiti.dm
index 6ca1bbf32f..369f9156b4 100644
--- a/code/modules/persistence/effects/graffiti.dm
+++ b/code/modules/persistence/effects/graffiti.dm
@@ -1,22 +1,14 @@
/datum/persistent/graffiti
name = "graffiti"
- tokens_per_line = 6
entries_expire_at = 4 // This previously was at 50 rounds??? Over 10 days.
has_admin_data = TRUE
-/datum/persistent/graffiti/LabelTokens(var/list/tokens)
- var/list/labelled_tokens = ..()
- var/entries = LAZYLEN(labelled_tokens)
- labelled_tokens["author"] = tokens[entries+1]
- labelled_tokens["message"] = tokens[entries+2]
- return labelled_tokens
-
-/datum/persistent/graffiti/GetValidTurf(var/turf/T, var/list/tokens)
+/datum/persistent/graffiti/GetValidTurf(var/turf/T, var/list/token)
var/turf/checking_turf = ..()
if(istype(checking_turf) && checking_turf.can_engrave())
return checking_turf
-/datum/persistent/graffiti/CheckTurfContents(var/turf/T, var/list/tokens)
+/datum/persistent/graffiti/CheckTurfContents(var/turf/T, var/list/token)
var/too_much_graffiti = 0
for(var/obj/effect/decal/writing/W in .)
too_much_graffiti++
@@ -24,8 +16,10 @@
return FALSE
return TRUE
-/datum/persistent/graffiti/CreateEntryInstance(var/turf/creating, var/list/tokens)
- new /obj/effect/decal/writing(creating, tokens["age"]+1, tokens["message"], tokens["author"])
+/datum/persistent/graffiti/CreateEntryInstance(var/turf/creating, var/list/token)
+ var/obj/effect/decal/writing/inst = new /obj/effect/decal/writing(creating, token["age"]+1, token["message"], token["author"])
+ if(token["icon_state"])
+ inst.icon_state = token["icon_state"]
/datum/persistent/graffiti/IsValidEntry(var/atom/entry)
. = ..()
@@ -40,8 +34,9 @@
/datum/persistent/graffiti/CompileEntry(var/atom/entry, var/write_file)
. = ..()
var/obj/effect/decal/writing/save_graffiti = entry
- LAZYADD(., "[save_graffiti.author ? save_graffiti.author : "unknown"]")
- LAZYADD(., "[save_graffiti.message]")
+ LAZYADDASSOC(., "author", "[save_graffiti.author ? save_graffiti.author : "unknown"]")
+ LAZYADDASSOC(., "message", "[save_graffiti.message]")
+ LAZYADDASSOC(., "icon_state", "[save_graffiti.icon_state]")
/datum/persistent/graffiti/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user)
var/obj/effect/decal/writing/save_graffiti = thing
diff --git a/code/modules/persistence/effects/paper.dm b/code/modules/persistence/effects/paper.dm
index fe2ef81368..95968274eb 100644
--- a/code/modules/persistence/effects/paper.dm
+++ b/code/modules/persistence/effects/paper.dm
@@ -1,32 +1,24 @@
/datum/persistent/paper
name = "paper"
- tokens_per_line = 7
entries_expire_at = 50
has_admin_data = TRUE
var/paper_type = /obj/item/weapon/paper
var/requires_noticeboard = TRUE
-/datum/persistent/paper/LabelTokens(var/list/tokens)
- var/list/labelled_tokens = ..()
- var/entries = LAZYLEN(labelled_tokens)
- labelled_tokens["author"] = tokens[entries+1]
- labelled_tokens["message"] = tokens[entries+2]
- labelled_tokens["title"] = tokens[entries+3]
- return labelled_tokens
-
-/datum/persistent/paper/CheckTurfContents(var/turf/T, var/list/tokens)
+/datum/persistent/paper/CheckTurfContents(var/turf/T, var/list/token)
if(requires_noticeboard && !(locate(/obj/structure/noticeboard) in T))
new /obj/structure/noticeboard(T)
. = ..()
-/datum/persistent/paper/CreateEntryInstance(var/turf/creating, var/list/tokens)
+/datum/persistent/paper/CreateEntryInstance(var/turf/creating, var/list/token)
var/obj/structure/noticeboard/board = locate() in creating
if(requires_noticeboard && LAZYLEN(board.notices) >= board.max_notices)
return
var/obj/item/weapon/paper/paper = new paper_type(creating)
- paper.info = tokens["message"]
- paper.name = tokens["title"]
- paper.last_modified_ckey = tokens["author"]
+ paper.info = token["message"]
+ paper.name = token["title"]
+ paper.last_modified_ckey = token["author"]
+ paper.age = token["age"]+1
if(requires_noticeboard)
board.add_paper(paper)
if(!paper.was_maploaded) // If we were created/loaded when the map was made, skip us!
@@ -40,9 +32,9 @@
/datum/persistent/paper/CompileEntry(var/atom/entry, var/write_file)
. = ..()
var/obj/item/weapon/paper/paper = entry
- LAZYADD(., "[paper.last_modified_ckey ? paper.last_modified_ckey : "unknown"]")
- LAZYADD(., "[paper.info]")
- LAZYADD(., "[paper.name]")
+ LAZYADDASSOC(., "author", "[paper.last_modified_ckey ? paper.last_modified_ckey : "unknown"]")
+ LAZYADDASSOC(., "message", "[paper.info]")
+ LAZYADDASSOC(., "name", "[paper.name]")
/datum/persistent/paper/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user)
var/obj/item/weapon/paper/paper = thing
diff --git a/code/modules/persistence/effects/paper_sticky.dm b/code/modules/persistence/effects/paper_sticky.dm
index 1871eb4a03..08fb905009 100644
--- a/code/modules/persistence/effects/paper_sticky.dm
+++ b/code/modules/persistence/effects/paper_sticky.dm
@@ -2,27 +2,22 @@
name = "stickynotes"
paper_type = /obj/item/weapon/paper/sticky
requires_noticeboard = FALSE
- tokens_per_line = 10
-/datum/persistent/paper/sticky/LabelTokens(var/list/tokens)
- var/list/labelled_tokens = ..()
- var/entries = LAZYLEN(labelled_tokens)
- labelled_tokens["offset_x"] = tokens[entries+1]
- labelled_tokens["offset_y"] = tokens[entries+2]
- labelled_tokens["color"] = tokens[entries+3]
- return labelled_tokens
-
-/datum/persistent/paper/sticky/CreateEntryInstance(var/turf/creating, var/list/tokens)
+/datum/persistent/paper/sticky/CreateEntryInstance(var/turf/creating, var/list/token)
var/atom/paper = ..()
if(paper)
- paper.pixel_x = text2num(tokens["offset_x"])
- paper.pixel_y = text2num(tokens["offset_y"])
- paper.color = tokens["color"]
+ if(prob(90))
+ paper.pixel_x = token["offset_x"]
+ paper.pixel_y = token["offset_y"]
+ else
+ paper.pixel_x = rand(-5,5)
+ paper.pixel_y = rand(-5,5)
+ paper.color = token["color"]
return paper
/datum/persistent/paper/sticky/CompileEntry(var/atom/entry, var/write_file)
. = ..()
var/obj/item/weapon/paper/sticky/paper = entry
- LAZYADD(., "[paper.pixel_x]")
- LAZYADD(., "[paper.pixel_y]")
- LAZYADD(., "[paper.color]")
\ No newline at end of file
+ LAZYADDASSOC(., "offset_x", paper.pixel_x)
+ LAZYADDASSOC(., "offset_y", paper.pixel_y)
+ LAZYADDASSOC(., "color", paper.color)
\ No newline at end of file
diff --git a/code/modules/persistence/persistence.dm b/code/modules/persistence/serialize.dm
similarity index 100%
rename from code/modules/persistence/persistence.dm
rename to code/modules/persistence/serialize.dm
diff --git a/code/modules/persistence/storage/smartfridge.dm b/code/modules/persistence/storage/smartfridge.dm
index 0b2eee0ca1..0584ab9e79 100644
--- a/code/modules/persistence/storage/smartfridge.dm
+++ b/code/modules/persistence/storage/smartfridge.dm
@@ -6,9 +6,9 @@
for(var/datum/stored_item/I in entry.item_records)
.[I.item_path] = I.get_amount()
-/datum/persistent/storage/smartfridge/CreateEntryInstance(var/turf/creating, var/list/tokens)
+/datum/persistent/storage/smartfridge/CreateEntryInstance(var/turf/creating, var/list/token)
var/obj/machinery/smartfridge/S = find_specific_instance(creating)
- var/list/L = generate_items(tokens["items"])
+ var/list/L = generate_items(token["items"])
for(var/atom/A in L)
if(S.accept_check(A))
S.stock(A)
@@ -20,50 +20,64 @@
/datum/persistent/storage/smartfridge/sheet_storage
- name = "sheet_storage"
+ name = "sheet storage"
max_storage = 50
store_per_type = TRUE
target_type = /obj/machinery/smartfridge/sheets
+ var/stacks_go_missing = FALSE // Variable rate depletion of stacks inter-round
+
+/datum/persistent/storage/smartfridge/sheet_storage/lossy
+ name = "sheet storage lossy"
+ max_storage = 250
+ stacks_go_missing = TRUE
+
/datum/persistent/storage/smartfridge/sheet_storage/generate_items(var/list/L)
. = list()
for(var/obj/item/stack/material/S as anything in L)
- if(!ispath(S, /obj/item/stack/material))
+ var/real_path = istext(S) ? text2path(S) : S
+ if(!ispath(real_path, /obj/item/stack/material))
log_debug("Warning: Sheet_storage persistent datum tried to create [S]")
continue
- var/count = L[S]
- while(count > 0)
- S = new S
- S.amount = min(count, S.get_max_amount())
- count -= S.get_amount()
- . += S
+ // Skip entire stack if we hit the chance
+ if(prob(go_missing_chance))
+ continue
+ var/count = L[S]
+
+ var/obj/item/stack/material/inst = real_path
+ var/max_amount = initial(inst.max_amount)
+
+ // Delete some stacks if we want
+ if(stacks_go_missing)
+ var/fuzzy = rand(-5,5)
+ switch(count / max_amount)
+ if(0 to 1)
+ count -= 10+fuzzy // 1 stack or less, lose 10
+ if(1 to 10)
+ count -= max_amount+fuzzy // 1 to 10 stacks, lose a stack
+ if(10 to INFINITY)
+ count -= max_amount*3+fuzzy // 10+ stacks, lose 3 stacks
+ if(count <= 0)
+ continue
+
+ while(count > 0)
+ inst = new real_path
+ inst.amount = min(count, max_amount)
+ count -= inst.get_amount()
+ . += inst
/datum/persistent/storage/smartfridge/produce
- name = "fruit_storage"
+ name = "fruit storage"
max_storage = 50
store_per_type = FALSE
target_type = /obj/machinery/smartfridge/produce
-/datum/persistent/storage/smartfridge/produce/assemble_token(var/T)
- var/list/subtok = splittext(T, " ")
- if(subtok.len != 2)
- return null
-
- if(!istype(SSplants)) // No seed controller means the fruit will come out all wonky if at all
- return null
-
- subtok[2] = text2num(subtok[2])
-
- // Ensure we've found a token describing the quantity of a path
- if(subtok.len != 2 || \
- !istype(SSplants.seeds[subtok[1]], /datum/seed) || \
- !isnum(subtok[2]))
- return null
-
- return subtok
+/datum/persistent/storage/smartfridge/produce/lossy
+ name = "fruit storage lossy"
+ go_missing_chance = 12.5 // 10% loss between rounds
/datum/persistent/storage/smartfridge/produce/create_item(var/seedtype)
return new /obj/item/weapon/reagent_containers/food/snacks/grown(null, seedtype) // Smartfridge will be stock()ed with it, loc is unimportant
@@ -74,6 +88,8 @@
. = list()
for(var/datum/stored_item/I in entry.item_records)
+ if(prob(go_missing_chance))
+ continue
if(LAZYLEN(I.instances))
var/obj/item/weapon/reagent_containers/food/snacks/grown/G = I.instances[1]
if(!istype(G))
diff --git a/code/modules/persistence/storage/storage.dm b/code/modules/persistence/storage/storage.dm
index 9ad9531cbc..58b23a6ce9 100644
--- a/code/modules/persistence/storage/storage.dm
+++ b/code/modules/persistence/storage/storage.dm
@@ -1,40 +1,23 @@
/datum/persistent/storage
+ name = "storage"
entries_expire_at = 1
+ has_admin_data = TRUE
+
+ // Don't use these for storage persistence. If someone takes some sheets out and puts them back in mixed in with
+ // new sheets, how do you know the age of the stack? If you want sheets to 'decay', see go_missing_chance
entries_decay_at = 0
entry_decay_weight = 0
- tokens_per_line = PERSISTENCE_VARIABLE_TOKEN_LENGTH
-
+ // // // //
+
var/max_storage = 0
var/store_per_type = FALSE // If true, will store up to max_storage for each type stored
var/target_type = null // Path of the thing that this expects to put stuff into
+ var/go_missing_chance = 0 // Chance an item will fail to be spawned in from persistence and need to be restocked
+
/datum/persistent/storage/SetFilename()
if(name)
- filename = "data/persistent/storage/[lowertext(using_map.name)]-[lowertext(name)].txt"
-
-/datum/persistent/storage/LabelTokens(var/list/tokens)
- . = ..()
- .["items"] = list()
- for(var/T in tokens)
- var/list/L = assemble_token(T)
- if(LAZYLEN(L))
- .["items"][L[1]] = text2num(L[2])
-
-/datum/persistent/storage/proc/assemble_token(var/T)
- var/list/subtok = splittext(T, " ")
- if(subtok.len != 2)
- return null
-
- subtok[1] = text2path(subtok[1])
- subtok[2] = text2num( subtok[2])
-
- // Ensure we've found a token describing the quantity of a path
- if(subtok.len != 2 || \
- !ispath(subtok[1]) || \
- !isnum(subtok[2]))
- return null
-
- return subtok
+ filename = "data/persistent/storage/[lowertext(using_map.name)]-[lowertext(name)].json"
/datum/persistent/storage/IsValidEntry(var/atom/entry)
return ..() && istype(entry, target_type)
@@ -52,9 +35,8 @@
if(!store_per_type)
stored = max(stored - item_list[item], 0)
- for(var/item in storage_list)
- . += "[item] [storage_list[item]]"
-
+ LAZYADDASSOC(., "items", storage_list)
+
// Usage: returns list with structure:
// list(
// [type1] = [stored_quantity],
@@ -66,16 +48,27 @@
/datum/persistent/storage/proc/find_specific_instance(var/turf/T)
return locate(target_type) in T
-/datum/persistent/storage/CheckTurfContents(var/turf/T, var/list/tokens)
+/datum/persistent/storage/CheckTurfContents(var/turf/T, var/list/token)
return istype(find_specific_instance(T), target_type)
/datum/persistent/storage/proc/generate_items(var/list/L)
. = list()
for(var/path in L)
+ // byond's json implementation is "questionable", and uses types as keys and values without quotes sometimes even though they aren't valid json
+ var/real_path = istext(path) ? text2path(path) : path
for(var/i in 1 to L[path])
- var/atom/A = create_item(path)
+ if(prob(go_missing_chance))
+ continue
+ var/atom/A = create_item(real_path)
if(!QDELETED(A))
. += A
/datum/persistent/storage/proc/create_item(var/path)
- return new path()
\ No newline at end of file
+ return new path()
+
+/datum/persistent/storage/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user)
+ var/atom/T = thing
+ if(!istype(T))
+ return "| "
+ else
+ . = " | [T.name] | [T.x],[T.y],[T.z] | "
diff --git a/maps/offmap_vr/talon/talon_v2.dmm b/maps/offmap_vr/talon/talon_v2.dmm
index 1f5fdef65c..bf5637ebb9 100644
--- a/maps/offmap_vr/talon/talon_v2.dmm
+++ b/maps/offmap_vr/talon/talon_v2.dmm
@@ -1918,6 +1918,18 @@
/obj/structure/closet/walllocker_double/hydrant/west,
/turf/simulated/floor/tiled/techmaint,
/area/talon_v2/secure_storage)
+"fk" = (
+/obj/structure/railing/grey{
+ dir = 1
+ },
+/obj/structure/window/reinforced{
+ dir = 1
+ },
+/obj/machinery/smartfridge/sheets/persistent_lossy{
+ layer = 3.3
+ },
+/turf/simulated/floor/tiled/techfloor,
+/area/talon_v2/refining)
"fm" = (
/obj/machinery/door/airlock/glass_external{
req_one_access = list(301)
@@ -26583,7 +26595,7 @@ ca
rj
fW
jS
-tX
+fk
VS
mQ
ZR
diff --git a/maps/tether/submaps/_tether_submaps.dm b/maps/tether/submaps/_tether_submaps.dm
index 38d43844ce..0980436c8b 100644
--- a/maps/tether/submaps/_tether_submaps.dm
+++ b/maps/tether/submaps/_tether_submaps.dm
@@ -553,6 +553,6 @@
/datum/map_z_level/tether_lateload/talon_v2
name = "Talon"
- flags = MAP_LEVEL_PLAYER
+ flags = MAP_LEVEL_PLAYER|MAP_LEVEL_PERSIST
base_turf = /turf/space
z = Z_LEVEL_OFFMAP1
\ No newline at end of file
diff --git a/maps/tether/tether-03-surface3.dmm b/maps/tether/tether-03-surface3.dmm
index 3212a18e84..263da6150f 100644
--- a/maps/tether/tether-03-surface3.dmm
+++ b/maps/tether/tether-03-surface3.dmm
@@ -272518,13 +272518,13 @@ aaa
/turf/simulated/floor/tiled,
/area/tether/surfacebase/surface_three_hall)
"aDX" = (
-/obj/machinery/smartfridge,
/obj/effect/floor_decal/borderfloor{
dir = 1
},
/obj/effect/floor_decal/corner/lime/border{
dir = 1
},
+/obj/machinery/smartfridge/produce/persistent_lossy,
/turf/simulated/floor/tiled,
/area/tether/surfacebase/botanystorage)
"aDY" = (
diff --git a/maps/tether/tether-07-station3.dmm b/maps/tether/tether-07-station3.dmm
index f40c8549d0..0cd00a8eec 100644
--- a/maps/tether/tether-07-station3.dmm
+++ b/maps/tether/tether-07-station3.dmm
@@ -19037,7 +19037,6 @@
/turf/simulated/floor,
/area/maintenance/station/ai)
"aSj" = (
-/obj/structure/closet/emcloset,
/obj/machinery/atmospherics/unary/vent_pump/on{
dir = 8
},
@@ -19510,6 +19509,7 @@
/obj/machinery/atmospherics/unary/vent_scrubber/on{
dir = 8
},
+/obj/structure/closet/emcloset,
/turf/simulated/floor/tiled,
/area/quartermaster/belterdock)
"aTA" = (
@@ -23196,6 +23196,10 @@
},
/turf/simulated/floor/tiled/eris/dark/techfloor,
/area/shuttle/medivac/engines)
+"kPM" = (
+/obj/machinery/smartfridge/sheets/persistent_lossy,
+/turf/simulated/wall,
+/area/quartermaster/belterdock)
"kPW" = (
/obj/machinery/door/blast/regular{
dir = 4;
@@ -38495,7 +38499,7 @@ aHB
aMz
aBU
aBU
-aQG
+kPM
aSj
aOu
aOL
diff --git a/maps/tether/tether_areas.dm b/maps/tether/tether_areas.dm
index 8f53b49f8b..ded5e8110f 100644
--- a/maps/tether/tether_areas.dm
+++ b/maps/tether/tether_areas.dm
@@ -698,6 +698,7 @@
name = "\improper South Maintenance"
/area/maintenance/lower/trash_pit
name = "\improper Trash Pit"
+ flags = RAD_SHIELDED|AREA_FLAG_IS_NOT_PERSISTENT
/area/maintenance/lower/solars
name = "\improper Solars Maintenance"
/area/maintenance/lower/mining_eva
diff --git a/maps/tether/tether_defines.dm b/maps/tether/tether_defines.dm
index 27b7b41daf..efb3f626ab 100644
--- a/maps/tether/tether_defines.dm
+++ b/maps/tether/tether_defines.dm
@@ -291,14 +291,14 @@
// We have a bunch of stuff common to the station z levels
/datum/map_z_level/tether/station
- flags = MAP_LEVEL_STATION|MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_CONSOLES|MAP_LEVEL_XENOARCH_EXEMPT
+ flags = MAP_LEVEL_STATION|MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_CONSOLES|MAP_LEVEL_XENOARCH_EXEMPT|MAP_LEVEL_PERSIST
holomap_legend_x = 220
holomap_legend_y = 160
/datum/map_z_level/tether/station/surface_low
z = Z_LEVEL_SURFACE_LOW
name = "Surface 1"
- flags = MAP_LEVEL_STATION|MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_CONSOLES|MAP_LEVEL_SEALED|MAP_LEVEL_XENOARCH_EXEMPT
+ flags = MAP_LEVEL_STATION|MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_CONSOLES|MAP_LEVEL_SEALED|MAP_LEVEL_XENOARCH_EXEMPT|MAP_LEVEL_PERSIST
base_turf = /turf/simulated/floor/outdoors/rocks/virgo3b
holomap_offset_x = TETHER_HOLOMAP_MARGIN_X
holomap_offset_y = TETHER_HOLOMAP_MARGIN_Y + TETHER_MAP_SIZE*0
@@ -306,7 +306,7 @@
/datum/map_z_level/tether/station/surface_mid
z = Z_LEVEL_SURFACE_MID
name = "Surface 2"
- flags = MAP_LEVEL_STATION|MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_CONSOLES|MAP_LEVEL_SEALED|MAP_LEVEL_XENOARCH_EXEMPT
+ flags = MAP_LEVEL_STATION|MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_CONSOLES|MAP_LEVEL_SEALED|MAP_LEVEL_XENOARCH_EXEMPT|MAP_LEVEL_PERSIST
base_turf = /turf/simulated/open
holomap_offset_x = TETHER_HOLOMAP_MARGIN_X
holomap_offset_y = TETHER_HOLOMAP_MARGIN_Y + TETHER_MAP_SIZE*1
@@ -314,7 +314,7 @@
/datum/map_z_level/tether/station/surface_high
z = Z_LEVEL_SURFACE_HIGH
name = "Surface 3"
- flags = MAP_LEVEL_STATION|MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_CONSOLES|MAP_LEVEL_SEALED|MAP_LEVEL_XENOARCH_EXEMPT
+ flags = MAP_LEVEL_STATION|MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_CONSOLES|MAP_LEVEL_SEALED|MAP_LEVEL_XENOARCH_EXEMPT|MAP_LEVEL_PERSIST
base_turf = /turf/simulated/open
holomap_offset_x = TETHER_HOLOMAP_MARGIN_X
holomap_offset_y = TETHER_HOLOMAP_MARGIN_Y + TETHER_MAP_SIZE*2
@@ -351,11 +351,11 @@
/datum/map_z_level/tether/mine
z = Z_LEVEL_SURFACE_MINE
name = "Mining Outpost"
- flags = MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_SEALED
+ flags = MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_SEALED|MAP_LEVEL_PERSIST
base_turf = /turf/simulated/floor/outdoors/rocks/virgo3b
/datum/map_z_level/tether/solars
z = Z_LEVEL_SOLARS
name = "Solar Field"
- flags = MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_SEALED
+ flags = MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_SEALED|MAP_LEVEL_PERSIST
base_turf = /turf/simulated/floor/outdoors/rocks/virgo3b
diff --git a/maps/~map_system/maps.dm b/maps/~map_system/maps.dm
index 0ed8fc4b18..6e86eb8aa3 100644
--- a/maps/~map_system/maps.dm
+++ b/maps/~map_system/maps.dm
@@ -33,6 +33,7 @@ var/list/all_maps = list()
var/static/list/player_levels = list() // Z-levels a character can typically reach
var/static/list/sealed_levels = list() // Z-levels that don't allow random transit at edge
var/static/list/xenoarch_exempt_levels = list() //Z-levels exempt from xenoarch finds and digsites spawning.
+ var/static/list/persist_levels = list() // Z-levels where SSpersistence should persist between rounds. Defaults to station_levels if unset.
var/static/list/empty_levels = null // Empty Z-levels that may be used for various things (currently used by bluespace jump)
var/static/list/vorespawn_levels = list() //Z-levels where players are allowed to vore latejoin to.
// End Static Lists
@@ -138,8 +139,10 @@ var/list/all_maps = list()
if(zlevel_datum_type)
for(var/type in subtypesof(zlevel_datum_type))
new type(src)
- if(!map_levels)
+ if(!map_levels?.len)
map_levels = station_levels.Copy()
+ if(!persist_levels?.len)
+ persist_levels = station_levels.Copy()
if(!allowed_jobs || !allowed_jobs.len)
allowed_jobs = subtypesof(/datum/job)
if(default_skybox) //Type was specified
@@ -298,7 +301,12 @@ var/list/all_maps = list()
if(flags & MAP_LEVEL_PLAYER) map.player_levels += z
if(flags & MAP_LEVEL_SEALED) map.sealed_levels += z
if(flags & MAP_LEVEL_XENOARCH_EXEMPT) map.xenoarch_exempt_levels += z
+<<<<<<< HEAD
if(flags & MAP_LEVEL_VORESPAWN) map.vorespawn_levels += z
+||||||| parent of ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
+=======
+ if(flags & MAP_LEVEL_PERSIST) map.persist_levels += z
+>>>>>>> ba346f5f63... Merge pull request #10325 from VOREStation/Arokha/persistsheets
if(flags & MAP_LEVEL_EMPTY)
if(!map.empty_levels) map.empty_levels = list()
map.empty_levels += z
diff --git a/vorestation.dme b/vorestation.dme
index b2cf2c482d..29b2c90c04 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -3532,6 +3532,7 @@
#include "code\modules\persistence\filth.dm"
#include "code\modules\persistence\graffiti.dm"
#include "code\modules\persistence\noticeboard.dm"
+<<<<<<< HEAD
#include "code\modules\persistence\noticeboard_yw.dm"
#include "code\modules\persistence\persistence.dm"
#include "code\modules\persistence\datum\persistence_datum.dm"
| |