Files
CHOMPStation2/code/modules/client/preferences.dm
2024-11-29 00:10:57 +01:00

485 lines
16 KiB
Plaintext

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" = <enabled>, "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 = "<html><body><center>"
if(path)
dat += "Slot - "
dat += "<a href='?src=\ref[src];load=1'>Load slot</a> - "
dat += "<a href='?src=\ref[src];save=1'>Save slot</a> - "
dat += "<a href='?src=\ref[src];reload=1'>Reload slot</a> - "
dat += "<a href='?src=\ref[src];resetslot=1'>Reset slot</a> - "
dat += "<a href='?src=\ref[src];copy=1'>Copy slot</a>"
else
dat += "Please create an account to save your preferences."
dat += "<br>"
dat += player_setup.header()
dat += "<br><HR></center>"
dat += player_setup.content(user)
dat += "</html></body>"
//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)