var/list/preferences_datums = list() /datum/preferences /// The path to the general savefile for this datum var/path /// Whether or not we allow saving/loading. Used for guests, if they're enabled var/load_and_save = TRUE /// Ensures that we always load the last used save, QOL var/default_slot = 1 //non-preference stuff var/warns = 0 var/muted = 0 var/last_ip var/last_id //game-preferences var/lastchangelog = "" //Saved changlog filesize to detect if there was a change var/ooccolor = "#010000" //Whatever this is set to acts as 'reset' color and is thus unusable as an actual custom color var/be_special = 0 //Special role selection var/UI_style = "Midnight" var/UI_style_color = "#ffffff" var/UI_style_alpha = 255 var/tooltipstyle = "Midnight" //Style for popup tooltips var/client_fps = 40 var/ambience_freq = 5 // How often we're playing repeating ambience to a client. var/ambience_chance = 35 // What's the % chance we'll play ambience (in conjunction with the above frequency) var/tgui_fancy = TRUE var/tgui_lock = FALSE var/tgui_input_mode = FALSE // All the Input Boxes (Text,Number,List,Alert) var/tgui_large_buttons = TRUE var/tgui_swapped_buttons = FALSE var/obfuscate_key = FALSE var/obfuscate_job = FALSE var/chat_timestamp = FALSE //character preferences var/real_name //our character's name var/be_random_name = 0 //whether we are a random name every round var/nickname //our character's nickname var/age = 30 //age of character var/bday_month = 0 //Birthday month var/bday_day = 0 //Birthday day var/last_birthday_notification = 0 //The last year we were notified about our birthday var/bday_announce = FALSE //Public announcement for birthdays var/spawnpoint = "Arrivals Shuttle" //where this character will spawn (0-2). var/b_type = "A+" //blood type (not-chooseable) var/blood_reagents = "default" //blood restoration reagents var/headset = 1 //headset type var/backbag = 2 //backpack type var/pdachoice = 1 //PDA type //var/shoe_hater = FALSE //RS ADD - if true, will spawn with no shoes //CHOMPRemove, remove RS No shoes var/h_style = "Bald" //Hair type var/r_hair = 0 //Hair color var/g_hair = 0 //Hair color var/b_hair = 0 //Hair color var/grad_style = "none" //Gradient style var/r_grad = 0 //Gradient color var/g_grad = 0 //Gradient color var/b_grad = 0 //Gradient color var/f_style = "Shaved" //Face hair type var/r_facial = 0 //Face hair color var/g_facial = 0 //Face hair color var/b_facial = 0 //Face hair color var/s_tone = -75 //Skin tone var/r_skin = 238 //Skin color // Vorestation edit, so color multi sprites can aren't BLACK AS THE VOID by default. var/g_skin = 206 //Skin color // Vorestation edit, so color multi sprites can aren't BLACK AS THE VOID by default. var/b_skin = 179 //Skin color // Vorestation edit, so color multi sprites can aren't BLACK AS THE VOID by default. var/r_eyes = 0 //Eye color var/g_eyes = 0 //Eye color var/b_eyes = 0 //Eye color var/species = SPECIES_HUMAN //Species datum to use. var/species_preview //Used for the species selection window. var/list/alternate_languages = list() //Secondary language(s) var/list/language_prefixes = list() //Language prefix keys var/list/language_custom_keys = list() //Language custom call keys var/list/gear //Left in for Legacy reasons, will no longer save. var/list/gear_list = list() //Custom/fluff item loadouts. var/gear_slot = 1 //The current gear save slot var/list/traits //Traits which modifier characters for better or worse (mostly worse). var/synth_color = 0 //Lets normally uncolorable synth parts be colorable. var/r_synth //Used with synth_color to color synth parts that normaly can't be colored. var/g_synth //Same as above var/b_synth //Same as above var/synth_markings = 1 //Enable/disable markings on synth parts. //VOREStation Edit - 1 by default var/digitigrade = 0 //Some faction information. var/home_system = "Unset" //Current home or residence. var/birthplace = "Unset" //Location of birth. var/citizenship = "None" //Government or similar entity with which you hold citizenship. var/faction = "None" //General associated faction. var/religion = "None" //Religious association. var/antag_faction = "None" //Antag associated faction. var/antag_vis = "Hidden" //How visible antag association is to others. //Mob preview var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen. var/static/list/preview_screen_locs = list( "1" = "character_preview_map:2,7", "2" = "character_preview_map:2,5", "4" = "character_preview_map:2,3", "8" = "character_preview_map:2,1", "BG" = "character_preview_map:1,1 to 3,8", "PMH" = "character_preview_map:2,7" ) //Jobs, uses bitflags var/job_civilian_high = 0 var/job_civilian_med = 0 var/job_civilian_low = 0 var/job_medsci_high = 0 var/job_medsci_med = 0 var/job_medsci_low = 0 var/job_engsec_high = 0 var/job_engsec_med = 0 var/job_engsec_low = 0 //Keeps track of preferrence for not getting any wanted jobs var/alternate_option = 1 // maps each organ to either null(intact), "cyborg" or "amputated" // will probably not be able to do this for head and torso ;) var/list/organ_data = list() var/list/rlimb_data = list() var/list/player_alt_titles = new() // the default name of a job like JOB_MEDICAL_DOCTOR var/list/body_markings = list() // "name" = "#rgbcolor" //VOREStation Edit: "name" = list(BP_HEAD = list("on" = , "color" = "#rgbcolor"), BP_TORSO = ...) var/list/flavor_texts = list() var/list/flavour_texts_robot = list() var/custom_link = null var/list/body_descriptors = list() var/med_record = "" var/sec_record = "" var/gen_record = "" var/exploit_record = "" var/disabilities = 0 var/economic_status = "Average" var/uplinklocation = "PDA" // OOC Metadata: var/metadata = "" var/metadata_likes = "" var/metadata_dislikes = "" var/list/ignored_players = list() var/client/client = null var/client_ckey = null // Communicator identity data var/communicator_visibility = 0 /// Default ringtone for character; if blank, use job default. var/ringtone = null var/datum/category_collection/player_setup_collection/player_setup var/datum/browser/panel var/lastnews // Hash of last seen lobby news content. var/lastlorenews //ID of last seen lore news article. var/examine_text_mode = 0 // Just examine text, include usage (description_info), switch to examine panel. var/multilingual_mode = 0 // Default behaviour, delimiter-key-space, delimiter-key-delimiter, off // THIS IS NOT SAVED // WE JUST HAVE NOWHERE ELSE TO STORE IT var/list/action_button_screen_locs var/list/volume_channels = list() ///If they are currently in the process of swapping slots, don't let them open 999 windows for it and get confused var/selecting_slots = FALSE /// The json savefile for this datum var/datum/json_savefile/savefile /datum/preferences/New(client/C) client = C for(var/middleware_type in subtypesof(/datum/preference_middleware)) middleware += new middleware_type(src) if(istype(C)) // IS_CLIENT_OR_MOCK client_ckey = C.ckey load_and_save = !IsGuestKey(C.key) load_path(C.ckey) if(load_and_save && !fexists(path)) try_savefile_type_migration() else CRASH("attempted to create a preferences datum without a client or mock!") load_savefile() // Legacy code gear = list() gear_list = list() gear_slot = 1 // End legacy code player_setup = new(src) var/loaded_preferences_successfully = load_preferences() if(loaded_preferences_successfully) if(load_character()) return // Didn't load a character, so let's randomize set_biological_gender(pick(MALE, FEMALE)) real_name = random_name(identifying_gender,species) b_type = RANDOM_BLOOD_TYPE if(client) apply_all_client_preferences() if(!loaded_preferences_successfully) save_preferences() save_character() // Save random character /datum/preferences/Destroy() QDEL_LIST_ASSOC_VAL(char_render_holders) QDEL_NULL(middleware) value_cache = null return ..() /datum/preferences/proc/ShowChoices(mob/user) if(!user || !user.client) return if(!get_mob_by_key(client_ckey)) to_chat(user, span_danger("No mob exists for the given client!")) return if(!char_render_holders) update_preview_icon() show_character_previews() var/dat = "
" if(path) dat += "Slot - " dat += "Load slot - " dat += "Save slot - " dat += "Reload slot - " dat += "Reset slot - " dat += "Copy slot" else dat += "Please create an account to save your preferences." dat += "
" dat += player_setup.header() dat += "

