Files
Yogstation/code/controllers/subsystem/persistence.dm
Ling a6d7e3fd15 TGUI Preferences Menu + total rewrite of the preferences backend (#17381)
* TGUI Preferences Menu + total rewrite of the preferences backend (#17368)

* It compiles

* It opens

* Sync 1

* Add asset caching

* Sync 2

* It opens without dev now

* Update a few packages

* Sync 3

* Sync 4

keybind fix

* start of dehardcoded species

* Small fixes

* Add more individual preferences

* ASS sync

* Automatic changelog generation #17368 [ci skip]

* AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

* e

* Fix some TS stuff

* Sort quirks starting from good

* Fix skin tone selector

* Jamie Fixes

* Update moth.dm

* Fix latejoin menu + tweaks

* Some fixes

* Finally fix job selection

* e

* Ling

* MORE

* config

* Convert pref: ooccolor

* Convert pref: asay color

* Convert pref: tooltips

* Convert pref: ui style

* Convert pref: buttons locked

* Convert pref: hotkeys

* Convert pref: tgui stuff

* Convert pref: windowflashing

* Convert pref: ghost stuff

* Convert pref: map & antag

* Convert pref: PDA stuff

* Convert pref: credits & glasses


1

* Convert pref: name

* Convert pref: appearances 1

* Convert pref: appearances 2

* Convert pref: jobless role

* Convert pref: runechat

* Convert pref: yogtoggles + tail wagging


1

* Convert pref: client fps

* Convert pref: graphic settings

* Convert pref: pda uplink & menuoptions

* Convert pref: map & flare

* Convert pref: Bar choice

* Fix setup character button

* Convert pref: alt announcer

* Fix

* Add cycle background button

* Convert pref: disable balloon alert

* fix

* Clean savefile

* Fix backpack pref

* Fix underwear selection

* Fixes some shit

* Updates

* Fix computer runtime

* Fix pref names

* Convert pref: donor item & hat

* More computer fixes

* Convert pref: borg hat

* Convert pref: donor pda (broken)

* Convert pref: purrbation

* Convert pref: afreeze

* Convert pref: accent

* Various savefile improvements

* Convert pref: persistent scars


1

* A few pref fixes

* Some more fixes

* Various SSoverlays improvements

* Add IPC appearances

* Add polysmorph appearances

* No icons for ipc and polysmorph

* Podpeople deserve death

* Add plasmaman appearance

* h

* fix

* fix2

* asdf

* fsdf

* aaaaa

* FUCK MOTHS

* Preternis color

* e

* e

* Update human.dmi

* icon fix

* un snowflake

* fix underwear icon

* remove color from here

* donor ree

* aa

* maybe

* Restore a bunch of TGUI files

* More TGUI fixes

* test

* Fix more errors

* a

* test

* e?

* a;lso this

* maybe

* Fix

* Revert "maybe"

This reverts commit 14d044a7e3.

* fuck off m8

* e

* fak off m8

* e2?

* AHHH

* AHA

* AHHH

* fix linter 2

* debug

* fix runtime

* Update dynamic.json

* Revert "debug"

This reverts commit 18681432bd.

* 2

* who sleeps in an async?

* Hack

* e

* Fix a few blocking calls

* Oh bother

* Stay dead

* fuck

* Update jobs.dm

* move debugging

* Update jobs.dm

* Test

* YEET

* Revert "YEET"

This reverts commit 4082e3b133.

* Update jobs.dm

* Update jobs.dm

* e

* Fix sechailer runtime

* Fix human hair color

* d

* Ports part of that job refactor

* Convert latejoin to new departments

* Fix ghost form

* Quirk validation

* Hopefully pod color fix

* oops

* Prayge job fix

* test

* Better unit test asset loading

* Remove print

* Add error just in case

* Remove brief outfit and bypass centcom deadmin

* Remove broadcast login/logout

* Remove darkened flash

* Remove fov darkness

* Remove ghost lighting

* Remove some tgui prefs

* Typo fix

* Small fixes

* IPC name fix

* IPC and pod colors

* Jobless fix

* Donor item fix

* Oopsie

* Quirk bandaid

* Misc

* Move new prefs to Preferences tab for now

* Add skillcape

* FUCK THIS SHIT

* Remove /tg/ gamer cloak

* Restrict some job related preferences to clean up UI

* Remove useless client var

* e

* Small tweaks

* Dont allow selecting mood quirks if mood is disabled

* AHHH

* Filter ckey-locked donor items

* stupid jamie

* AI core display fix

* Move donor stuff back to the top

* Remove TODOs

* Clean up perks

* Linter fixes

* e

* WORKS

* LORE

* Fix skillcape list

* Backpack why

* Fixes

* Fix cargo console

* Remove these

* Add horns, frills and mark

* Fix not applying all features

* Add some missing mutant bodyparts

* Update numberinput

* Makes animatednumber cooler

* Oops

* Add default ghost orbit

* Default to normal backpack

* Fixes skillcapes not being filtered

* Donor fix prayge

* yep

* Adds fallback latejoin menu

* Rework donor stuff a bit

* Fix donor tgui logic

* Delete unused proc

* Update FA

* Un-yogify quirks

* Better checking of quirks

* Update tgfont

* Fix quirk icons

* Fix backup name

* Fix donor stuff

* A few runtime fixes

* Fix another runtime

* Give fallback latejoin verb upon connecting

* Update AirAlarm interface

* maybe this works

* Test

* Sentient

* Remove AI core display preview icons

* Fix resetting plasmaman helmet style

* Equip plasman in preview

* Fix plasmaman preview icon

* fuck keybind fix

* Extra keybind sanity

---------

Co-authored-by: Yogbot-13 <admin@yogstation.net>
Co-authored-by: Jamie D <993128+JamieD1@users.noreply.github.com>
Co-authored-by: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com>
Co-authored-by: adamsong <adamsong@users.noreply.github.com>
2023-01-28 15:26:19 +00:00

346 lines
11 KiB
Plaintext

#define FILE_ANTAG_REP "data/AntagReputation.json"
SUBSYSTEM_DEF(persistence)
name = "Persistence"
init_order = INIT_ORDER_PERSISTENCE
flags = SS_NO_FIRE
var/list/obj/structure/chisel_message/chisel_messages = list()
var/list/saved_messages = list()
var/list/saved_modes = list(1,2,3)
var/list/saved_trophies = list()
var/list/antag_rep = list()
var/list/antag_rep_change = list()
var/list/picture_logging_information = list()
var/list/obj/structure/sign/picture_frame/photo_frames = list()
var/list/obj/item/storage/photo_album/photo_albums = list()
/datum/controller/subsystem/persistence/Initialize()
LoadPoly()
LoadChiselMessages()
LoadTrophies()
LoadRecentModes()
LoadPhotoPersistence()
if(CONFIG_GET(flag/use_antag_rep))
LoadAntagReputation()
LoadRandomizedRecipes()
return SS_INIT_SUCCESS
/datum/controller/subsystem/persistence/proc/LoadPoly()
for(var/mob/living/simple_animal/parrot/Poly/P in GLOB.alive_mob_list)
twitterize(P.speech_buffer, "polytalk")
break //Who's been duping the bird?!
/datum/controller/subsystem/persistence/proc/LoadChiselMessages()
var/list/saved_messages = list()
if(fexists("data/npc_saves/ChiselMessages.sav")) //legacy compatability to convert old format to new
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
var/saved_json
chisel_messages_sav[SSmapping.config.map_name] >> saved_json
if(!saved_json)
return
saved_messages = json_decode(saved_json)
fdel("data/npc_saves/ChiselMessages.sav")
else
var/json_file = file("data/npc_saves/ChiselMessages[SSmapping.config.map_name].json")
if(!fexists(json_file))
return
var/list/json = json_decode(file2text(json_file))
if(!json)
return
saved_messages = json["data"]
for(var/item in saved_messages)
if(!islist(item))
continue
var/xvar = item["x"]
var/yvar = item["y"]
var/zvar = item["z"]
if(!xvar || !yvar || !zvar)
continue
var/turf/T = locate(xvar, yvar, zvar)
if(!isturf(T))
continue
if(locate(/obj/structure/chisel_message) in T)
continue
var/obj/structure/chisel_message/M = new(T)
if(!QDELETED(M))
M.unpack(item)
log_world("Loaded [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
/datum/controller/subsystem/persistence/proc/LoadTrophies()
if(fexists("data/npc_saves/TrophyItems.sav")) //legacy compatability to convert old format to new
var/savefile/S = new /savefile("data/npc_saves/TrophyItems.sav")
var/saved_json
S >> saved_json
if(!saved_json)
return
saved_trophies = json_decode(saved_json)
fdel("data/npc_saves/TrophyItems.sav")
else
var/json_file = file("data/npc_saves/TrophyItems.json")
if(!fexists(json_file))
return
var/list/json = json_decode(file2text(json_file))
if(!json)
return
saved_trophies = json["data"]
SetUpTrophies(saved_trophies.Copy())
/datum/controller/subsystem/persistence/proc/LoadRecentModes()
var/json_file = file("data/RecentModes.json")
if(!fexists(json_file))
return
var/list/json = json_decode(file2text(json_file))
if(!json)
return
saved_modes = json["data"]
/datum/controller/subsystem/persistence/proc/LoadAntagReputation()
var/json = file2text(FILE_ANTAG_REP)
if(!json)
var/json_file = file(FILE_ANTAG_REP)
if(!fexists(json_file))
WARNING("Failed to load antag reputation. File likely corrupt.")
return
return
antag_rep = json_decode(json)
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
for(var/A in GLOB.trophy_cases)
var/obj/structure/displaycase/trophy/T = A
if (T.showpiece)
continue
T.added_roundstart = TRUE
var/trophy_data = pick_n_take(trophy_items)
if(!islist(trophy_data))
continue
var/list/chosen_trophy = trophy_data
if(!chosen_trophy || isemptylist(chosen_trophy)) //Malformed
continue
var/path = text2path(chosen_trophy["path"]) //If the item no longer exist, this returns null
if(!path)
continue
T.showpiece = new /obj/item/showpiece_dummy(T, path)
T.trophy_message = chosen_trophy["message"]
T.placer_key = chosen_trophy["placer_key"]
T.update_icon()
/datum/controller/subsystem/persistence/proc/CollectData()
CollectChiselMessages()
CollectTrophies()
CollectRoundtype()
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
if(CONFIG_GET(flag/use_antag_rep))
CollectAntagReputation()
SaveRandomizedRecipes()
SaveScars()
/datum/controller/subsystem/persistence/proc/GetPhotoAlbums()
var/album_path = file("data/photo_albums.json")
if(fexists(album_path))
return json_decode(file2text(album_path))
/datum/controller/subsystem/persistence/proc/GetPhotoFrames()
var/frame_path = file("data/photo_frames.json")
if(fexists(frame_path))
return json_decode(file2text(frame_path))
/datum/controller/subsystem/persistence/proc/LoadPhotoPersistence()
var/album_path = file("data/photo_albums.json")
var/frame_path = file("data/photo_frames.json")
if(fexists(album_path))
var/list/json = json_decode(file2text(album_path))
if(json.len)
for(var/i in photo_albums)
var/obj/item/storage/photo_album/A = i
if(!A.persistence_id)
continue
if(json[A.persistence_id])
A.populate_from_id_list(json[A.persistence_id])
if(fexists(frame_path))
var/list/json = json_decode(file2text(frame_path))
if(json.len)
for(var/i in photo_frames)
var/obj/structure/sign/picture_frame/PF = i
if(!PF.persistence_id)
continue
if(json[PF.persistence_id])
PF.load_from_id(json[PF.persistence_id])
/datum/controller/subsystem/persistence/proc/SavePhotoPersistence()
var/album_path = file("data/photo_albums.json")
var/frame_path = file("data/photo_frames.json")
var/list/frame_json = list()
var/list/album_json = list()
if(fexists(album_path))
album_json = json_decode(file2text(album_path))
fdel(album_path)
for(var/i in photo_albums)
var/obj/item/storage/photo_album/A = i
if(!istype(A) || !A.persistence_id)
continue
var/list/L = A.get_picture_id_list()
album_json[A.persistence_id] = L
album_json = json_encode(album_json)
WRITE_FILE(album_path, album_json)
if(fexists(frame_path))
frame_json = json_decode(file2text(frame_path))
fdel(frame_path)
for(var/i in photo_frames)
var/obj/structure/sign/picture_frame/F = i
if(!istype(F) || !F.persistence_id)
continue
frame_json[F.persistence_id] = F.get_photo_id()
frame_json = json_encode(frame_json)
WRITE_FILE(frame_path, frame_json)
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
var/json_file = file("data/npc_saves/ChiselMessages[SSmapping.config.map_name].json")
for(var/obj/structure/chisel_message/M in chisel_messages)
saved_messages += list(M.pack())
log_world("Saved [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
var/list/file_data = list()
file_data["data"] = saved_messages
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
saved_messages += list(M.pack()) // dm eats one list
/datum/controller/subsystem/persistence/proc/CollectTrophies()
var/json_file = file("data/npc_saves/TrophyItems.json")
var/list/file_data = list()
file_data["data"] = remove_duplicate_trophies(saved_trophies)
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/remove_duplicate_trophies(list/trophies)
var/list/ukeys = list()
. = list()
for(var/trophy in trophies)
var/tkey = "[trophy["path"]]-[trophy["message"]]"
if(ukeys[tkey])
continue
else
. += list(trophy)
ukeys[tkey] = TRUE
/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
if(!T.added_roundstart && T.showpiece)
var/list/data = list()
data["path"] = T.showpiece.type
data["message"] = T.trophy_message
data["placer_key"] = T.placer_key
saved_trophies += list(data)
/datum/controller/subsystem/persistence/proc/CollectRoundtype()
saved_modes[3] = saved_modes[2]
saved_modes[2] = saved_modes[1]
saved_modes[1] = SSticker.mode.config_tag
var/json_file = file("data/RecentModes.json")
var/list/file_data = list()
file_data["data"] = saved_modes
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/CollectAntagReputation()
var/ANTAG_REP_MAXIMUM = CONFIG_GET(number/antag_rep_maximum)
for(var/p_ckey in antag_rep_change)
// var/start = antag_rep[p_ckey]
antag_rep[p_ckey] = max(0, min(antag_rep[p_ckey]+antag_rep_change[p_ckey], ANTAG_REP_MAXIMUM))
// WARNING("AR_DEBUG: [p_ckey]: Committed [antag_rep_change[p_ckey]] reputation, going from [start] to [antag_rep[p_ckey]]")
antag_rep_change = list()
fdel(FILE_ANTAG_REP)
text2file(json_encode(antag_rep), FILE_ANTAG_REP)
/datum/controller/subsystem/persistence/proc/LoadRandomizedRecipes()
var/json_file = file("data/RandomizedChemRecipes.json")
var/json
if(fexists(json_file))
json = json_decode(file2text(json_file))
for(var/randomized_type in subtypesof(/datum/chemical_reaction/randomized))
var/datum/chemical_reaction/randomized/R = new randomized_type
var/loaded = FALSE
if(R.persistent && json)
var/list/recipe_data = json[R.id]
if(recipe_data)
if(R.LoadOldRecipe(recipe_data) && (daysSince(R.created) <= R.persistence_period))
loaded = TRUE
if(!loaded) //We do not have information for whatever reason, just generate new one
R.GenerateRecipe()
if(!R.HasConflicts()) //Might want to try again if conflicts happened in the future.
add_chemical_reaction(R)
/datum/controller/subsystem/persistence/proc/SaveRandomizedRecipes()
var/json_file = file("data/RandomizedChemRecipes.json")
var/list/file_data = list()
//asert globchems done
for(var/randomized_type in subtypesof(/datum/chemical_reaction/randomized))
var/datum/chemical_reaction/randomized/R = randomized_type
R = get_chemical_reaction(initial(R.id)) //ew, would be nice to add some simple tracking
if(R && R.persistent && R.id)
var/recipe_data = list()
recipe_data["timestamp"] = R.created
recipe_data["required_reagents"] = R.required_reagents
recipe_data["required_catalysts"] = R.required_catalysts
recipe_data["required_temp"] = R.required_temp
recipe_data["is_cold_recipe"] = R.is_cold_recipe
recipe_data["results"] = R.results
recipe_data["required_container"] = "[R.required_container]"
file_data["[R.id]"] = recipe_data
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/SaveScars()
for(var/i in GLOB.joined_player_list)
var/mob/living/carbon/human/ending_human = get_mob_by_ckey(i)
if(!istype(ending_human) || !ending_human.mind?.original_character_slot_index || !ending_human.client || !ending_human.client.prefs || !ending_human.client.prefs.read_preference(/datum/preference/toggle/persistent_scars))
continue
var/mob/living/carbon/human/original_human = ending_human.mind.original_character
if(!original_human)
continue
if(original_human.stat == DEAD || !original_human.all_scars || original_human != ending_human)
original_human.save_persistent_scars(TRUE)
else
original_human.save_persistent_scars()