" dat += player_setup.content(user) dat += "" //user << browse(dat, "window=preferences;size=635x736") winshow(user, "preferences_window", TRUE) var/datum/browser/popup = new(user, "preferences_browser", "Character Setup", 800, 800) popup.set_content(dat) popup.open(FALSE) // Skip registring onclose on the browser pane onclose(user, "preferences_window", src) // We want to register on the window itself /datum/preferences/proc/update_character_previews(var/mob/living/carbon/human/mannequin) if(!client) return var/obj/screen/setup_preview/pm_helper/PMH = LAZYACCESS(char_render_holders, "PMH") if(!PMH) PMH = new LAZYSET(char_render_holders, "PMH", PMH) client.screen |= PMH PMH.screen_loc = preview_screen_locs["PMH"] var/obj/screen/setup_preview/bg/BG = LAZYACCESS(char_render_holders, "BG") if(!BG) BG = new BG.plane = TURF_PLANE BG.icon = 'icons/effects/setup_backgrounds_vr.dmi' BG.pref = src LAZYSET(char_render_holders, "BG", BG) client.screen |= BG BG.icon_state = bgstate BG.screen_loc = preview_screen_locs["BG"] for(var/D in global.cardinal) var/obj/screen/setup_preview/O = LAZYACCESS(char_render_holders, "[D]") if(!O) O = new O.pref = src LAZYSET(char_render_holders, "[D]", O) client.screen |= O mannequin.set_dir(D) mannequin.update_tail_showing() mannequin.ImmediateOverlayUpdate() var/mutable_appearance/MA = new(mannequin) O.appearance = MA O.screen_loc = preview_screen_locs["[D]"] /datum/preferences/proc/show_character_previews() if(!client || !char_render_holders) return for(var/render_holder in char_render_holders) client.screen |= char_render_holders[render_holder] /datum/preferences/proc/clear_character_previews() for(var/index in char_render_holders) var/obj/screen/S = char_render_holders[index] client?.screen -= S qdel(S) char_render_holders = null /datum/preferences/proc/process_link(mob/user, list/href_list) if(!user) return if(!istype(user, /mob/new_player)) return if(href_list["preference"] == "open_whitelist_forum") if(CONFIG_GET(string/forumurl)) user << link(CONFIG_GET(string/forumurl)) else to_chat(user, span_danger("The forum URL is not set in the server configuration.")) return ShowChoices(user) //ChompEDIT - usr removal return 1 /datum/preferences/Topic(href, list/href_list) if(..()) return 1 if(href_list["save"]) save_character() save_preferences() else if(href_list["reload"]) load_preferences() load_character() attempt_vr(client.prefs_vr,"load_vore","") //VOREStation Edit sanitize_preferences() else if(href_list["load"]) if(!IsGuestKey(usr.key)) open_load_dialog(usr) return 1 else if(href_list["resetslot"]) if("Yes" != tgui_alert(usr, "This will reset the current slot. Continue?", "Reset current slot?", list("No", "Yes"))) return 0 if("Yes" != tgui_alert(usr, "Are you completely sure that you want to reset this character slot?", "Reset current slot?", list("No", "Yes"))) return 0 reset_slot() sanitize_preferences() else if(href_list["copy"]) if(!IsGuestKey(usr.key)) open_copy_dialog(usr) return 1 else if(href_list["close"]) // User closed preferences window, cleanup anything we need to. clear_character_previews() return 1 else return 0 ShowChoices(usr) return 1 /datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = TRUE) // Sanitizing rather than saving as someone might still be editing when copy_to occurs. player_setup.sanitize_setup() // This needs to happen before anything else becuase it sets some variables. character.set_species(species) // Special Case: This references variables owned by two different datums, so do it here. if(be_random_name) real_name = random_name(identifying_gender,species) // Ask the preferences datums to apply their own settings to the new mob player_setup.copy_to_mob(character) for(var/datum/preference/preference as anything in get_preferences_in_priority_order()) if(preference.savefile_identifier != PREFERENCE_CHARACTER) continue preference.apply_to_human(character, read_preference(preference.type)) // VOREStation Edit - Sync up all their organs and species one final time character.force_update_organs() if(icon_updates) character.force_update_limbs() character.update_icons_body() character.update_mutations() character.update_underwear() character.update_hair() if(LAZYLEN(character.descriptors)) for(var/entry in body_descriptors) character.descriptors[entry] = body_descriptors[entry] /datum/preferences/proc/open_load_dialog(mob/user) if(selecting_slots) to_chat(user, span_warning("You already have a slot selection dialog open!")) return if(!savefile) return var/default var/list/charlist = list() for(var/i in 1 to CONFIG_GET(number/character_slots)) var/list/save_data = savefile.get_entry("character[i]", list()) var/name = save_data["real_name"] var/nickname = save_data["nickname"] if(!name) name = "[i] - \[Unused Slot\]" else if(i == default_slot) name = "►[i] - [name]" else name = "[i] - [name]" if(i == default_slot) default = "[name][nickname ? " ([nickname])" : ""]" charlist["[name][nickname ? " ([nickname])" : ""]"] = i selecting_slots = TRUE var/choice = tgui_input_list(user, "Select a character to load:", "Load Slot", charlist, default) selecting_slots = FALSE if(!choice) return var/slotnum = charlist[choice] if(!slotnum) error("Player picked [choice] slot to load, but that wasn't one we sent.") return load_preferences() load_character(slotnum) attempt_vr(user.client?.prefs_vr,"load_vore","") //VOREStation Edit sanitize_preferences() save_preferences() ShowChoices(user) /datum/preferences/proc/open_copy_dialog(mob/user) if(selecting_slots) to_chat(user, span_warning("You already have a slot selection dialog open!")) return if(!savefile) return var/list/charlist = list() for(var/i in 1 to CONFIG_GET(number/character_slots)) var/list/save_data = savefile.get_entry("character[i]", list()) var/name = save_data["real_name"] var/nickname = save_data["nickname"] if(!name) name = "[i] - \[Unused Slot\]" else if(i == default_slot) name = "►[i] - [name]" else name = "[i] - [name]" charlist["[name][nickname ? " ([nickname])" : ""]"] = i selecting_slots = TRUE var/choice = tgui_input_list(user, "Select a character to COPY TO:", "Copy Slot", charlist) selecting_slots = FALSE if(!choice) return var/slotnum = charlist[choice] if(!slotnum) error("Player picked [choice] slot to copy to, but that wasn't one we sent.") return if(tgui_alert(user, "Are you sure you want to override slot [slotnum], [choice]'s savedata?", "Confirm Override", list("No", "Yes")) == "Yes") overwrite_character(slotnum) sanitize_preferences() save_character() save_preferences() attempt_vr(user.client?.prefs_vr,"load_vore","") ShowChoices(user)